Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Christian Ehrlicher, SLSE, 2016-03-01
#
ADD_SUBDIRECTORY(Data)
ADD_SUBDIRECTORY(Gui)
#
# Data Plugin Interface
#
ADD_INTERFACE_LIBRARY(TgtDataPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/tgt_data_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
DataPluginInterface
svcTgtCommon
)
+19
View File
@@ -0,0 +1,19 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-09-06
#
#
# Data Plugin
#
NGL_ADD_LIBRARY(WS TgtDataPlugin MODULE tgt_data_plugin.cpp tgt_data_plugin.h)
NGL_TARGET_LINK_LIBRARIES(TgtDataPlugin
Qt5::Core
TgtDataPluginInterface
svcTgtClient
NGLLogger
LtsSessionDataDds
)
NGL_INSTALL_TARGET(TgtDataPlugin)
+34
View File
@@ -0,0 +1,34 @@
/**
* @RDE_HEADER@
* Data Plugin for TargetManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#include "tgt_data_plugin.h"
#include <DDS/DDSConnector/dds_connector.h>
#include <LtsSession/lts_session_data_dds.h>
namespace TargetManagement
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
std::shared_ptr<TargetManagement::Interface::Dtc> dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> ftc;
if (!session->createTopicClient(dtc, ftc))
return std::shared_ptr<DataPluginBase::Interface>();
return std::make_shared<DataInterfaceImpl>(dtc, ftc);
}
DataInterfaceImpl::DataInterfaceImpl(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc)
: DataInterface()
, m_dtc(dtc)
, m_ftc(ftc)
{}
} // namespace TargetManagement
+54
View File
@@ -0,0 +1,54 @@
/**
* @RDE_HEADER@
* Data Plugin for TargetManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
namespace TargetManagement
{
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:tgt")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin() = default;
~DataPlugin() = default;
QString pluginName() const override { return QStringLiteral("TargetManagement"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Replay ||
partition == IDL::PartitionType::Global;
}
};
class DataInterfaceImpl final : public DataInterface
{
public:
DataInterfaceImpl(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc);
std::shared_ptr<TargetManagement::Interface::Dtc> getDtc() override { return m_dtc; }
std::shared_ptr<TargetManagement::Interface::Ftc> getFtc() override { return m_ftc; }
private:
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
};
} // namespace TargetManagement
+8
View File
@@ -0,0 +1,8 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Norbert Thoden, NLE, 2020-05-28
#
ADD_SUBDIRECTORY(ShootbackTargetConfiguration)
@@ -0,0 +1,79 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Norbert Thoden, NLE, 2020-05-28
#
SET(tgt_gui_SRCS
# common
tgt_target_gui_plugin.cpp
tgt_target_gui_plugin.h
tgt_telegrams.cpp
tgt_telegrams.h
tgt_common.cpp
tgt_common.h
# target
tgt_participant_handler.cpp
tgt_participant_handler.h
tgt_target_part_model.cpp
tgt_target_part_model.h
tgt_target_part_dialog.cpp
tgt_target_part_dialog.h
tgt_shootback_target_edit.cpp
tgt_shootback_target_edit.h
# assignment
tgt_assignment_part_model.cpp
tgt_assignment_part_model.h
tgt_target_area_assignment_dialog.cpp
tgt_target_area_assignment_dialog.h
tgt_target_area_assignment_edit.cpp
tgt_target_area_assignment_edit.h
# area
tgt_area_dialog.cpp
tgt_area_dialog.h
tgt_area_edit.cpp
tgt_area_edit.h
tgt_area_model.cpp
tgt_area_model.h
)
NGL_WRAP_UI(tgt_gui_SRCS
tgt_shootback_target_edit.ui
tgt_target_part_dialog.ui
tgt_target_area_assignment_dialog.ui
tgt_target_area_assignment_edit.ui
tgt_area_dialog.ui
tgt_area_edit.ui
)
NGL_ADD_LIBRARY(WS TgtTargetGuiPlugin MODULE ${tgt_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(TgtTargetGuiPlugin
NGLLogger
LtsPrinting
LtsSession
svcTgtClient
Qt5::Widgets
LtsCoordTrans
ltsCoordWidget
LtsWidgets
LtsDataView
LtsSessionData
LtsUtilsCore
LtsUtilsGuiDds
LtsUtilsSettings
advancedSymbology
FlmDataPluginInterface #flm_translation
PpmGuiComboboxPluginInterface
svcExmCommon
svcPpmCommon
)
NGL_INSTALL_TARGET(TgtTargetGuiPlugin)
@@ -0,0 +1,155 @@
#
# Hinweise fuer ShootbackTargets (Projekt L400)
#
# $Id$
# $HeadURL$
# $Author$
#
N. Thoden, 16.07.2020
Facts
============================================================
- Die Shootbacktargets im Projekt L400 besitzen kaum eigene Intelligenz.
- Einige der Shootbacktargets können sich bewegen.
- Sie haben unterschiedliche Silouetten.
-
Statik
============================================================
Im namespace TargetManagement existieren 3 wesentliche Objekte/Topics:
1) ShootbackTarget
Es wird "assigned" mit einem Participant aus den ORBAT (Teilnehmerbaum). Diese muss ein WmsTypeClass (TargetVehicle|TargetHuman) haben.
Beim Zuordnen zu eine Teilnehmer (aus dem ORBAT) kann/muss eine TargetConfiguration vorgenommen werden: activateLaserDesignation etc.
2) ShootbackArea
Die Area wird per center, width, height definiert. Ist also nordausgerichtet.
3) TargetAreaAssignment (inkl. (Shootback)-Configuration)
Das Assignment zw. 1) und 2) beinhaltet zusätzlich die (Shootback)-Configuration, die das Verhalten definiert: PreWarning-interval, hitsToKill etc.
Diese (Shootback)-Configuration kann per CheckBox "assigned" aktiviert oder deaktiviert werden (DDS: TargetAreaAssignment.isActive())
!!! Somit hat nicht ein Target nicht genau EINE (Shootback)-Configuration, sondern jedes einzelnes Assignment !!!
Ablauf / Best Practise
============================================================
PreCondition:
Zunächst sollte sichergestellt sein, dass der ORBAT einige Targets enthält. Ggf. sollten entsprechende Typen/template eingefügt werden.
Step 1: TargetConfiguration
Im Dialog "Assign/Configure Targets" kann man die grundsätzliche TargetConfiguration pro Teilnehmer erstellen (activateLaserDesignation etc.)
Anmerkung:
- Es muss nicht für jeden im ORBAT als "Target" konfigurierten Particpant eine TargetConfiguration erstellt werden.
- Es muss aber für jedes "Target" im ORBAT eine TargetConfiguration erstellt werden, wenn es einer Area zugeordnet werden soll.
Step 2: ShootbackArea
Im Dialog "Configure Areas" können die Areas erstellt werden.
Step 3: Zuordnungen vornehmen
Hierfür gibt es 3 mögliche Wege:
Step 3a)
Shootback Overview
Dieser Dialog zeigt in Tabellenform alle aktiven Zuordnungen. Zunächst sind keine vorhanden.
Per Add kann zum einen eine Zuordnung zw. einem Target und einer Area erstellt und andererseits die (Shootback)-Configuration vorgenommen werden.
Step 3b)
Assign Area
Im Target-ÜbersichtsDialog kann ein Target selektiert und dann per Btn "Assign Area" ein weiterführender Dialog geöfnet werden "Edit Areas assigned to <Targetname>"
Dieser Zuordnungs-Dialog zeigt in Tabellenform nur die für dieses Target relevanten Zuordnungen.
Es werden die bestehenden mit "Assigned" = "Yes" dargestellt.
Darüberhinaus sind die noch möglichen Areas mit "Assigned" = "No" aufgeführt. Mit Klick auf "No" wird es assigned.
Wenn die (Shootback)-Configuration aber ungültig (derzeit == default) ist, wird die Zeile rot hinterlegt und ein "Apply" ist nicht möglich.
Per "Edit" kann die (Shootback)-Configuration vorgenommen werden.
Step 3c)
Assign Target
Hier verhält es sich analog zu Step 3b):
Im Area-ÜbersichtsDialog kann ein Area selektiert und dann per Btn "Assign Target" ein weiterführender Dialog geöfnet werden "Edit targets assigned to <Areaname>"
Dieser Zuordnungs-Dialog zeigt in Tabellenform nur die für dieses Area relevanten Zuordnungen.
Es werden die bestehenden mit "Assigned" = "Yes" dargestellt.
Darüberhinaus sind die noch möglichen Targets mit "Assigned" = "No" aufgeführt. Mit Klick auf "No" wird es assigned.
Wenn die (Shootback)-Configuration aber ungültig (derzeit == default) ist, wird die Zeile rot hinterlegt und ein "Apply" ist nicht möglich.
Per "Edit" kann die (Shootback)-Configuration vorgenommen werden.
Anmerkungen:
- Für alle Step 3 Varianten gilt: Der ÜbersichtsDialog muss mit "Apply" abgeschlossen werden, um die Daten wirksam zu übernehmen.
- Sowohl eine fehlende TargetConfiguration als auch eine fehlende (Shootback)-Configuration wird in den Tabellen farblich dargestellt.
Convenience
============================================================
- Tooltips in Tabellen, ComboBoxen
- Selektiert man eine Area, Target oder Assignment, so wird in der Karten das zugehörige Objekt per Pfeil markiert (MapObjectIndicator) und selektiert dargestellt.
Die dem Area oder Target zugeordneten Objekte werden ebenfalls selektiert dargestellt.
- Per "Center Map" wird die Karten auf das selektiert Objekt zentriert.
Dies kann auch mit der gedrückten Shift-Taste bei selektieren in der Tabelle erreicht werden.
- Per "Zoom to " zoomt die die Karten auf das selektiert Objekt und dessen zugeordneten Objekte.
- Einige Dialog haben die Möglichkeit, die Daten in die Library zu exportieren, bzw. von diort zu importieren.
Beim Importieren werden die aktuellen Daten überschrieben (Warn-Meldung ist vorhanden)
Um Irritationen zu vermeiden, empfiehlt es sich, erst die Targets und Areas zu importieren und erst danach die Zuordnungen zu importieren.
Todo:
============================================================
- EA:
- Umbenennung des Topics TargetAreaConfiguration in ShootbackConfiguration (Done)
- ForeignKeys entfernen (Done)
- Die dynamischen Daten "Position" und visibleParticpants evtl. in seperates Topic auslagern.
(Derzeit im Target)
-SVC:
- ModulTests anpassen
--->
--->
- Es ist derzeit die Höhenkarten für Bremen hart programmiert.
Es muss dafür gesort werden (Ablauf) wie TrainingAreas mit den Basemaps UND
ElevationMaps augf den System (INKL. Server kommen), damit auch die Services
diese Dateien nutzen können.
Derzeit ist dort viel getrickst.... :-(
<-----
<-----
- GUI
- Yes/No Icons durchgängig machen (Done)
- Filter der LtsDataViews vervollständigen (Done, mit Bug)
- "Name" -> "Designation"
- Spalten sortieren, umbenennen
- Silouetten einbinden
- "ZoomTo" SVG erstellen (ButtonBox) (Done)
- Evtl. "Experten"-Modus beim Dlg "Targets per Area"???
- I18N
- SOURCEN
- Konsistenten Datei- und Klassen-Bezeichnungen herstellen. Ist derzeit kaum wartbar.
- LogMessages auf passenden Level stellen (Done)
- Links zur OnlineHilfe setzen/korrigieren (setOnlineHelpFilename)
- seperate APP erzeugen: "ShootbackApp"
Ideen
============================================================
- Beim Dlg "Assign/Configure Targets" einen Defaultwert eintragen/anzeigen: Takt. Bezeichner des Participants.
Btn. "Use Tact. Identifier als Designation" kopiert den Wert in das LineEdit...
Known Problems/Bugs:
============================================================
- Einige Filter der LtsDataViews (Dlg "Targets per Area" und "Areas per Target" enthalten Values, die nicht gefiltert werden können.
Problem in AssignmentParticipantModel::updateColumnFilter()
- Wenn das Target nicht modifiziert werden darf, ist die ComboBox disabled. Leider ist dann auch das Icon dunkel...
(Label mit Icon statt ComboBox)
@@ -0,0 +1,118 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party Overview Model
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_shootback_target_model.h"
#include <LtsCoordTrans/lts_coord_trans.h>
namespace TargetMa nagement
{
//---------------------------------
// ShootbackTargetModel
//---------------------------------
ShootbackTargetModel::ShootbackTargetModel(QObject *parent)
: BaseClass({tr("Id"),
tr("TargetId"),
tr("Name"),
tr("TargetParticipantId"),
tr("Position"),
tr("ActivateLaserDesignation"),
tr("ActivateLights"),
tr("ActivatePopupAutomatic"),
tr("HitsToKill"),
tr("PermanentInstalledTarget"),
tr("VisibleParticipants"),
tr("Is Used")},
parent)
, m_dtc(nullptr)
, m_logger(getLogger("ShootbackTargetModel"))
{}
bool ShootbackTargetModel::initModel(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc)
{
if (!dtc)
return false;
m_dtc = dtc;
connect(m_dtc.get(), &TargetManagement::Interface::Dtc::shootbackTargetChanged,
this, &ShootbackTargetModel::onDataChanged);
connect(m_dtc.get(), &TargetManagement::Interface::Dtc::shootbackTargetChanged, [](const TargetManagement::ShootbackTarget &data, DataModification modType) {
ShootbackTargetModel::onDataChanged(data, modType);
});
m_dtc->shootbackTargets([this](const TargetManagement::ShootbackTarget & shootbackTarget)
{
insertRow(shootbackTarget);
});
return true;
}
QString toStringLocal(const std::vector< int32_t > &ids)
{
QString ret;
for (auto id : ids)
ret.append(QString::number(id));
return ret;
}
QVariant ShootbackTargetModel::data(const QModelIndex &index, int role) const
{
if (!indexIsValid(index))
return QVariant();
const TargetManagement::ShootbackTarget &shootbackTarget = m_vecData.at(index.row());
// if (role == Qt::BackgroundRole)
// {
// switch(index.column())
// {
// case Color:
// return QColor::fromRgb(QRgb(shootbackTarget.color()));
// case FadedColor:
// return QColor::fromRgb(QRgb(shootbackTarget.fadingColor()));
// }
// }
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case Id:
return shootbackTarget.id();
case TargetDataId:
return shootbackTarget.targetDataId();
case Name:
return QString::fromStdString(shootbackTarget.name());
case TargetParticipantId:
return shootbackTarget.targetParticipantId();
case Position:
{
const Core::GeoPosition2D &pos = shootbackTarget.position();
return LtsCoordTrans::mgrsFromGeographic(pos.lon(), pos.lat());
}
case ActivateLaserDesignation:
return shootbackTarget.activateLaserDesignation() ? tr("Yes") : tr("No");
case ActivateLights:
return shootbackTarget.activateLights() ? tr("Yes") : tr("No");
case ActivatePopupAutomatic:
return shootbackTarget.activatePopupAutomatic() ? tr("Yes") : tr("No");
case HitsToKill:
return shootbackTarget.hitsToKill();
case PermanentInstalledTarget:
return shootbackTarget.permanentInstalledTarget() ? tr("Yes") : tr("No");
case VisibleParticipants:
return TargetManagement::toStringLocal(shootbackTarget.visibleParticipants());
case IsUsedBy:
return shootbackTarget.isUsed() ? tr("Yes") : tr("No");
}
}
return QVariant();
}
} // namespace TargetManagement
@@ -0,0 +1,61 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party Overview Model
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include <Services/TargetManagement/tgt_dtc.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <TargetManagement/logger.h>
namespace TargetManagement
{
// --------------------------------------------------------
// ShootbackTargetModel
// --------------------------------------------------------
class ShootbackTargetModel final : public LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackTarget>
{
using BaseClass = LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackTarget>;
Q_OBJECT
public:
enum Columns
{
Id,
TargetDataId,
Name,
// ExerciseId,
TargetParticipantId,
Position,
ActivateLaserDesignation,
ActivateLights,
ActivatePopupAutomatic,
HitsToKill,
PermanentInstalledTarget,
VisibleParticipants,
IsUsedBy
};
explicit ShootbackTargetModel(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc);
QVariant data(const QModelIndex &, int) const override;
protected:
bool isFiltered(const ShootbackTarget &data, DataModification modType) const override
{
return BaseClass::isFiltered(data, modType);
}
private:
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
LOGGER_T m_logger;
};
} //namespace TargetManagement
@@ -0,0 +1,213 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party View
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_shootback_target_view.h"
#include "ui_tgt_shootback_target_view.h"
//#include "CustomView/ppm_party.h"
#include "tgt_shootback_target_edit.h"
#include <LtsPrinting/printing.h>
#include <QTreeView>
namespace TargetManagement
{
ShootbackTargetView::ShootbackTargetView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_session(session)
, m_ui(new Ui::ShootbackTargetView)
, m_logger(getLogger("ShootbackTargetView"))
{
m_ui->setupUi(this);
m_ui->widget->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &ShootbackTargetView::enaDisa);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked, this, &ShootbackTargetView::onEditShootbackTarget);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalEnterPressed, this, &ShootbackTargetView::onEditShootbackTarget);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &ShootbackTargetView::onEditShootbackTarget);
// m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &ShootbackTargetView::onAddParty);
// m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &ShootbackTargetView::onRemoveParty);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ShootbackTargetView::onPrint);
// m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &ShootbackTargetView::onSyncParties);
m_buttonBox->setText(LtsWidgets::DialogButton::Load, tr("Synchronize Parties"));
setOnlineHelpFilename(QStringLiteral("Administrator-ShootbackTargets"));
}
ShootbackTargetView::~ShootbackTargetView()
{
delete m_ui;
}
void ShootbackTargetView::retranslate()
{
translate(m_ui, tr("ShootbackTargets"));
}
bool ShootbackTargetView::init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc)
{
if (!dtc || !ftc)
return false;
m_dtc = dtc;
m_ftc = ftc;
m_model = new ShootbackTargetModel(this);
m_model->initModel(m_dtc);
m_ui->widget->setModel(m_model);
// m_ui->widget->setModel(m_model, [this]() { return new CustomViewParty(this); });
#ifndef LTS_DEBUG
m_ui->widget->hideColumn(ShootbackTargetModel::Id);
#endif
m_ui->widget->setSortingEnabled(false);
connect(m_model, &ShootbackTargetModel::rowsInserted, this, &ShootbackTargetView::enaDisa);
connect(m_model, &ShootbackTargetModel::rowsRemoved, this, &ShootbackTargetView::enaDisa);
enaDisa();
return true;
}
void ShootbackTargetView::enaDisa()
{
//const QModelIndex idx = m_ui->widget->currentIndex();
bool bAddVisible = false;
bool bEditEnabled = false;
bool bRemoveEnabled = false;
bool bRemoveVisible = false;
bool bLoadEnabled = true;
bool bLoadVisible = (m_session->exerciseId() > 0);
/*
* const int row = idx.row();
if (m_ui->widget->selectedRows().size() == 0 || row < 0)
{
bEditEnabled = false;
bRemoveEnabled = false;
}
else
{
const ParticipantManagement::Party party = m_model->getRowData(row);
bEditEnabled = party.id() > 0; // all but not pool
bRemoveEnabled = !party.isUsedBy();
}
if (m_session->exerciseId() > 0)
{
// no add parties in ex_N, they need to be added in ex_0 and synchronized. Last updated: 2018.04.12
bAddVisible = false;
// sync possible only in preparing exercise
const bool bInPreparation = (m_session->exerciseState() == LtsWidgets::ExerciseState::eCreated);
if (bInPreparation)
{
// sync possible only in preparing exercise
bLoadEnabled = true;
bLoadVisible = true;
bRemoveVisible = true;
}
else
{
// sync and delete not possible after starting exercise
bLoadEnabled = false;
bLoadVisible = false;
bRemoveVisible = false;
bRemoveEnabled = false;
}
}
*/
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, bAddVisible);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, bEditEnabled);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, bRemoveEnabled);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Remove, bRemoveVisible);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load, bLoadEnabled);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Load, bLoadVisible);
}
void ShootbackTargetView::onEditShootbackTarget()
{
const QModelIndex idx = m_ui->widget->currentIndex();
int row = idx.row();
if (row < 0)
return;
const TargetManagement::ShootbackTarget &target = m_model->getRowData(row);
ShootbackTargetEdit *dialog = new ShootbackTargetEdit(this);
dialog->init(m_dtc, m_ftc, nullptr, target);
addDialog(dialog, m_menuGroup, QLatin1String("tgtShootbackTarget") + QString::number(target.id()), LtsWidgets::LayoutArea::eDialogTab);
}
void ShootbackTargetView::onAddParty()
{
// PartyEdit *dialog = new PartyEdit(this);
// dialog->init(-1 , m_dtc, m_ftc, m_ppmGuiCbxIfc);
// addDialog(dialog, m_menuGroup, QLatin1String("ppmAddParty"), LtsWidgets::LayoutArea::eDialogTab);
}
void ShootbackTargetView::onRemoveParty()
{
// const QModelIndex curIdx = m_ui->widget->currentIndex();
// if (!curIdx.isValid())
// return;
// const Party party = m_model->getRowData(curIdx.row());
// if (party.id() < 0)
// return;
// RemovePartyRequest req;
// req.partyId(party.id());
// m_requestHelper->startSingleRequest([req, this]()
// {
// return m_ftc->removePartyRequest(req, this);
// });
// enaDisa();
}
void ShootbackTargetView::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->widget->treeView());
}
void ShootbackTargetView::onSyncParties()
{
// LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this,tr("Changes in this exercise will be lost. Do you wish to continue?"), tr("Warning"),
// LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
// if (button == LtsWidgets::Button::Yes)
// {
// m_requestHelper->startSingleRequest([this]()
// {
// SyncPartiesRequest req;
// req.exerciseId(m_session->exerciseId());
// DEBUG_LOG(m_logger) << "Sync parties for exercise " << req.exerciseId();
// return m_ftc->syncPartiesRequest(req, this);
// });
// }
// enaDisa();
}
} // namespace TargetManagement
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party View
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include "tgt_shootback_target_model.h"
#include <TargetManagement/logger.h>
#include <Services/TargetManagement/tgt_dtc.h>
#include <Services/TargetManagement/tgt_ftc.h>
//#include <Services/ExerciseManagement/exm_dtc.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace Ui
{
class ShootbackTargetView;
}
namespace TargetManagement
{
class ShootbackTargetView : public LtsWidgets::LtsDialog
// , protected ParticipantManagement::Interface::Ftc::ModifyPartyDataReplyHandler
// , protected ParticipantManagement::Interface::Ftc::RemovePartyReplyHandler
// , protected ParticipantManagement::Interface::Ftc::SyncPartiesReplyHandler
{
Q_OBJECT
public:
explicit ShootbackTargetView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~ShootbackTargetView();
bool init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc);
private:
void retranslate() override;
// void onModifyPartyDataReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
// void onRemovePartyReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
// void onSyncPartiesReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
void enaDisa();
void onEditShootbackTarget();
void onAddParty();
void onRemoveParty();
void onPrint();
void onSyncParties();
private:
QString m_menuGroup;
ShootbackTargetModel *m_model{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LtsSession::LtsSession *m_session{nullptr};
Ui::ShootbackTargetView *m_ui{nullptr};
LOGGER_T m_logger;
};
} // namespace ParticipantManagement
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ShootbackTargetView</class>
<widget class="QWidget" name="ShootbackTargetView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,487 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_area_dialog.h"
#include "ui_tgt_area_dialog.h"
#include "tgt_area_edit.h"
#include "tgt_telegrams.h"
#include <LtsSession/lts_session_data.h>
#include <FileManagement/flm_translation.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include "tgt_target_area_assignment_dialog.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
namespace TargetManagement
{
AreaDialog::AreaDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_session(session)
, m_ui(new Ui::AreaDialog)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("AreaDialog"))
{
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Situation-Assign/Configure_Targets"));
}
AreaDialog::~AreaDialog()
{
clearSelectionOfMapObjects();
delete m_ui;
}
bool AreaDialog::init()
{
if (!m_session)
return false;
if (!m_session->getDtc<TargetManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<TargetManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
return false;
if (!m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc))
return false;
// initialize model:
INFO_LOG(m_logger) << "AreaDialog::init";
m_areaModel = new AreaModel(this);
m_areaModel->initModel(m_dtc);
// proxyModel:
auto proxyModel = new AreaProxyModel(this);
proxyModel->setSourceModel(m_areaModel);
proxyModel->setDynamicSortFilter(false);
// set view: (LtsDataView)
m_ui->widget->setModel(proxyModel);
// to allow remove off some rows at once. Anoying in all other cases -> stay at singleSelection
// m_ui->widget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
m_assignTargetBtn = m_buttonBox->getButton(LtsWidgets::DialogButton::Import);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &AreaDialog::onAssignTargetButtonClicked);
// connects for gui
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &AreaDialog::onSelectionChanged);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &AreaDialog::onEditArea);
connect(this, &AreaDialog::escapePressed, this,
&AreaDialog::onEscapePressed, Qt::UniqueConnection);
// Create Add-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &AreaDialog::onNewArea);
// Create Remove-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &AreaDialog::onRemoveArea);
// Create Modify-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &AreaDialog::onEditArea);
// connect signals of TableView/CustomView:
connect(m_ui->widget, &LtsDataView::LtsDataView::clicked, this, &AreaDialog::onTableViewClicked);
// it´s possible to evaluate signalEntered, but seems to be overkill here:
// connect(m_ui->widget, &LtsDataView::LtsDataView::signalEntered, this, &AreaDialog::onObjectEntered);
#ifndef LTS_DEBUG
m_ui->widget->hideColumn(AreaModel::Columns::Id);
#endif
// Save/Load from Library Button
m_buttonBox->connectLibraryButton(this,
&AreaDialog::onImportButtonClicked,
&AreaDialog::onExportButtonClicked);
if (!m_flmGui)
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
// 'Map' Button(s)
m_buttonBox->connectButton(LtsWidgets::DialogButton::CenterMap, this, &AreaDialog::onMapCenterClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::ZoomMapTo, this, &AreaDialog::onMapZoomToClicked);
if (!m_sitMapGuiIfc)
{
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::CenterMap, false);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::ZoomMapTo, false);
}
// call eneDisa / onSelectionChanged once:
onSelectionChanged();
return true;
}
void AreaDialog::retranslate()
{
translate(m_ui, tr("Configure Areas"));
m_assignTargetBtn->setText(tr("Assign Targets"));
}
void AreaDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
return BaseClass::keyPressEvent(event);
}
void AreaDialog::onNewArea()
{
INFO_LOG(m_logger) << "onNewArea";
AreaEdit *dialog = new AreaEdit(this);
if (!dialog->init(m_dtc, m_ftc, m_sitMapGuiIfc, m_areaModel))
{
ERROR_LOG(m_logger) << QLatin1String("Can't initialize AreaEdit!");
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("Add Target"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
void AreaDialog::onRemoveArea()
{
const QModelIndexList &selectedRows = m_ui->widget->selectedRows();
for (const auto &mi : selectedRows)
{
Core::RemoveElementRequest req;
req.id(m_areaModel->getRowData(mi.row()).id());
m_requestHelper->addRequest([req, this]()
{
return m_ftc->shootbackAreaRemoveRequest(req, this);
});
}
m_requestHelper->startRequests();
}
void AreaDialog::onEditArea()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
INFO_LOG(m_logger) << " onEditTargetPart";
AreaEdit *dialog = new AreaEdit(this);
const TargetManagement::ShootbackArea &area = m_areaModel->getRowData(curIdx.row());
if (!dialog->init(m_dtc, m_ftc, m_sitMapGuiIfc, m_areaModel, area))
{
ERROR_LOG(m_logger) << LOGFUNCTION << QLatin1String("Can't initialize AreaEdit!");
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("Edit Area"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
QByteArray AreaDialog::toJson() const
{
QJsonObject obj;
// operatorId just for convenience:
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
obj[QStringLiteral("OperatorId")] = operatorId;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TGTShootbackArea);
{
const QVector<TargetManagement::ShootbackArea>& modelData = m_areaModel->getData();
QJsonArray jArray;
for (const TargetManagement::ShootbackArea &area : modelData)
{
ShootbackAreaData sbad;
sbad.id = area.id();
sbad.name = QString::fromStdString(area.name());
sbad.position = GeoPosition2D(area.position());
sbad.width = area.width();
sbad.height = area.height();
jArray.append(sbad.toJson());
}
obj[QStringLiteral("ShootbackAreas")] = jArray;
}
QJsonDocument doc(obj);
DEBUG_LOG(m_logger) << " json = " << doc.toJson();
return doc.toJson(QJsonDocument::Compact);
}
QVector<ShootbackArea> AreaDialog::fromJson(const QByteArray &content)
{
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
// operatorId just for convenience:
const int operatorId = obj[QStringLiteral("operatorId")].toInt();
Q_UNUSED(operatorId);
const QJsonArray &jArray = obj[QStringLiteral("ShootbackAreas")].toArray();
QVector<TargetManagement::ShootbackArea> vecData;
vecData.reserve(jArray.size());
for (const auto &item : jArray)
{
const ShootbackAreaData &sbad = ShootbackAreaData::fromJson(item.toObject());
TargetManagement::ShootbackArea area;
area.id(sbad.id);
area.name(sbad.name.toStdString());
area.position({sbad.position.lon, sbad.position.lat}); // GeoPosition2D( double lon, double lat);
area.width(sbad.width);
area.height(sbad.height);
vecData.push_back(std::move(area));
}
return vecData;
}
void AreaDialog::onEscapePressed()
{
m_ui->widget->clearSelection();
}
void AreaDialog::onExportButtonClicked()
{
QByteArray byteArray = toJson();
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
if (fileId > 0)
DEBUG_LOG(m_logger) << LOGFUNCTION << "Saved file with id = " << fileId;
else
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not save file in library ";
}
void AreaDialog::onImportButtonClicked()
{
QHash<LtsWidgets::Button, QString> buttonTexts;
buttonTexts.insert(LtsWidgets::Button::Ok, tr("Overwrite"));
buttonTexts.insert(LtsWidgets::Button::Cancel, tr("Cancel"));
LtsWidgets::LtsMessageDialogNew *dlg = new LtsWidgets::LtsMessageDialogNew(this,
tr("Overwrite existing data?"),
tr("Load from Library"),
LtsWidgets::Behaviour::Popup,
LtsWidgets::Button::Ok | LtsWidgets::Button::Cancel,
buttonTexts);
connect(dlg, &LtsWidgets::LtsMessageDialogNew::ok,
this, &AreaDialog::onImport);
}
void AreaDialog::onImport()
{
INFO_LOG(m_logger) << LOGFUNCTION << "--- onImportButtonClicked() ";
QByteArray content;
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml},
m_session->exerciseId(),
FileManagement::toString(FileManagement::XmlType::TGTShootbackArea));
if (fileId > 0)
{
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TGTShootbackArea)))
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Invalid xml file content"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes,
texts);
}
else
{
// update svc via clear and (re-)insert:
// 1) clear svc:
const QVector<ShootbackArea> &curData = m_areaModel->getData();
for (auto item : curData)
{
Core::RemoveElementRequest req(item.id());
m_requestHelper->addRequest([this, req]()
{
return m_ftc->shootbackAreaRemoveRequest(req, this);
});
}
// 2) re-insert:
const QVector<TargetManagement::ShootbackArea> vecDataCandidate(fromJson(content));
for (ShootbackArea area : vecDataCandidate)
{
DEBUG_LOG(m_logger) << "area " <<area;
area.id(0); // force create
m_requestHelper->addRequest([this, area]()
{
return m_ftc->shootbackAreaModifyRequest(area, this);
});
}
// clear view *before* performing the requests:
m_areaModel->clear();
m_requestHelper->startRequests();
}
}
}
void AreaDialog::onAssignTargetButtonClicked()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
const int areaId = m_areaModel->getRowData(curIdx.row()).id();
// instead of emit a signal, create the according dialog frome here directly
// emit assignTargetsRequested(areaId);
auto dlg = new AssignmentDialog(menuGroup(), m_session, this->parentWidget());
if (!dlg->init(AssignmentDialog::MODE::FILTERED_TO_SINGLE_AREA, areaId))
{
dlg->deleteLater();
return;
}
if (!m_session->addWidget(dlg, menuGroup(), QStringLiteral("ConfigureTargetsToAreaId_%1").arg(areaId), LtsWidgets::LayoutArea::eDialogTab))
dlg->deleteLater();
}
void AreaDialog::onMapCenterClicked()
{
if (!m_sitMapGuiIfc)
return;
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
const int id = m_areaModel->getRowData(curIdx.row()).id();
m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, id);
}
void AreaDialog::onMapZoomToClicked()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
QModelIndex index = selectedRows.first();
if (!index.isValid())
return;
if (!m_areaModel || !m_sitMapGuiIfc)
return;
int areaId = m_areaModel->getRowData(index.row()).id();
if (areaId<=0)
return;
// Assigned Targets:
QVector<int> assignedTargets;
auto cb = [areaId, &assignedTargets](const TargetManagement::TargetAreaAssignment &assignment)
{
if (assignment.areaId() == areaId)
assignedTargets.push_back(assignment.targetParticipantId());
};
m_dtc->targetAreaAssignments(cb);
{
QVector<QPair<SituationMap::MapObjectType, int>> entities;
entities.reserve(assignedTargets.size()+1);
entities.push_back({SituationMap::MapObjectType::MOT_ShootbackArea, areaId});
for (auto item : assignedTargets)
entities.push_back({SituationMap::MapObjectType::MOT_Participant, item});
m_sitMapGuiIfc->zoomMapTo(entities);
}
}
void AreaDialog::onObjectEntered(const QModelIndex &index)
{
if (!m_sitMapGuiIfc)
return;
if (!index.isValid())
{
m_sitMapGuiIfc->removeObjectIndicator();
return;
}
int areaId = m_areaModel->getRowData(index.row()).id();
if (areaId>0)
{
// Area
m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, areaId, true);
// Assigned Targets:
QVector<int> assignedTargets;
auto cb = [areaId, &assignedTargets](const TargetManagement::TargetAreaAssignment &assignment)
{
if (assignment.areaId() == areaId)
assignedTargets.push_back(assignment.targetParticipantId());
};
m_dtc->targetAreaAssignments(cb);
m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_Participant, assignedTargets, true);
}
else
m_sitMapGuiIfc->removeObjectIndicator();
}
void AreaDialog::onTableViewClicked(const QModelIndex &index)
{
if (!index.isValid())
return;
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
onMapCenterClicked();
}
void AreaDialog::clearSelectionOfMapObjects()
{
if (!m_sitMapGuiIfc)
return;
// remove MapObjectIndicator:
m_sitMapGuiIfc->removeObjectIndicator();
}
void AreaDialog::onSelectionChanged()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
const int cntSelectedRows = selectedRows.size();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, cntSelectedRows >= 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::CenterMap, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::ZoomMapTo, cntSelectedRows == 1);
m_assignTargetBtn->setEnabled(cntSelectedRows == 1); // LtsWidgets::DialogButton::Library
if (selectedRows.isEmpty())
onObjectEntered({}); // use invalid Idx to removeObjectIndicator
else
onObjectEntered(selectedRows.first());
}
//-----------------------------------------------------------------------------
} // namespace TargetManagement
@@ -0,0 +1,94 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/tgt_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <TargetManagement/logger.h>
#include <Plugins/TargetManagement/Gui/ShootbackTargetConfiguration/tgt_area_model.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
namespace Ui
{
class AreaDialog;
}
namespace TargetManagement
{
class AreaDialog final : public LtsWidgets::LtsDialog
, protected TargetManagement::Interface::Ftc::ShootbackAreaModifyReplyHandler
, protected TargetManagement::Interface::Ftc::ShootbackAreaRemoveReplyHandler
{
Q_OBJECT
public:
using BaseClass = LtsWidgets::LtsDialog;
explicit AreaDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~AreaDialog();
bool init();
void retranslate() override;
Q_SIGNALS:
void escapePressed();
protected:
void keyPressEvent(QKeyEvent *event) override final;
void onShootbackAreaModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onShootbackAreaRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
QByteArray toJson() const;
QVector<ShootbackArea> fromJson(const QByteArray &content);
private Q_SLOTS:
void onEscapePressed();
void onSelectionChanged();
void onNewArea();
void onRemoveArea();
void onEditArea();
void onExportButtonClicked();
void onImportButtonClicked();
void onImport();
void onAssignTargetButtonClicked();
void onMapCenterClicked();
void onMapZoomToClicked();
void onObjectEntered(const QModelIndex &index);
void onTableViewClicked(const QModelIndex &index);
void clearSelectionOfMapObjects();
private:
QPushButton *m_assignTargetBtn{nullptr};
AreaModel *m_areaModel{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
LtsSession::LtsSession *m_session{nullptr};
Ui::AreaDialog *m_ui{nullptr};
QString m_menuGroup;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LOGGER_T m_logger;
};
} // namespace TargetManagement
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AreaDialog</class>
<widget class="QWidget" name="AreaDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">AlarmView</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,174 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_area_edit.h"
#include "tgt_area_model.h"
#include "ui_tgt_area_edit.h"
#include <LtsUtilsSettings/settings.h>
namespace TargetManagement
{
AreaEdit::AreaEdit(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ui(new Ui::AreaEdit)
, m_logger(getLogger("AreaEdit"))
{
m_ui->setupUi(this);
m_ui->sbWidth->setMinimum(s_minWidth);
m_ui->sbWidth->setMaximum(s_maxWidth);
m_ui->sbWidth->setSingleStep(s_stepWidth);
m_ui->sbHeight->setMinimum(s_minHeight);
m_ui->sbHeight->setMaximum(s_maxHeight);
m_ui->sbHeight->setSingleStep(s_stepHeight);
}
//-----------------------------------------------------------------------------
AreaEdit::~AreaEdit()
{
delete m_ui;
}
//-----------------------------------------------------------------------------
void AreaEdit::retranslate()
{
translate(m_ui, m_area, tr("ShootbackArea"));
}
bool AreaEdit::init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMapGuiIfc,
AreaModel *areaModel,
const ShootbackArea &area)
{
DEBUG_LOG(m_logger) << "AreaEdit::init()";
if (!dtc || !ftc || !sitMapGuiIfc)
{
ERROR_LOG(m_logger) << "AreaEdit::init() Invalid shared_ptr!";
return false;
}
m_dtc = dtc;
m_ftc = ftc;
m_sitMapGuiIfc = sitMapGuiIfc;
m_areaModel = areaModel;
setData(area);
if (m_sitMapGuiIfc)
connect(m_ui->pbPosition, &QPushButton::clicked, this, &AreaEdit::getPosition);
else
m_ui->pbPosition->setEnabled(false);
connect(m_ui->pbClear, &QPushButton::clicked,
m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
setOnlineHelpFilename(QStringLiteral("Situation-Targets"));
// if (m_area.id() <= 0)
// slotChangesMade();
enaDisa();
return true;
}
void AreaEdit::enaDisa()
{
m_ui->pbPosition->setEnabled(m_sitMapGuiIfc.get());
}
//slots
bool AreaEdit::apply()
{
m_area.name(m_ui->leName->text().toStdString());
const QPointF &coord = m_ui->positionEdit->coordinate();
m_area.position({coord.x(), coord.y()});
m_area.width(m_ui->sbWidth->value());
m_area.height(m_ui->sbHeight->value());
m_requestHelper->addRequest([this]()
{
return m_ftc->shootbackAreaModifyRequest(m_area, this);
});
return m_requestHelper->startRequests();
}
void AreaEdit::getPosition()
{
if (!has2DMap())
return;
m_sitMapGuiIfc->getRectangleNorth(this,
SLOT(onRectData(QPointF,double,double,QPolygonF)),
nullptr,
s_minWidth,
s_maxWidth,
s_minHeight,
s_maxHeight,
m_ui->positionEdit->coordinate(),
m_ui->sbWidth->value(),
m_ui->sbHeight->value());
}
void AreaEdit::onRectData(const QPointF &centerPoint, double width, double height, const QPolygonF &coordinates)
{
m_previewPolygon = coordinates;
m_ui->positionEdit->setCoordinate(centerPoint);
m_ui->sbWidth->setValue(width);
m_ui->sbHeight->setValue(height);
DEBUG_LOG(m_logger) << "Pos X: " << centerPoint.x() << " Y: " << centerPoint.y() << " W: " << width << " H: " << height;
showPreviewObject();
}
//private
bool AreaEdit::has2DMap()
{
if (!m_sitMapGuiIfc)
return false;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return false;
}
return true;
}
void AreaEdit::showPreviewObject()
{
if (!m_sitMapGuiIfc)
return;
if (m_previewPolygon.isEmpty())
return;
m_sitMapGuiIfc->displayPreviewObject(this, m_previewPolygon, true);
}
void AreaEdit::setData(const ShootbackArea &area)
{
m_area = area;
if (m_area.id() > 0)
{
m_ui->leName->setText(QString::fromStdString(m_area.name()));
m_ui->positionEdit->setCoordinate(m_area.position().lon(), m_area.position().lat());
m_ui->sbWidth->setValue(m_area.width());
m_ui->sbHeight->setValue(m_area.height());
}
}
}
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <Services/TargetManagement/tgt_dtc.h>
#include <Services/TargetManagement/tgt_ftc.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <TargetManagement/logger.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace Ui
{
class AreaEdit;
}
namespace TargetManagement
{
class AreaModel;
class AreaEdit : public LtsWidgets::LtsDialog,
protected TargetManagement::Interface::Ftc::ShootbackAreaModifyReplyHandler
{
Q_OBJECT
public:
explicit AreaEdit(QWidget *parent = nullptr);
~AreaEdit();
bool init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
const std::shared_ptr<SituationMap::ForeignGuiInterface> &sitMapGuiIfc,
AreaModel *areaModel,
const ShootbackArea &area = ShootbackArea());
//virtual functions from TargetManagement::Interface::Ftc::..
void onShootbackAreaModifyReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
public Q_SLOTS:
private Q_SLOTS:
void enaDisa();
void getPosition();
void onRectData(const QPointF &centerPoint, double width, double height, const QPolygonF &coordinates);
private:
bool has2DMap();
void showPreviewObject();
void setData(const ShootbackArea &area);
bool apply() override;
void retranslate() override;
static constexpr double s_minWidth {10};
static constexpr double s_maxWidth {1000};
static constexpr double s_stepWidth {5};
static constexpr double s_minHeight {10};
static constexpr double s_maxHeight {1000};
static constexpr double s_stepHeight {5};
ShootbackArea m_area;
QPolygonF m_previewPolygon;
AreaModel *m_areaModel{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
Ui::AreaEdit *m_ui{nullptr};
LOGGER_T m_logger;
};
} //namespace TargetManagement
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AreaEdit</class>
<widget class="QWidget" name="AreaEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>963</width>
<height>318</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lbl_name">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="4">
<widget class="QLineEdit" name="leName"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="lblPosition">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Center Point:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="LtsCoordWidget::LtsCoordWidget" name="positionEdit" native="true">
<property name="toolTip">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QPushButton" name="pbPosition">
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/position.svg</normaloff>:/style/position.svg</iconset>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QPushButton" name="pbClear">
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/remove.svg</normaloff>:/style/remove.svg</iconset>
</property>
</widget>
</item>
<item row="1" column="6">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>690</width>
<height>33</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="lblDimensions">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Dimensions [m]:</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="LtsWidgets::LtsSpinBox" name="sbWidth"/>
</item>
<item row="2" column="4" colspan="2">
<widget class="LtsWidgets::LtsSpinBox" name="sbHeight"/>
</item>
<item row="2" column="6">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>181</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsCoordWidget::LtsCoordWidget</class>
<extends>QWidget</extends>
<header>LtsCoordTrans/lts_coord_widget.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsSpinBox</class>
<extends>QSpinBox</extends>
<header>LtsWidgets/lts_spinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leName</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,203 @@
/**
* @RDE_HEADER@
* AreaModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_area_model.h"
#include "tgt_common.h"
#include <LtsUtilsCore/variant_operators.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QApplication> // pixelMetric
#include <QBuffer>
namespace TargetManagement
{
//---------------------------------
// AreaModel
//---------------------------------
AreaModel::AreaModel(QObject *parent)
: BaseClass(
{
tr("Id"),
tr("Name"),
// main config
tr("Center"),
tr("Width"),
tr("Height"),
},
parent)
, m_logger(getLogger("AreaModel"))
{}
bool AreaModel::initModel(const std::shared_ptr<TargetManagement::Interface::Dtc> &tgtDtc)
{
m_tgt_dtc = tgtDtc;
// insert Model
const QMap<qint32, TargetManagement::ShootbackArea> areas = m_tgt_dtc->shootbackAreas();
INFO_LOG(m_logger) << "initModel - #AreaModel: " << areas.size();
connect(m_tgt_dtc.get(), &Interface::Dtc::shootbackAreaChanged,
this, &AreaModel::onShootbackAreaChanged);
auto cb = [this](const TargetManagement::ShootbackArea & d) { onShootbackAreaChanged(d, DataModification::eAdded); };
m_tgt_dtc->shootbackAreas(cb);
// updateColumnFilter
connect(this, &AreaModel::rowsInserted, this, &AreaModel::updateColumnFilter);
connect(this, &AreaModel::rowsRemoved, this, &AreaModel::updateColumnFilter);
connect(this, &AreaModel::modelReset, this, &AreaModel::updateColumnFilter);
// in case of changing value like hitsToKill:
connect(this, &AreaModel::dataChanged, this, &AreaModel::updateColumnFilter);
updateColumnFilter();
return true;
}
QVariant AreaModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
orientation == Qt::Horizontal)
{
// a few QSet<QString> ==>
const auto processString = [](const QSet<QString> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (const QString &value : usedXYCont)
{
cfd.data = value;
cfd.text = value;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
if (section == Name)
return processString(m_usedNames);
}
return BaseClass::headerData(section, orientation, role);
}
QVariant AreaModel::data(const QModelIndex &index, int role) const
{
INFO_LOG(m_logger) << LOGFUNCTION << " role=" << role
<< " index = " << index.column();
if (!indexIsValid(index))
return QVariant();
if (role != Qt::DisplayRole &&
role != Qt::DecorationRole &&
role != Qt::BackgroundRole &&
role != Qt::ToolTipRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
return QVariant();
const TargetManagement::ShootbackArea &shootbackArea = m_vecData.at(index.row());
if (role == Qt::BackgroundRole)
{
if ((index.column() == Center) &&
((shootbackArea.position().lat() <= 0) || (shootbackArea.position().lon() <= 0)))
return getWarningBackgroundRole(); // orange
if (index.column() == Width && shootbackArea.width() <= 0)
return getWarningBackgroundRole(); // orange
if (index.column() == Height && shootbackArea.height() <= 0)
return getWarningBackgroundRole(); // orange
}
else
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
if (index.column() == Name)
return QString::fromStdString(shootbackArea.name());
}
switch (index.column())
{
case Id:
return shootbackArea.id();
case Name:
return QString::fromStdString(shootbackArea.name());
case Center:
{
const Core::GeoPosition2D &pos = shootbackArea.position();
return LtsCoordTrans::mgrsFromGeographic(pos.lon(), pos.lat());
}
case Width:
return shootbackArea.width();
case Height:
return shootbackArea.height();
} // switch
return QVariant();
}
void AreaModel::onShootbackAreaChanged(const TargetManagement::ShootbackArea &data,
const DataModification modType)
{
BaseClass::onDataChanged(data, modType);
emit signalAreaNamesChanged();
}
void AreaModel::updateColumnFilter()
{
m_usedNames.clear();
for (const ShootbackArea &item : qAsConst(m_vecData))
m_usedNames.insert(QString::fromStdString(item.name()));
}
// --------------------------------------------------------
// AreaProxyModel
// --------------------------------------------------------
void AreaProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<AreaModel *>(sourceModel);
BaseClass::setSourceModel(sourceModel);
}
bool AreaProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel ||
source_left.column() != source_right.column() ||
source_left.row() < 0 || source_left.row() >= m_sourceModel->m_vecData.size() ||
source_right.row() < 0 || source_right.row() >= m_sourceModel->m_vecData.size()
)
return BaseClass::lessThan(source_left, source_right);
const TargetManagement::ShootbackArea &left = m_sourceModel->m_vecData.at(source_left.row());
const TargetManagement::ShootbackArea &right = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case AreaModel::Columns::Id:
return left.id() < right.id();
case AreaModel::Columns::Name:
return left.name() < right.name();
case AreaModel::Columns::Width:
return left.width() < right.width();
case AreaModel::Columns::Height:
return left.height() < right.height();
case AreaModel::Columns::Center:
// QString compare
return LtsUtils::lessThan(source_left.data(), source_right.data());
}
return BaseClass::lessThan(source_left, source_right);
}
} // namespace TargetManagement
@@ -0,0 +1,92 @@
/**
* @RDE_HEADER@
* AreaModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include "tgt_participant_handler.h"
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/logger.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsSession/lts_session.h>
namespace TargetManagement
{
// Forward:
class ParticipantHandler;
// --------------------------------------------------------
// AreaModel
// --------------------------------------------------------
class AreaModel final : public LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackArea>
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackArea>;
public:
enum Columns
{
Id,
Name,
// main config
Center,
Width,
Height
};
explicit AreaModel(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<Interface::Dtc> &tgtDtc);
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
QVariant data(const QModelIndex &, int) const override;
const QVector<ShootbackArea> &getData() const { return m_vecData; }
Q_SIGNALS:
void signalAreaNamesChanged();
private Q_SLOTS:
void onShootbackAreaChanged(const TargetManagement::ShootbackArea &data,
const DataModification modType);
void updateColumnFilter();
private:
friend class AreaProxyModel;
std::shared_ptr<TargetManagement::Interface::Dtc> m_tgt_dtc;
// column filter
QSet<QString> m_usedNames;
LOGGER_T m_logger;
};
// --------------------------------------------------------
// AreaProxyModel
// --------------------------------------------------------
class AreaProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
protected:
AreaModel *m_sourceModel{nullptr};
};
} //namespace TargetManagement
@@ -0,0 +1,703 @@
/**
* @RDE_HEADER@
* AssignmentParticipantModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_assignment_part_model.h"
#include "tgt_common.h"
#include <LtsUtilsCore/variant_operators.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QApplication> // pixelMetric
#include <QBuffer>
namespace TargetManagement
{
// some helper
bool isEqual(const ShootbackConfiguration &c1, const ShootbackConfiguration &c2)
{
return (
(c1.interval1() == c2.interval1()) &&
(c1.flash1() == c2.flash1()) &&
(c1.effect1() == c2.effect1()) &&
(c1.interval2() == c2.interval2()) &&
(c1.flash2() == c2.flash2()) &&
(c1.effect2() == c2.effect2())
);
}
bool isDefault(const ShootbackConfiguration &c) { return isEqual(c, ShootbackConfiguration()); }
bool isEqual(const TargetAreaAssignment &a1, const TargetAreaAssignment &a2, bool ignoringAreaIdAndParticipantId)
{
return (
(a1.id() == a2.id()) &&
(a1.name() == a2.name()) &&
(ignoringAreaIdAndParticipantId || (a1.areaId() == a2.areaId())) &&
(ignoringAreaIdAndParticipantId || (a1.targetParticipantId() == a2.targetParticipantId())) &&
(a1.isActive() == a2.isActive()) &&
isEqual(a1.configuration(), a2.configuration())
);
}
//---------------------------------
// AssignmentParticipantModel
//---------------------------------
AssignmentParticipantModel::AssignmentParticipantModel(QObject *parent)
: BaseClass(
{
tr("Id"),
tr("Assignment Name"),
tr("Assigned"), // isActive
// associated target:
tr("TargetId"),
tr("TargetName"),
// associated participant:
tr("Participant Id"),
tr("Equipmentnumber"),
tr("Participant"),
// associated Area
tr("AreaId"),
tr("AreaName"),
// configuration
tr("Interval_1"),
tr("Flash_1"),
tr("Effect_1"),
tr("Interval_2"),
tr("Flash_2"),
tr("Effect_2")
},
parent)
, m_logger(getLogger("AssignmentParticipantModel"))
{}
bool AssignmentParticipantModel::initModel(const std::shared_ptr<TargetManagement::Interface::Dtc> &tgtDtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
LtsSession::LtsSession *session)
{
m_tgt_dtc = tgtDtc;
m_session = session;
delete m_participantHandler;
m_participantHandler = new ParticipantHandler(this);
m_participantHandler->init(m_tgt_dtc, ppmDtc, ppmGuiCbxIfc /*, exmDtc*/); // exercises are no relavant yet
connect(m_participantHandler, &ParticipantHandler::signalParticipantNamesChanged,
this, &AssignmentParticipantModel::signalParticipantNamesChanged);
connect(m_participantHandler, &ParticipantHandler::signalParticipantChanged,
this, &AssignmentParticipantModel::update);
// insert Model
const QMap<qint32, TargetManagement::TargetAreaAssignment> targetAreaAssignments = m_tgt_dtc->targetAreaAssignments();
INFO_LOG(m_logger) << "initModel - #targetAreaAssignments.size(): " << targetAreaAssignments.size();
connect(m_tgt_dtc.get(), &Interface::Dtc::targetAreaAssignmentChanged,
this, &AssignmentParticipantModel::onTargetAreaAssignmentChanged);
{
auto cb = [this](const TargetManagement::TargetAreaAssignment & d) { onTargetAreaAssignmentChanged(d, DataModification::eAdded); };
m_tgt_dtc->targetAreaAssignments(cb);
}
INFO_LOG(m_logger) << "initModel - #targetAreaAssignments.size(): " << targetAreaAssignments.size() << " DONE";
// updateColumnFilter
connect(this, &AssignmentParticipantModel::rowsInserted, this, &AssignmentParticipantModel::updateColumnFilter);
connect(this, &AssignmentParticipantModel::rowsRemoved, this, &AssignmentParticipantModel::updateColumnFilter);
connect(this, &AssignmentParticipantModel::modelReset, this, &AssignmentParticipantModel::updateColumnFilter);
// in case of changing value like hitsToKill:
connect(this, &AssignmentParticipantModel::dataChanged, this, &AssignmentParticipantModel::updateColumnFilter);
updateColumnFilter();
return true;
}
QVariant AssignmentParticipantModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
orientation == Qt::Horizontal)
{
// a few QSet<QString> ==>
const auto processString = [](const QSet<QString> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (const QString &value : usedXYCont)
{
cfd.data = value;
cfd.text = value;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
// a few Set<int> ==>
const auto processBoolean = [this](const QSet<int> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (int value : usedXYCont)
{
cfd.data = value;
cfd.text = value ? tr("Yes") : tr("No");
cfd.icon = value ? m_yes : m_no;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
// a few Set<int> ==>
const auto processInt = [](const QSet<int> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (int value : usedXYCont)
{
cfd.data = value;
cfd.text = QString::number(value);
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
if (section == IsActive)
return processBoolean(m_usedIsActive);
else if (section == AreaId)
return processInt(m_usedAreaIds);
else if (section == AreaName)
return processString(m_usedAreas);
else if (section == TargetId)
return processInt(m_usedTargetIds);
else if (section == TargetName)
return processString(m_usedTargets);
else if (section == TargetPartipantId)
return processInt(m_usedTargetParticipantIds);
else if (section == TargetPartipantEquipmentNumber)
return processInt(m_usedParticipantEqNo);
else if (section == Participant)
return processString(m_usedParticipants);
}
return BaseClass::headerData(section, orientation, role);
}
template <typename T>
QVariant handleIsDefault(const TargetManagement::TargetAreaAssignment &assignment, const T &value)
{
if (isDefault(assignment.configuration()))
return QStringLiteral("-");
return value;
}
QVariant AssignmentParticipantModel::data(const QModelIndex &index, int role) const
{
INFO_LOG(m_logger) << LOGFUNCTION << " role=" << role
<< " index = " << index.column();
if (!indexIsValid(index))
return QVariant();
if (role != Qt::DisplayRole &&
role != Qt::EditRole &&
role != Qt::CheckStateRole &&
role != Qt::DecorationRole &&
role != Qt::ForegroundRole &&
role != Qt::BackgroundRole &&
role != Qt::ToolTipRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
return QVariant();
const TargetManagement::TargetAreaAssignment &assignment = m_vecData.at(index.row());
if (role == Qt::CheckStateRole)
{
// CheckBoxes only for columns that are actually checkable
if (!flags(index).testFlag(Qt::ItemIsUserCheckable))
return QVariant();
return assignment.isActive() ? Qt::Checked : Qt::Unchecked;
}
else if (role == Qt::DecorationRole)
{
if (index.column() == Participant)
{
static const int pmSize = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
const QPixmap &pm = m_participantHandler->getParticipantDecoration(assignment.targetParticipantId());
if (!pm.isNull())
return pm.scaled(pmSize, pmSize);
}
else if ((index.column() == Flash_1))
return assignment.configuration().flash1() ? m_yes : m_no;
else if ((index.column() == Flash_2))
return assignment.configuration().flash2() ? m_yes : m_no;
return QVariant();
}
else if (role == Qt::BackgroundRole)
{
if ((index.column() == TargetId) || (index.column() == TargetName))
{
int targetId = m_participantHandler->getParticipantIdToTargetId(assignment.targetParticipantId());
if (targetId <= 0)
return getNoParticipantColor(); // orange
}
else if ((index.column() == AreaId) || (index.column() == AreaName))
{
if (m_tgt_dtc->shootbackArea(assignment.areaId()).id()<=0)
return getNoParticipantColor(); // orange
}
else if ((index.column() == TargetPartipantId) && (assignment.targetParticipantId() <= 0))
return getNoParticipantColor(); // orange
else if (index.column() == TargetPartipantEquipmentNumber)
{
const int eqNo = m_participantHandler->getParticipantIdToEquipmentNumber(assignment.targetParticipantId());
if (eqNo <= 0)
return getNoParticipantColor(); // orange
}
// no else here
if (assignment.isActive() && isDefault(assignment.configuration()))
return getAssignedButNoConfigurationColor(); // lightRed
}
else if (role == Qt::ForegroundRole)
{
if (!assignment.isActive() && (index.column() != Participant))
return QColor(Qt::gray);
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == Participant)
{
QString tooltip(QStringLiteral("<html>"));
const QPixmap &img = m_participantHandler->getParticipantDecoration(assignment.targetParticipantId());
if (!img.isNull())
{
// without a temporary file:
QByteArray data;
QBuffer buffer(&data);
img.save(&buffer, "PNG", 100);
tooltip.append(QStringLiteral("<center><img src='data:image/png;base64,%1'></center>").arg(QString::fromLatin1(data.toBase64())));
QString hdr = this->headerData(AssignmentName, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, QString::fromStdString(assignment.name())));
hdr = this->headerData(Participant, Qt::Horizontal, Qt::DisplayRole).toString();
const QString &val = m_participantHandler->getParticipantHierarchie(assignment.targetParticipantId());
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, val));
tooltip.append(QStringLiteral("</html>"));
return tooltip;
}
}
}
else if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
// following static_cast<int> are important!!!
if (index.column() == IsActive)
return static_cast<int>(assignment.isActive());
if (index.column() == AreaId)
return assignment.areaId();
if (index.column() == TargetPartipantId)
return assignment.targetParticipantId();
}
switch (index.column())
{
case Id:
return assignment.id();
case AssignmentName:
return QString::fromStdString(assignment.name());
case IsActive:
return assignment.isActive() ? tr("Yes") : tr("No");
case TargetId:
{
int targetId = m_participantHandler->getParticipantIdToTargetId(assignment.targetParticipantId());
return targetId;
}
case TargetName:
{
int targetId = m_participantHandler->getParticipantIdToTargetId(assignment.targetParticipantId());
if (targetId <= 0)
return QStringLiteral("-");
const ShootbackTarget &st = m_tgt_dtc->shootbackTarget(targetId);
if (st.id() != targetId)
return QStringLiteral("-");
return QString::fromStdString(st.name());
}
// associated participant:
case TargetPartipantId:
return assignment.targetParticipantId();
case TargetPartipantEquipmentNumber:
{
const int eqNo = m_participantHandler->getParticipantIdToEquipmentNumber(assignment.targetParticipantId());
if (eqNo <= 0)
return QStringLiteral("-");
return eqNo;
}
case Participant:
return m_participantHandler->getParticipantHierarchie(assignment.targetParticipantId());
// associated area:
case AreaId:
return assignment.areaId();
case AreaName:
return QString::fromStdString(m_tgt_dtc->shootbackArea(assignment.areaId()).name());
// configuration:
case Interval_1:
return handleIsDefault(assignment, assignment.configuration().interval1());
case Flash_1:
return handleIsDefault(assignment, assignment.configuration().flash1());
case Effect_1:
return handleIsDefault(assignment, effectToString(assignment.configuration().effect1()));
case Interval_2:
return handleIsDefault(assignment, assignment.configuration().interval2());
case Flash_2:
return handleIsDefault(assignment, assignment.configuration().flash2());
case Effect_2:
return handleIsDefault(assignment, effectToString(assignment.configuration().effect2()));
} // switch
return QVariant();
}
bool AssignmentParticipantModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!indexIsValid(index))
return false;
if (role != Qt::CheckStateRole)
return false;
if (!value.canConvert<bool>())
return false;
bool bVal = value.toBool();
TargetAreaAssignment &data = m_vecData[index.row()];
if (data.isActive() != bVal)
{
data.isActive(bVal);
emit dataChanged(index, index);
emit signalEditableItemChanged();
}
return true;
}
Qt::ItemFlags AssignmentParticipantModel::flags(const QModelIndex &index) const
{
auto f = QAbstractTableModel::flags(index);
if (!index.isValid() || index.row() >= m_vecData.size())
return f;
if (index.column() == Columns::IsActive)
{
f.setFlag(Qt::ItemIsUserCheckable);
return f;
}
return f;
}
QSet<int> AssignmentParticipantModel::getAssociatedParticipantIds() const
{
QSet<int> ret;
ret.reserve(m_vecData.size());
for (const TargetManagement::TargetAreaAssignment &data : m_vecData)
ret += data.targetParticipantId();
return ret;
}
QSet<int> AssignmentParticipantModel::getAssociatedParticipantIdsForArea(int areaId) const
{
QSet<int> ret;
ret.reserve(m_vecData.size());
for (const TargetManagement::TargetAreaAssignment &data : m_vecData)
if (data.areaId() == areaId)
ret += data.targetParticipantId();
return ret;
}
QSet<int> AssignmentParticipantModel::getAssociatedAreasIdsForParticipantId(int participantId) const
{
QSet<int> ret;
ret.reserve(m_vecData.size());
for (const TargetManagement::TargetAreaAssignment &data : m_vecData)
if (data.targetParticipantId() == participantId)
ret += data.areaId();
return ret;
}
int AssignmentParticipantModel::findRowForAreaTargetParticipantId(int areaId, int targetParticipantId)
{
for (int i = 0; i < m_vecData.size(); ++i) // clazy:exclude=range-loop
{
const TargetAreaAssignment &curAssignment = m_vecData.at(i);
if ((curAssignment.areaId() == areaId) && (curAssignment.targetParticipantId() == targetParticipantId))
return i;
}
return -1;
}
void AssignmentParticipantModel::addGapFillerForArea(int areaId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, areaId=" << areaId;
const QSet<int> &associatedParticipantIds = getAssociatedParticipantIdsForArea(areaId);
QVector<TargetManagement::TargetAreaAssignment> gapFillers;
#define USE_PARTICIPANTS_OF_ORBAT
#ifdef USE_PARTICIPANTS_OF_ORBAT
// participantIds with EquipmentType (WmsTypeClass::TargetVehicle||WmsTypeClass::TargetHuman)
QList<int> pIds = getParticipantHierarchies().keys();
for (auto pId : qAsConst(pIds))
{
if (!associatedParticipantIds.contains(pId))
{
TargetManagement::TargetAreaAssignment gapFiller;
gapFiller.areaId(areaId);
gapFiller.targetParticipantId(pId);
gapFiller.isActive(false);
gapFillers.push_back(gapFiller);
}
} // for
#else // USE_PARTICIPANTS_OF_ORBAT
// use just the (base)configured targets:
auto cb = [associatedParticipantIds, areaId, &gapFillers](const TargetManagement::ShootbackTarget & targets)
{
if (targets.targetParticipantId() <= 0)
return;
if (!associatedParticipantIds.contains(targets.targetParticipantId()))
{
TargetManagement::TargetAreaAssignment gapFiller;
gapFiller.areaId(areaId);
gapFiller.targetParticipantId(targets.targetParticipantId());
gapFiller.isActive(false);
gapFillers.push_back(gapFiller);
}
};
m_tgt_dtc->shootbackTargets(cb);
#endif
this->insertRows(gapFillers);
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, areaId=" << areaId;
}
void AssignmentParticipantModel::addGapFillerForTargetParticipantId(int targetParticipantId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, targetParticipantId=" << targetParticipantId;
const QSet<int> &associatedAreaIds = getAssociatedAreasIdsForParticipantId(targetParticipantId);
QVector<TargetManagement::TargetAreaAssignment> gapFillers;
// gapFillers.reserve(1000);
auto cb = [associatedAreaIds, targetParticipantId, &gapFillers](const TargetManagement::ShootbackArea & area)
{
if (!associatedAreaIds.contains(area.id()))
{
TargetManagement::TargetAreaAssignment gapFiller;
gapFiller.areaId(area.id());
gapFiller.targetParticipantId(targetParticipantId);
gapFiller.isActive(false);
gapFillers.push_back(gapFiller);
}
};
m_tgt_dtc->shootbackAreas(cb);
this->insertRows(gapFillers);
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, targetParticipantId=" << targetParticipantId;
}
void AssignmentParticipantModel::onTargetAreaAssignmentChanged(const TargetManagement::TargetAreaAssignment &data,
DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " modType=" << modType << " data=" << data;
// avoid adding an assignment which already exists:
if (modType == DataModification::eAdded)
{
int row = findRowForAreaTargetParticipantId(data.areaId(), data.targetParticipantId());
DEBUG_LOG(m_logger) << LOGFUNCTION << " row=" << row;
if (row >= 0)
{
setRowData(row, data);
emit signalParticipantNamesChanged();
return;
}
}
BaseClass::onDataChanged(data, modType);
emit signalParticipantNamesChanged();
}
void AssignmentParticipantModel::updateColumnFilter()
{
m_usedIsActive.clear();
m_usedAreaIds.clear();
m_usedAreas.clear();
m_usedTargetIds.clear();
m_usedTargets.clear();
m_usedTargetParticipantIds.clear();
m_usedParticipantEqNo.clear();
m_usedParticipants.clear();
int row = -1;
for (const TargetAreaAssignment &assignment : qAsConst(m_vecData))
{
++row;
// This loops over ALL item, even if some of them are filtered by the AssignmentParticipantProxyModel (areaId, ..)
m_usedIsActive.insert(assignment.isActive());
m_usedAreaIds.insert(assignment.areaId());
m_usedAreas.insert( QString::fromStdString(m_tgt_dtc->shootbackArea(assignment.areaId()).name()) );
int targetId = m_participantHandler->getParticipantIdToTargetId(assignment.targetParticipantId());
m_usedTargetIds.insert(targetId);
m_usedTargets.insert(this->data(index(row, TargetName), Qt::DisplayRole).toString());
m_usedTargetParticipantIds.insert(assignment.targetParticipantId());
const int eqNo = m_participantHandler->getParticipantIdToEquipmentNumber(assignment.targetParticipantId());
m_usedParticipantEqNo.insert(eqNo);
m_usedParticipants.insert(m_participantHandler->getParticipantHierarchie(assignment.targetParticipantId()));
}
}
QString AssignmentParticipantModel::effectToString(const Effect &effect) const
{
switch (effect.underlying())
{
case TargetManagement::Effect_def::NearMiss:
return tr("NearMiss");
case TargetManagement::Effect_def::MobilityKill:
return tr("MobilityKill");
case TargetManagement::Effect_def::WeaponKill:
return tr("WeaponKill");
default:
{
// empty
}
}
return QStringLiteral("-");
}
// --------------------------------------------------------
// AssignmentParticipantProxyModel
// --------------------------------------------------------
void AssignmentParticipantProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<AssignmentParticipantModel *>(sourceModel);
BaseClass::setSourceModel(sourceModel);
}
void AssignmentParticipantProxyModel::filterToAreaId(int areaId)
{
m_areaId = areaId;
m_targetParticipantId = -1;
invalidateFilter();
}
void AssignmentParticipantProxyModel::filterToTargetParticpantId(int targetParticpantId)
{
m_targetParticipantId = targetParticpantId;
m_areaId = -1;
invalidateFilter();
}
bool AssignmentParticipantProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel)
return BaseClass::filterAcceptsRow(source_row, source_parent);
if (m_areaId > 0)
{
const TargetManagement::TargetAreaAssignment &item = m_sourceModel->m_vecData.at(source_row);
return (item.areaId() == m_areaId) && BaseClass::filterAcceptsRow(source_row, source_parent);
}
else if ((m_targetParticipantId > 0))
{
const TargetManagement::TargetAreaAssignment &item = m_sourceModel->m_vecData.at(source_row);
return (item.targetParticipantId() == m_targetParticipantId) && BaseClass::filterAcceptsRow(source_row, source_parent);;
}
return BaseClass::filterAcceptsRow(source_row, source_parent);
}
bool AssignmentParticipantProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel || !m_sourceModel->m_participantHandler ||
source_left.column() != source_right.column() ||
source_left.row() < 0 || source_left.row() >= m_sourceModel->m_vecData.size() ||
source_right.row() < 0 || source_right.row() >= m_sourceModel->m_vecData.size()
)
return BaseClass::lessThan(source_left, source_right);
const TargetManagement::TargetAreaAssignment &left = m_sourceModel->m_vecData.at(source_left.row());
const TargetManagement::TargetAreaAssignment &right = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case AssignmentParticipantModel::Columns::Id:
return left.id() < right.id();
case AssignmentParticipantModel::Columns::AssignmentName:
return left.name() < right.name();
case AssignmentParticipantModel::Columns::TargetPartipantId:
return left.targetParticipantId() < right.targetParticipantId();
case AssignmentParticipantModel::Columns::TargetPartipantEquipmentNumber:
{
const int eqNoLeft = m_sourceModel->m_participantHandler->getParticipantIdToEquipmentNumber(left.targetParticipantId());
const int eqNoRight = m_sourceModel->m_participantHandler->getParticipantIdToEquipmentNumber(right.targetParticipantId());
return eqNoLeft < eqNoRight;
}
case AssignmentParticipantModel::Columns::AreaId:
return left.areaId() < right.areaId();
case AssignmentParticipantModel::Columns::Participant:
case AssignmentParticipantModel::Columns::AreaName:
// QString compare
return LtsUtils::lessThan(source_left.data(), source_right.data());
}
return BaseClass::lessThan(source_left, source_right);
}
} // namespace TargetManagement
@@ -0,0 +1,160 @@
/**
* @RDE_HEADER@
* AssignmentParticipantModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include "tgt_participant_handler.h"
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/logger.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsSession/lts_session.h>
namespace TargetManagement
{
// Forward:
class ParticipantHandler;
bool isEqual(const ShootbackConfiguration &c1, const ShootbackConfiguration &c2);
bool isDefault(const ShootbackConfiguration &c);
bool isEqual(const TargetAreaAssignment &a1, const TargetAreaAssignment &a2, bool ignoringAreaIdAndParticipantId = false);
// --------------------------------------------------------
// AssignmentParticipantModel
// --------------------------------------------------------
class AssignmentParticipantModel final : public LtsWidgets::LtsAbstractTableModel<TargetManagement::TargetAreaAssignment>
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsAbstractTableModel<TargetManagement::TargetAreaAssignment>;
public:
enum Columns
{
Id,
AssignmentName,
IsActive,
// associated target:
TargetId,
TargetName,
// (associated participant):
TargetPartipantId,
TargetPartipantEquipmentNumber,
Participant,
// associated area
AreaId,
AreaName,
// configuration
Interval_1,
Flash_1,
Effect_1,
Interval_2,
Flash_2,
Effect_2
};
explicit AssignmentParticipantModel(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<Interface::Dtc> &tgtDtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
LtsSession::LtsSession *session);
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
QVariant data(const QModelIndex &, int) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
const QHash <int, QString> &getParticipantHierarchies() const { return m_participantHandler->getParticipantHierarchies(); }
const QHash <int, QPixmap> &getParticipantDecorations() const { return m_participantHandler->getParticipantDecorations(); }
QSet<int> getAssociatedParticipantIds() const;
QSet<int> getAssociatedParticipantIdsForArea(int areaId) const;
QSet<int> getAssociatedAreasIdsForParticipantId(int participantId) const;
int findRowForAreaTargetParticipantId(int areaId, int targetParticipantId);
const QVector<TargetAreaAssignment> &getData() const { return m_vecData; }
void addGapFillerForArea(int areaId);
void addGapFillerForTargetParticipantId(int targetParticipantId);
Q_SIGNALS:
void signalParticipantNamesChanged();
void signalEditableItemChanged();
private Q_SLOTS:
void onTargetAreaAssignmentChanged(const TargetManagement::TargetAreaAssignment &data,
DataModification modType);
void updateColumnFilter();
private:
QString effectToString(const TargetManagement::Effect &effect) const;
friend class AssignmentParticipantProxyModel;
std::shared_ptr<TargetManagement::Interface::Dtc> m_tgt_dtc;
ParticipantHandler *m_participantHandler{nullptr};
LtsSession::LtsSession *m_session{nullptr};
QIcon m_yes{QLatin1String("icon:yes.svg")};
QIcon m_no{QLatin1String("icon:no.svg")};
// column filter
QSet<int> m_usedIsActive; // Assigned
QSet<int> m_usedAreaIds;
QSet<QString> m_usedAreas;
QSet<int> m_usedTargetIds;
QSet<QString> m_usedTargets;
QSet<int> m_usedTargetParticipantIds;
QSet<int> m_usedParticipantEqNo;
QSet<QString> m_usedParticipants;
// continue with all configuration data???
LOGGER_T m_logger;
};
// --------------------------------------------------------
// AssignmentParticipantProxyModel
// --------------------------------------------------------
class AssignmentParticipantProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
int getFilterToAreaId() const { return m_areaId; }
void filterToAreaId(int areaId = -1);
int getFilterToTargetParticpantId() const { return m_targetParticipantId; }
void filterToTargetParticpantId(int targetParticpantId = -1);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override final;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
protected:
AssignmentParticipantModel *m_sourceModel{nullptr};
int m_areaId{-1};
int m_targetParticipantId{-1};
};
} //namespace TargetManagement
@@ -0,0 +1,24 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-07-ß8
*/
#include "tgt_common.h"
#include <QColor>
namespace TargetManagement
{
QColor getWarningBackgroundRole() { return QColor(240, 94, 35); } // QColor(240, 94, 35) -> orange
QColor getNoParticipantColor() { return QColor(240, 94, 35); } // QColor(240, 94, 35) -> orange
QColor getAssignedButNoConfigurationColor() { return QColor(255, 127, 127); } // QColor(255, 127, 127); -> lightRed
} // namespace TargetManagement
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-07-ß8
*/
#pragma once
// forward:
class QColor;
namespace TargetManagement
{
// missing configuration
QColor getWarningBackgroundRole();
// no participant -> orange
QColor getNoParticipantColor();
// assigned, but no behaviour configuration -> lightRed
QColor getAssignedButNoConfigurationColor();
} // namespace TargetManagement
@@ -0,0 +1,240 @@
/**
* @RDE_HEADER@
* Handler for ParticipantData
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_participant_handler.h"
#include <ParticipantManagement/ppm_translation.h>
#include <SituationMap/Symbology/symbol_result.h>
#include <SituationMap/Symbology/symbol_dictionary.h>
#include <QApplication> // pixelMetric
namespace TargetManagement
{
//---------------------------------
// ParticipantHandler
//---------------------------------
ParticipantHandler::ParticipantHandler(QObject *parent)
: BaseClass(parent)
, m_logger(getLogger("ParticipantHandler"))
{}
bool ParticipantHandler::init(const std::shared_ptr<Interface::Dtc> &tgt_dtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc)
{
m_tgt_dtc = tgt_dtc;
m_ppm_dtc = ppmDtc;
m_ppmGuiCbxIfc = ppmGuiCbxIfc;
// init
if (m_tgt_dtc)
{
connect(m_tgt_dtc.get(), &TargetManagement::Interface::Dtc::shootbackTargetChanged,
this, &ParticipantHandler::onShootbackTargetChanged);
auto cb = [this](const TargetManagement::ShootbackTarget & d) { onShootbackTargetChanged(d, DataModification::eAdded); };
m_tgt_dtc->shootbackTargets(cb);
}
if (m_ppm_dtc)
{
{
connect(m_ppm_dtc.get(), &ParticipantManagement::Interface::Dtc::typeChanged,
this, &ParticipantHandler::onTypeChanged);
auto cb = [this](const ParticipantManagement::Type & d) { onTypeChanged(d, DataModification::eAdded); };
m_ppm_dtc->types(cb);
}
{
connect(m_ppm_dtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &ParticipantHandler::onParticipantChanged);
auto cb = [this](const ParticipantManagement::Participant & d) { onParticipantChanged(d, DataModification::eAdded); };
m_ppm_dtc->participants(cb);
}
}
return true;
}
int ParticipantHandler::getParticipantIdToTargetId(int participantId) const
{
return m_participantIdToTargetId.value(participantId, -1);
}
QString ParticipantHandler::getParticipantHierarchie(int participantId) const
{
return m_participantHierarchies.value(participantId, tr("No participant name available"));
}
QString ParticipantHandler::target_wmsTypeClassToString(const ParticipantManagement::WmsTypeClass &wmsTypeClass)
{
switch (wmsTypeClass.underlying())
{
case ParticipantManagement::WmsTypeClass_def::TargetHuman:
return QStringLiteral("Human");
case ParticipantManagement::WmsTypeClass_def::TargetVehicle:
return QStringLiteral("Vehicle");
break;
default:
{
// empty
}
} //switch
return QStringLiteral("-");
}
void ParticipantHandler::onShootbackTargetChanged(const TargetManagement::ShootbackTarget &data, const DataModification modType)
{
INFO_LOG(m_logger) << "onShootbackTargetChanged: " << data << ", " << modType;
switch (modType)
{
case DataModification::eRemoved:
m_participantIdToTargetId.remove(data.targetParticipantId());
break;
case DataModification::eModified:
case DataModification::eAdded:
m_participantIdToTargetId.insert(data.targetParticipantId(), data.id());
break;
}
}
void ParticipantHandler::onTypeChanged(const ParticipantManagement::Type &data,
const DataModification modType)
{
INFO_LOG(m_logger) << "onTypeChanged:" << data << ", " << modType;
switch (modType)
{
case DataModification::eRemoved:
m_typeToTypeClass.remove(data.id());
break;
case DataModification::eModified:
case DataModification::eAdded:
m_typeToTypeClass.insert(data.id(), data.typeClass());
break;
}
}
void ParticipantHandler::onParticipantChanged(const ParticipantManagement::Participant &data,
DataModification modType)
{
TRACE_LOG(m_logger) << "onParticipantChanged: " << data << ", " << modType;
if (data.isDeleted())
modType = DataModification::eRemoved;
const int dataId = data.id();
switch (modType)
{
case DataModification::eRemoved:
m_participantHierarchies.remove(dataId);
m_participantIdToEq.remove(dataId);
m_participantIdToWmsTypeClass.remove(dataId);
break;
case DataModification::eModified:
case DataModification::eAdded:
{
DEBUG_LOG(m_logger) << "DataModification::eAdded Participant"
<< " Id=" << dataId
<< " TypeId=" << data.typeId()
<< " eqId=" << (data.equipmentNumber().is_set() ? data.equipmentNumber().get() : -1)
<< " " << data.name();
const int typeId = data.typeId();
const ParticipantManagement::Type &type = m_ppm_dtc->type(typeId);
if (type.id() != typeId)
return;
const int equipmentTypeId = type.equipmentTypeId();
const ParticipantManagement::EquipmentType &eqType = m_ppm_dtc->equipmentType(equipmentTypeId);
if (eqType.id() != equipmentTypeId)
return;
m_participantIdToWmsTypeClass.insert(dataId, eqType.wmsTypeClass());
bool bIsTarget{false};
switch (eqType.wmsTypeClass().underlying())
{
case ParticipantManagement::WmsTypeClass::None:
case ParticipantManagement::WmsTypeClass::Building:
case ParticipantManagement::WmsTypeClass::Vehicle:
case ParticipantManagement::WmsTypeClass::Human:
case ParticipantManagement::WmsTypeClass::Airborne:
case ParticipantManagement::WmsTypeClass::VehicleMarker:
bIsTarget = false;
break;
case ParticipantManagement::WmsTypeClass::TargetVehicle:
case ParticipantManagement::WmsTypeClass::TargetHuman:
bIsTarget = true;
break;
default:
break;
} // switch
if (!bIsTarget)
return;
// m_participantIdToEq :
int eqId = -1;
if (data.equipmentNumber().is_set())
eqId = data.equipmentNumber().get();
if (eqId >= 0)
m_participantIdToEq[dataId] = eqId;
else
m_participantIdToEq.remove(dataId);
// : m_participantIdToEq
// hierarchy...
const QString hierarchy = m_ppm_dtc->hierarchyFromParticipant(dataId);
if (data.equipmentNumber().is_set())
m_participantHierarchies.insert(dataId, hierarchy + QString(QStringLiteral(" (%1)")).arg(data.equipmentNumber().get()));
else
m_participantHierarchies.insert(dataId, hierarchy);
if (m_ppmGuiCbxIfc)
{
// afterwards, render sidc:
AdvancedSymbology::SymbolDictionary &dictionary =
AdvancedSymbology::SymbolDictionary::dictionary(AdvancedSymbology::SymbologyType::APP6D);
if (!m_participantDecorations.contains(dataId))
{
// for very first view, use simple squares of partyColor:
const auto party = m_ppm_dtc->party(data.partyId());
const QRgb col = QRgb(party.color());
m_participantDecorations.insert(dataId, m_ppmGuiCbxIfc->pixmapFromParty(col));
AdvancedSymbology::SymbolDataToRender symDataToRender(QString::fromStdString(data.symbol()));
symDataToRender.fillColor = m_ppm_dtc->party(data.partyId()).color();
symDataToRender.fillColorReplace = true;
AdvancedSymbology::SymbolResultWatcher *srw =
new AdvancedSymbology::SymbolResultWatcher(this);
connect(srw, &AdvancedSymbology::SymbolResultWatcher::resultReady, this, [this, dataId, srw]()
{
if (srw->symbolResult())
{
m_participantDecorations[dataId] = QPixmap::fromImage(srw->symbolResult()->symbolImage().image());
emit signalParticipantChanged(dataId);
// update();
}
});
srw->setSymbolResult(dictionary.fetchSymbol(symDataToRender));
}
}
break;
}
}
emit signalParticipantNamesChanged();
emit signalParticipantChanged(dataId);
// emit dataChanged(index(0, rowCount() -1), index(0, columnCount() - 1));
}
} // namespace TargetManagement
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Handler for ParticipantData
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include <TargetManagement/logger.h>
// Get targets
#include <TargetManagement/tgt_dtc.h>
// Get Participants
#include <ParticipantManagement/ppm_dtc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsSession/lts_session.h>
namespace TargetManagement
{
// --------------------------------------------------------
// ParticipantHandler
// --------------------------------------------------------
class ParticipantHandler final : public QObject // public LtsWidgets::LtsAbstractTableModel<class T>
{
Q_OBJECT
// using BaseClass = LtsWidgets::LtsAbstractTableModel<T>;
using BaseClass = QObject;
public:
explicit ParticipantHandler(QObject *parent = nullptr);
bool init(const std::shared_ptr<TargetManagement::Interface::Dtc> &tgt_dtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc);
int getParticipantIdToTargetId(int participantId) const;
const QHash <int, QString> &getParticipantHierarchies() const { return m_participantHierarchies; }
QString getParticipantHierarchie(int participantId) const;
const QHash <int, QPixmap> &getParticipantDecorations() const { return m_participantDecorations; }
QPixmap getParticipantDecoration(int participantId) const { return m_participantDecorations.value(participantId); }
QHash <int, int> getParticipantIdToEquipmentNumber() const { return m_participantIdToEq; }
int getParticipantIdToEquipmentNumber(int participantId) const { return m_participantIdToEq.value(participantId, -1); }
ParticipantManagement::WmsTypeClass getParticipantIdToWmsTypeClass(int participantId) const
{ return m_participantIdToWmsTypeClass.value(participantId, ParticipantManagement::WmsTypeClass_def::None); }
static QString target_wmsTypeClassToString(const ParticipantManagement::WmsTypeClass &wmsTypeClass);
Q_SIGNALS:
void signalParticipantNamesChanged();
void signalParticipantChanged(int participantId);
private Q_SLOTS:
void onShootbackTargetChanged(const TargetManagement::ShootbackTarget &data,
const DataModification modType);
void onTypeChanged(const ParticipantManagement::Type &data,
const DataModification modType);
void onParticipantChanged(const ParticipantManagement::Participant &data,
DataModification modType);
private:
std::shared_ptr<TargetManagement::Interface::Dtc> m_tgt_dtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppm_dtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
QHash <int, int > m_participantIdToTargetId; // key = (target)participantId, value = id of target
QHash <int, QString> m_participantHierarchies; // key = participantId, value = HierarchyString
QHash <int, QPixmap> m_participantDecorations;
QHash <int, int > m_participantIdToEq; // key = participantId, value = EquipmentNumber
QHash <int, ParticipantManagement::TypeClass> m_typeToTypeClass; // key = ParticipantType, value = TypeClass
QHash <int, ParticipantManagement::WmsTypeClass> m_participantIdToWmsTypeClass; // key = participantId, value = WmsTypeClass
QIcon m_yes{QLatin1String("icon:yes.svg")};
QIcon m_no{QLatin1String("icon:no.svg")};
LOGGER_T m_logger;
};
} //namespace TargetManagement
@@ -0,0 +1,199 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_shootback_target_edit.h"
#include "tgt_target_part_model.h"
#include "ui_tgt_shootback_target_edit.h"
#include <LtsUtilsSettings/settings.h>
#include <QBuffer>
namespace TargetManagement
{
ShootbackTargetEdit::ShootbackTargetEdit(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ui(new Ui::ShootbackTargetEdit)
, m_logger(getLogger("ShootbackTargetEdit"))
{
m_ui->setupUi(this);
}
//-----------------------------------------------------------------------------
ShootbackTargetEdit::~ShootbackTargetEdit()
{
delete m_ui;
}
//-----------------------------------------------------------------------------
void ShootbackTargetEdit::retranslate()
{
translate(m_ui, m_target, tr("ShootbackTarget"));
}
bool ShootbackTargetEdit::init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
TargetParticipantModel *targetParticipantModel,
const TargetManagement::ShootbackTarget &target)
{
DEBUG_LOG(m_logger) << "ShootbackTargetEdit::init()";
if (!dtc || !ftc)
{
ERROR_LOG(m_logger) << "ShootbackTargetEdit::init() Invalid shared_ptr!";
return false;
}
m_dtc = dtc;
m_ftc = ftc;
m_targetParticipantModel = targetParticipantModel;
setData(target);
initCmbParticipants();
connect(m_targetParticipantModel, &TargetParticipantModel::signalParticipantNamesChanged,
this, &ShootbackTargetEdit::initCmbParticipants);
setOnlineHelpFilename(QStringLiteral("Situation-Targets"));
// if (m_target.id() <= 0)
// slotChangesMade();
return true;
}
void ShootbackTargetEdit::initCmbParticipants()
{
m_ui->cmbParticipants->clear();
if (!m_targetParticipantModel)
return;
QSignalBlocker sb(m_ui->cmbParticipants); // pause tooltip update
m_ui->cmbParticipants->addItem(QStringLiteral("-"), 0); // to remove association
const auto hierarchies(m_targetParticipantModel->getParticipantHierarchies());
const auto decorations(m_targetParticipantModel->getParticipantDecorations());
for (auto it = hierarchies.begin(); it != hierarchies.end(); ++it)
{
const int participantId = it.key();
const QString hierarchy(it.value());
if (!m_targetParticipantModel->getAssociatedParticipantIds().contains(participantId) || m_target.targetParticipantId() == participantId)
{
const QPixmap &pm = decorations.value(participantId);
m_ui->cmbParticipants->addItem(QIcon(pm), hierarchy, participantId);
// Tooltip:
int idx = m_ui->cmbParticipants->findData(participantId);
QString tooltip(QStringLiteral("<html>"));
// without a temporary file:
QByteArray baData;
QBuffer buffer(&baData);
pm.save(&buffer, "PNG", 100);
tooltip.append(QStringLiteral("<center><img src='data:image/png;base64,%1'></center>").arg(QString::fromLatin1(baData.toBase64()))); // how can i center the image?
#ifndef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
#endif
tooltip.append(QStringLiteral("<center>id=%1</center>").arg(participantId));
tooltip.append(QStringLiteral("</html>"));
m_ui->cmbParticipants->setItemData(idx, tooltip, Qt::ToolTipRole);
}
}
int newIdx = m_ui->cmbParticipants->findData(m_target.targetParticipantId());
if (newIdx >= 0)
m_ui->cmbParticipants->setCurrentIndex(newIdx);
m_ui->cmbParticipants->model()->sort(0);
m_ui->cmbParticipants->setIconSize(QSize(50, 50));
connect(m_ui->cmbParticipants, QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &ShootbackTargetEdit::onCmbParticipantsChanged, Qt::UniqueConnection);
onCmbParticipantsChanged();
}
//slots
void ShootbackTargetEdit::onCmbParticipantsChanged()
{
const auto decorations(m_targetParticipantModel->getParticipantDecorations());
int participantId = m_ui->cmbParticipants->currentData().toInt();
const auto it = decorations.find(participantId);
if (it != decorations.constEnd())
{
const QPixmap &pm = decorations.value(it.key());
{
QString tooltip(QStringLiteral("<html>"));
QByteArray data;
QBuffer buffer(&data);
// XML-Symbol with scale = 4 will produce huge images. Limit the size:
pm.save(&buffer, "PNG", 100);
tooltip += QStringLiteral("<center>");
tooltip += QStringLiteral("<img src='data:image/png;base64,%1'>").arg(QString::fromLatin1(data.toBase64()));
tooltip += QStringLiteral("</center>");
#ifndef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
#endif
tooltip.append(QStringLiteral("<center>id=%1</center>").arg(participantId));
tooltip += QStringLiteral("</html>");
m_ui->cmbParticipants->setToolTip(tooltip);
}
}
}
bool ShootbackTargetEdit::apply()
{
m_target.name(m_ui->leName->text().toStdString());
m_target.activateLaserDesignation(m_ui->cb_activateLaserDetection->isChecked());
m_target.activateLights(m_ui->cb_activateLights->isChecked());
m_target.activatePopupAutomatic(m_ui->cb_activatePopupAutomatic->isChecked());
m_target.permanentInstalledTarget(m_ui->cb_permanentInstalledTarget->isChecked());
m_target.hitsToKill(m_ui->sp_hitsToKill->value());
// selected participant:
int32_t participantId = m_ui->cmbParticipants->currentData().toInt();
m_target.targetParticipantId(participantId);
m_requestHelper->addRequest([this]()
{
return m_ftc->shootbackTargetModifyRequest(m_target, this);
});
return m_requestHelper->startRequests();
}
//private
void ShootbackTargetEdit::setData(const ShootbackTarget &target)
{
m_target = target;
m_ui->leName->setText(QString::fromStdString(m_target.name()));
m_ui->cb_activateLaserDetection->setChecked(m_target.activateLaserDesignation());
m_ui->cb_activateLights->setChecked(m_target.activateLights());
m_ui->cb_activatePopupAutomatic->setChecked(m_target.activatePopupAutomatic());
m_ui->cb_permanentInstalledTarget->setChecked(m_target.permanentInstalledTarget());
m_ui->sp_hitsToKill->setValue(m_target.hitsToKill());
// update combo box:
int newIdx = m_ui->cmbParticipants->findData(m_target.targetParticipantId());
if (newIdx >= 0)
m_ui->cmbParticipants->setCurrentIndex(newIdx);
}
}
@@ -0,0 +1,66 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <Services/TargetManagement/tgt_dtc.h>
#include <Services/TargetManagement/tgt_ftc.h>
#include <TargetManagement/logger.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace Ui
{
class ShootbackTargetEdit;
}
namespace TargetManagement
{
class TargetParticipantModel;
class ShootbackTargetEdit : public LtsWidgets::LtsDialog,
protected TargetManagement::Interface::Ftc::ShootbackTargetModifyReplyHandler
{
Q_OBJECT
public:
explicit ShootbackTargetEdit(QWidget *parent = nullptr);
~ShootbackTargetEdit();
bool init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
TargetParticipantModel *targetParticipantModel,
const ShootbackTarget &target = ShootbackTarget());
//virtual functions from TargetManagement::Interface::Ftc::..
void onShootbackTargetModifyReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
private Q_SLOTS:
void initCmbParticipants();
void onCmbParticipantsChanged();
private:
void setData(const ShootbackTarget &target);
bool apply() override;
void retranslate() override;
ShootbackTarget m_target;
TargetParticipantModel *m_targetParticipantModel{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
Ui::ShootbackTargetEdit *m_ui{nullptr};
LOGGER_T m_logger;
};
} //namespace TargetManagement
@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ShootbackTargetEdit</class>
<widget class="QWidget" name="ShootbackTargetEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>963</width>
<height>318</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="lbl_name">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="leName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_assoParticipant">
<property name="text">
<string>Participant:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cmbParticipants"/>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="cb_activateLaserDetection">
<property name="text">
<string>Activate laser detection</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="cb_permanentInstalledTarget">
<property name="text">
<string>Permanent installed target</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cb_activateLights">
<property name="text">
<string>activate lights</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lb_silhouette">
<property name="text">
<string>Silhouette:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cmb_silhouette"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="lb_silhouetteImage">
<property name="text">
<string>Silhouette-placeholder</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="4">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lb_hitsToKill">
<property name="text">
<string>Hits to kill:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="sp_hitsToKill"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lb_curState">
<property name="text">
<string>Current State:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lb_curState_2">
<property name="text">
<string>value</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cb_activatePopupAutomatic">
<property name="text">
<string>Activate popup automatic</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lb_curState_3">
<property name="text">
<string>Set state:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QRadioButton" name="rb_stateUp">
<property name="text">
<string>Up</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QRadioButton" name="rb_StateDown">
<property name="text">
<string>Down</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leName</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,692 @@
/**
* @RDE_HEADER@
* Target-Area-Assignment
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_target_area_assignment_dialog.h"
#include "ui_tgt_target_area_assignment_dialog.h"
#include "tgt_target_area_assignment_edit.h"
#include "tgt_telegrams.h"
#include <LtsSession/lts_session_data.h>
#include <FileManagement/flm_translation.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QMessageBox>
#include <QDebug>
namespace TargetManagement
{
AssignmentDialog::AssignmentDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_session(session)
, m_ui(new Ui::TargetAreaAssignmentsDialog)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("AssignmentDialog"))
{
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Situation-Assign/Configure_Targets"));
}
AssignmentDialog::~AssignmentDialog()
{
clearSelectionOfMapObjects();
delete m_ui;
}
bool AssignmentDialog::init(MODE mode, int idAccordingToMode)
{
m_mode = mode;
if (!m_session)
return false;
if (!m_session->getDtc<TargetManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<TargetManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
return false;
if (!m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc))
return false;
// initialize model:
INFO_LOG(m_logger) << "AssignmentDialog::init";
m_assignmentParticipantModel = new AssignmentParticipantModel(this);
m_assignmentParticipantModel->initModel(m_dtc, m_ppmDtc, m_ppmGuiCbxIfc, m_session);
// proxyModel:
m_assignmentParticipantProxyModel = new AssignmentParticipantProxyModel(this);
m_assignmentParticipantProxyModel->setSourceModel(m_assignmentParticipantModel);
m_assignmentParticipantProxyModel->setDynamicSortFilter(false);
// set view: (LtsDataView)
m_ui->widget->setModel(m_assignmentParticipantProxyModel);
// to allow remove off some rows at once. Anoying in all other cases -> stay at singleSelection
// m_ui->widget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
// connects for gui
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &AssignmentDialog::onSelectionChanged);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &AssignmentDialog::onEditAssignment);
connect(this, &AssignmentDialog::escapePressed, this,
&AssignmentDialog::onEscapePressed, Qt::UniqueConnection);
// Create Add-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &AssignmentDialog::onNewAssignment);
// Create Remove-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &AssignmentDialog::onRemoveAssignment);
// Create Modify-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &AssignmentDialog::onEditAssignment);
// connect signals of TableView/CustomView:
connect(m_ui->widget, &LtsDataView::LtsDataView::clicked, this, &AssignmentDialog::onTableViewClicked);
// it´s possible to evaluate signalEntered, but seems to be overkill here:
// connect(m_ui->widget, &LtsDataView::LtsDataView::signalEntered, this, &AssignmentDialog::onObjectEntered);
#ifndef LTS_DEBUG
m_ui->widget->hideColumn(AssignmentParticipantModel::Columns::Id);
m_ui->widget->hideColumn(AssignmentParticipantModel::Columns::TargetPartipantId);
#endif
// connect signals of model:
connect(m_assignmentParticipantModel, &AssignmentParticipantModel::signalEditableItemChanged,
this, [this]()
{
slotChangesMade();
// most likely the checkBox 'active' has changed. BackgroundRole has to be updated:
m_assignmentParticipantModel->update();
});
// Save/Load from Library Button
m_buttonBox->connectLibraryButton(this,
&AssignmentDialog::onImportButtonClicked,
&AssignmentDialog::onExportButtonClicked);
if (!m_flmGui)
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
// 'Map' Button(s)
m_buttonBox->connectButton(LtsWidgets::DialogButton::CenterMap, this, &AssignmentDialog::onMapCenterClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::ZoomMapTo, this, &AssignmentDialog::onMapZoomToClicked);
if (!m_sitMapGuiIfc)
{
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::CenterMap, false);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::ZoomMapTo, false);
}
// according mode: set filter; showHide columns; fill gap etc.
setMode(mode, idAccordingToMode);
// call eneDisa / onSelectionChanged once:
onSelectionChanged();
return true;
}
bool AssignmentDialog::setMode(AssignmentDialog::MODE mode, int idAccordingToMode)
{
if (!m_assignmentParticipantProxyModel)
return false;
// filter:
bool hideTargetColumns = false;
bool hideAreaColumns = false;
switch (mode)
{
case MODE::ALL:
m_assignmentParticipantProxyModel->filterToAreaId();
m_assignmentParticipantProxyModel->filterToTargetParticpantId();
break;
case MODE::FILTERED_TO_SINGLE_AREA:
m_assignmentParticipantProxyModel->filterToAreaId(idAccordingToMode);
hideAreaColumns = true;
break;
case MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT:
m_assignmentParticipantProxyModel->filterToTargetParticpantId(idAccordingToMode); // idAccordingToMode == targetParticipantId
hideTargetColumns = true;
break;
}
// targetColumns:
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::TargetId, hideTargetColumns);
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::TargetName, hideTargetColumns);
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::TargetPartipantId, hideTargetColumns);
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::TargetPartipantEquipmentNumber, hideTargetColumns);
// m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::Participant, hideTargetColumns);
// areaColumns:
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::AreaId, hideAreaColumns);
m_ui->widget->setColumnHidden(AssignmentParticipantModel::Columns::AreaName, hideAreaColumns);
// fill gaps (add missing entries in the model to show their checkboxes):
if (mode == MODE::FILTERED_TO_SINGLE_AREA)
m_assignmentParticipantModel->addGapFillerForArea(idAccordingToMode);
else if (mode == MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT)
m_assignmentParticipantModel->addGapFillerForTargetParticipantId(idAccordingToMode);
// visible
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Library, (mode == MODE::ALL));
return true;
}
void AssignmentDialog::retranslate()
{
if (m_assignmentParticipantProxyModel)
{
const int areadId = m_assignmentParticipantProxyModel->getFilterToAreaId();
if (areadId > 0)
{
translate(m_ui,
QString::fromStdString(m_dtc->shootbackArea(areadId).name()),
false,
tr("Targets assigned to"));
return;
}
QString name;
const int targetParticipantId = m_assignmentParticipantProxyModel->getFilterToTargetParticpantId();
if (targetParticipantId > 0)
{
const QMap<qint32, TargetManagement::ShootbackTarget> &shootbackTargets =
m_dtc->shootbackTargets();
for (const TargetManagement::ShootbackTarget &target : qAsConst(shootbackTargets))
{
if (target.targetParticipantId() == targetParticipantId)
{
name = QString::fromStdString(target.name());
break;
}
} // for
translate(m_ui,
name,
false,
tr("Areas assigned to"));
return;
}
}
// translate(m_ui, tr("Target-Area-Assignments"));
translate(m_ui, tr("Shootback Overview"));
}
void AssignmentDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
return BaseClass::keyPressEvent(event);
}
void AssignmentDialog::onNewAssignment()
{
INFO_LOG(m_logger) << "onNew";
AssignmentEditDialog *dialog = new AssignmentEditDialog(this);
if (!dialog->init(m_dtc, m_ftc, m_assignmentParticipantModel))
{
ERROR_LOG(m_logger) << QLatin1String("Can't initialize AssignmentEditDialog!");
delete dialog;
return;
}
connect(dialog, &AssignmentEditDialog::updateItem, this, &AssignmentDialog::onUpdateItem);
addDialog(dialog, m_menuGroup, QStringLiteral("Add Assignment"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
void AssignmentDialog::onRemoveAssignment()
{
const QModelIndexList &selectedRows = m_ui->widget->selectedRows();
for (const auto &mi : selectedRows)
{
Core::RemoveElementRequest req;
req.id(m_assignmentParticipantModel->getRowData(mi.row()).id());
m_requestHelper->addRequest([req, this]()
{
return m_ftc->targetAreaAssignmentRemoveRequest(req, this);
});
}
m_requestHelper->startRequests();
}
void AssignmentDialog::onEditAssignment()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
AssignmentEditDialog *dialog = new AssignmentEditDialog(this);
const TargetAreaAssignment &assignment = m_assignmentParticipantModel->getRowData(curIdx.row());
DEBUG_LOG(m_logger) << " onEditTargetArea, row = " << curIdx.row() << ", assignment.id() = " << assignment.id();
if (!dialog->init(m_dtc, m_ftc, m_assignmentParticipantModel, assignment))
{
ERROR_LOG(m_logger) << LOGFUNCTION << QLatin1String("Can't initialize ShootbackTarget!");
delete dialog;
return;
}
if (m_mode != MODE::ALL)
dialog->lockTargetParticipantAndArea(); // edit a certain assignment, changing target and/or areas is not allowed
connect(dialog, &AssignmentEditDialog::updateItem, this, &AssignmentDialog::onUpdateItem);
addDialog(dialog, m_menuGroup, QStringLiteral("Edit Target"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
void AssignmentDialog::onUpdateItem(const TargetAreaAssignment &assignment)
{
INFO_LOG(m_logger) << LOGFUNCTION << " got item to update, item=" << assignment;
if (assignment.id()>0)
{
//
// assignment.id>0 -> already persistent
//
QModelIndex mi = m_assignmentParticipantModel->findIndexForId(assignment.id());
int row = mi.row();
INFO_LOG(m_logger) << LOGFUNCTION << " got item to update, row=" << row;
if (row < 0)
{
abort();
// m_assignmentParticipantModel->insertRow(assignment);
// INFO_LOG(m_logger) << LOGFUNCTION << " CHANGED CHANGED CHANGED CHANGED CHANGED";
}
else
{
if (m_assignmentParticipantModel->getRowData(row) != assignment)
{
m_assignmentParticipantModel->setRowData(row, assignment);
INFO_LOG(m_logger) << LOGFUNCTION << " CHANGED CHANGED CHANGED CHANGED CHANGED, row = " << row;
slotChangesMade();
}
}
} else {
//
// assignment.id<0 -> new
//
int row = m_assignmentParticipantModel->findRowForAreaTargetParticipantId(assignment.areaId(), assignment.targetParticipantId());
INFO_LOG(m_logger) << LOGFUNCTION << " got item to update, row=" << row;
if (row < 0)
{
m_assignmentParticipantModel->insertRow(assignment);
INFO_LOG(m_logger) << LOGFUNCTION << " CHANGED CHANGED CHANGED CHANGED CHANGED";
}
else
{
if (m_assignmentParticipantModel->getRowData(row) != assignment)
{
m_assignmentParticipantModel->setRowData(row, assignment);
INFO_LOG(m_logger) << LOGFUNCTION << " CHANGED CHANGED CHANGED CHANGED CHANGED, row = " << row;
slotChangesMade();
}
}
}
}
QByteArray AssignmentDialog::toJson() const
{
QJsonObject obj;
// operatorId just for convenience:
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
obj[QStringLiteral("OperatorId")] = operatorId;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TGTShootbackAssignment); // ToDo
{
const QVector<TargetManagement::TargetAreaAssignment>& modelData = m_assignmentParticipantModel->getData();
QJsonArray jArray;
for (const TargetManagement::TargetAreaAssignment &taa : modelData)
{
TargetAreaAssignmentData taad;
taad.id = taa.id();
taad.name = QString::fromStdString(taa.name());
taad.areaId = taa.areaId();
taad.targetParticipantId = taa.targetParticipantId();
taad.isActive = taa.isActive();
// TargetAreaConfigurationData
taad.configuration.interval1 = taa.configuration().interval1();
taad.configuration.flash1 = taa.configuration().flash1();
taad.configuration.effect1 = taa.configuration().effect1();
taad.configuration.interval2 = taa.configuration().interval2();
taad.configuration.flash2 = taa.configuration().flash2();
taad.configuration.effect2 = taa.configuration().effect2();
jArray.append(taad.toJson());
}
obj[QStringLiteral("TargetAreaAssignment")] = jArray;
}
QJsonDocument doc(obj);
DEBUG_LOG(m_logger) << " json = " << doc.toJson();
return doc.toJson(QJsonDocument::Compact);
}
QVector<TargetManagement::TargetAreaAssignment> AssignmentDialog::fromJson(const QByteArray &content)
{
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
// operatorId just for convenience:
const int operatorId = obj[QStringLiteral("operatorId")].toInt();
Q_UNUSED(operatorId);
const QJsonArray &jArray = obj[QStringLiteral("TargetAreaAssignment")].toArray();
QVector<TargetManagement::TargetAreaAssignment> vecData;
vecData.reserve(jArray.size());
for (const auto &item : jArray)
{
const TargetAreaAssignmentData &taad = TargetAreaAssignmentData::fromJson(item.toObject());
TargetManagement::TargetAreaAssignment taa;
taa.id(taad.id);
taa.name(taad.name.toStdString());
taa.areaId(taad.areaId);
taa.targetParticipantId(taad.targetParticipantId);
taa.isActive(taad.isActive);
// TargetAreaConfigurationData
taa.configuration().interval1(taad.configuration.interval1);
taa.configuration().flash1(taad.configuration.flash1);
taa.configuration().effect1(taad.configuration.effect1);
taa.configuration().interval2(taad.configuration.interval2);
taa.configuration().flash2(taad.configuration.flash2);
taa.configuration().effect2(taad.configuration.effect2);
vecData.push_back(std::move(taa));
}
return vecData;
}
bool AssignmentDialog::apply()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " APPLY";
const QVector<TargetAreaAssignment> &assignments = m_assignmentParticipantModel->getData();
for (const TargetAreaAssignment &updateCandidate : qAsConst(assignments))
{
const int assignmentId = updateCandidate.id();
const TargetAreaAssignment &curAssignment = m_dtc->targetAreaAssignment(assignmentId);
if (updateCandidate.isActive() && isDefault(updateCandidate.configuration()))
{
// apply not allowed
ERROR_LOG(m_logger) << LOGFUNCTION << " APPLY NOT ALLOWED - Invalid configuration provided for at least one active assignment";
ERROR_LOG(m_logger) << LOGFUNCTION << " APPLY NOT ALLOWED - Invalid configuration provided for at least one active assignment";
ERROR_LOG(m_logger) << LOGFUNCTION << " updateCandidate " << updateCandidate;
QMessageBox::warning(this, tr("No configuration"),
tr("Invalid configuration provided for at least one active assignment.")
);
// maybe the selection covers the invalid row marked red (backgroundRole)
m_ui->widget->clearSelection();
return false;
}
// gapFiller -> call isEqual with ignoringAreaIdAndParticipantId==true
bool isGapFiller = (assignmentId <= 0);
if (!isEqual(curAssignment, updateCandidate, isGapFiller))
{
INFO_LOG(m_logger) << LOGFUNCTION << " add request for: assignmentId:" << assignmentId
<< " name: " << QString::fromStdString(updateCandidate.name());
m_requestHelper->addRequest([this, updateCandidate]()
{
return m_ftc->targetAreaAssignmentModifyRequest(updateCandidate, this);
});
}
}
if (m_requestHelper->hasRequests())
m_requestHelper->startRequests();
return true;
}
void AssignmentDialog::onEscapePressed()
{
m_ui->widget->clearSelection();
}
void AssignmentDialog::onExportButtonClicked()
{
QByteArray byteArray = toJson();
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
if (fileId > 0)
DEBUG_LOG(m_logger) << LOGFUNCTION << "Saved file with id = " << fileId;
else
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not save file in library ";
}
void AssignmentDialog::onImportButtonClicked()
{
INFO_LOG(m_logger) << LOGFUNCTION << "--- onImportButtonClicked() ";
QHash<LtsWidgets::Button, QString> buttonTexts;
buttonTexts.insert(LtsWidgets::Button::Ok, tr("Overwrite"));
buttonTexts.insert(LtsWidgets::Button::Cancel, tr("Cancel"));
LtsWidgets::LtsMessageDialogNew *dlg = new LtsWidgets::LtsMessageDialogNew(this,
tr("Overwrite existing data?"),
tr("Load from Library"),
LtsWidgets::Behaviour::Popup,
LtsWidgets::Button::Ok | LtsWidgets::Button::Cancel,
buttonTexts);
connect(dlg, &LtsWidgets::LtsMessageDialogNew::ok,
this, &AssignmentDialog::onImport);
}
void AssignmentDialog::onImport()
{
QByteArray content;
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml},
m_session->exerciseId(),
FileManagement::toString(FileManagement::XmlType::TGTShootbackAssignment));
if (fileId > 0)
{
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TGTShootbackAssignment)))
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Invalid xml file content"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes,
texts);
}
else
{
// update svc via clear and (re-)insert:
// 1) clear svc:
const QVector<TargetAreaAssignment> &curData = m_assignmentParticipantModel->getData();
for (auto item : curData)
{
Core::RemoveElementRequest req(item.id());
m_requestHelper->addRequest([this, req]()
{
return m_ftc->targetAreaAssignmentRemoveRequest(req, this);
});
}
// 2) re-insert:
const QVector<TargetManagement::TargetAreaAssignment> vecDataCandidate(fromJson(content));
for (TargetAreaAssignment assignment : vecDataCandidate)
{
assignment.id(0); // force create
m_requestHelper->addRequest([this, assignment]()
{
return m_ftc->targetAreaAssignmentModifyRequest(assignment, this);
});
}
// clear view *before* performing the requests:
m_assignmentParticipantModel->clear();
m_requestHelper->startRequests();
}
}
}
void AssignmentDialog::onMapCenterClicked()
{
if (!m_sitMapGuiIfc)
return;
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
if (m_mode == MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT)
{
const int areaId = m_assignmentParticipantModel->getRowData(curIdx.row()).areaId();
if (areaId<=0)
return;
m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, areaId);
} else {
const int pId = m_assignmentParticipantModel->getRowData(curIdx.row()).targetParticipantId();
if (pId<=0)
return;
m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_Participant, pId);
}
}
void AssignmentDialog::onMapZoomToClicked()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
QModelIndex index = selectedRows.first();
if (!index.isValid())
return;
if (!m_assignmentParticipantModel || !m_sitMapGuiIfc)
return;
const TargetAreaAssignment &assignment = m_assignmentParticipantModel->getRowData(index.row());
const int areaId = assignment.areaId();
const int pId = assignment.targetParticipantId();
if ((areaId<=0) || (pId<=0))
return;
m_sitMapGuiIfc->zoomMapTo({ {SituationMap::MapObjectType::MOT_Participant, pId}, {SituationMap::MapObjectType::MOT_ShootbackArea, areaId} });
}
void AssignmentDialog::onObjectEntered(const QModelIndex &index)
{
if (!m_sitMapGuiIfc)
return;
if (!index.isValid())
{
m_sitMapGuiIfc->removeObjectIndicator();
return;
}
const TargetAreaAssignment &assignment = m_assignmentParticipantModel->getRowData(index.row());
const int areaId = assignment.areaId();
const int pId = assignment.targetParticipantId();
if ((areaId<=0) || (pId<=0))
return;
if (m_mode == MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT)
{
// Assigned Area:
m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, areaId, true);
// Target/Participant
m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_Participant, {pId}, true);
} else {
// Target/Participant
m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_Participant, pId, true);
// Assigned Area:
m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_ShootbackArea, {areaId}, true);
}
}
void AssignmentDialog::onTableViewClicked(const QModelIndex &index)
{
if (!index.isValid())
return;
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
onMapCenterClicked();
}
void AssignmentDialog::clearSelectionOfMapObjects()
{
if (!m_sitMapGuiIfc)
return;
// remove MapObjectIndicator:
m_sitMapGuiIfc->removeObjectIndicator();
}
void AssignmentDialog::onSelectionChanged()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
const int cntSelectedRows = selectedRows.size();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, cntSelectedRows >= 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::CenterMap, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::ZoomMapTo, cntSelectedRows == 1);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, m_mode == MODE::ALL);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Remove, m_mode == MODE::ALL);
if (selectedRows.isEmpty())
onObjectEntered({}); // use invalid Idx to removeObjectIndicator
else
onObjectEntered(selectedRows.first());
}
//-----------------------------------------------------------------------------
} // namespace TargetManagement
@@ -0,0 +1,112 @@
/**
* @RDE_HEADER@
* Target-Area-Assignment
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/tgt_ftc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <TargetManagement/logger.h>
#include <Plugins/TargetManagement/Gui/ShootbackTargetConfiguration/tgt_assignment_part_model.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
namespace Ui
{
class TargetAreaAssignmentsDialog;
}
namespace TargetManagement
{
class AssignmentDialog final : public LtsWidgets::LtsDialog
, protected TargetManagement::Interface::Ftc::TargetAreaAssignmentModifyReplyHandler
, protected TargetManagement::Interface::Ftc::TargetAreaAssignmentRemoveReplyHandler
{
Q_OBJECT
public:
using BaseClass = LtsWidgets::LtsDialog;
enum class MODE
{
ALL,
FILTERED_TO_SINGLE_AREA,
FILTERED_TO_SINGLE_TARGET_PARTICPANT
};
explicit AssignmentDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~AssignmentDialog();
bool init(MODE mode = MODE::ALL, int idAccordingToMode = -1);
Q_SIGNALS:
void escapePressed();
protected:
bool setMode(MODE mode, int idAccordingToMode = -1);
void retranslate() override;
protected:
void keyPressEvent(QKeyEvent *event) override final;
void onTargetAreaAssignmentModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onTargetAreaAssignmentRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
QByteArray toJson() const;
QVector<TargetAreaAssignment> fromJson(const QByteArray &content);
private Q_SLOTS:
bool apply() override;
void onEscapePressed();
void onSelectionChanged();
void onNewAssignment();
void onRemoveAssignment();
void onEditAssignment();
void onUpdateItem(const TargetAreaAssignment &assignment);
void onExportButtonClicked();
void onImportButtonClicked();
void onImport();
void onMapCenterClicked();
void onMapZoomToClicked();
void onObjectEntered(const QModelIndex &index);
void onTableViewClicked(const QModelIndex &index);
void clearSelectionOfMapObjects();
private:
MODE m_mode{MODE::ALL};
AssignmentParticipantModel *m_assignmentParticipantModel{nullptr};
AssignmentParticipantProxyModel *m_assignmentParticipantProxyModel{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
LtsSession::LtsSession *m_session{nullptr};
Ui::TargetAreaAssignmentsDialog *m_ui{nullptr};
QString m_menuGroup;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LOGGER_T m_logger;
};
} // namespace TargetManagement
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TargetAreaAssignmentsDialog</class>
<widget class="QWidget" name="TargetAreaAssignmentsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">AlarmView</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,294 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_target_area_assignment_edit.h"
#include "tgt_assignment_part_model.h"
#include "ui_tgt_target_area_assignment_edit.h"
//#include <TargetManagement/ppm_translation.h>
#include <LtsUtilsSettings/settings.h>
#include <QBuffer>
namespace TargetManagement
{
AssignmentEditDialog::AssignmentEditDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ui(new Ui::AssignmentEdit)
, m_logger(getLogger("AssignmentEditDialog"))
{
m_ui->setupUi(this);
}
//-----------------------------------------------------------------------------
AssignmentEditDialog::~AssignmentEditDialog()
{
delete m_ui;
}
//-----------------------------------------------------------------------------
void AssignmentEditDialog::retranslate()
{
translate(m_ui, m_assignment, tr("ShootbackAreaAssignment"));
}
bool AssignmentEditDialog::init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
AssignmentParticipantModel *assignmentParticipantModel,
const TargetManagement::TargetAreaAssignment &assignment)
{
DEBUG_LOG(m_logger) << "AssignmentEditDialog::init(), assignment=" << assignment;
if (!dtc || !ftc)
{
ERROR_LOG(m_logger) << "AssignmentEditDialog::init() Invalid shared_ptr!";
return false;
}
m_dtc = dtc;
m_ftc = ftc;
m_assignmentParticipantModel = assignmentParticipantModel;
initCmbParticipants();
connect(m_assignmentParticipantModel, &AssignmentParticipantModel::signalParticipantNamesChanged,
this, &AssignmentEditDialog::initCmbParticipants);
initCmbAreas();
// configuration
initCmbPreWarningEffect();
initCmbTimeToEffectEffect();
//HACK as close is not allowed directly
// connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &ParticipantEditItem::close);
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Apply), &QPushButton::clicked, this, &AssignmentEditDialog::readyToClose);
// comboBoxes are filled, set data now
setData(assignment);
setOnlineHelpFilename(QStringLiteral("Situation-Targets"));
// if (m_assignment.id() <= 0)
// slotChangesMade();
return true;
}
void AssignmentEditDialog::lockTargetParticipantAndArea()
{
m_ui->cmbParticipants->setEnabled(false);
m_ui->cmbAreas->setEnabled(false);
}
void AssignmentEditDialog::initCmbParticipants()
{
m_ui->cmbParticipants->clear();
if (!m_assignmentParticipantModel)
return;
QSignalBlocker sb(m_ui->cmbParticipants); // pause tooltip update
m_ui->cmbParticipants->addItem(QStringLiteral("-"), 0); // to remove association
const auto hierarchies(m_assignmentParticipantModel->getParticipantHierarchies());
const auto decorations(m_assignmentParticipantModel->getParticipantDecorations());
for (auto it = hierarchies.begin(); it != hierarchies.end(); ++it)
{
const int participantId = it.key();
const QString hierarchy(it.value());
// for Editing it´s neseccary to have all items in the comboBox:
// if (!m_assignmentParticipantModel->getAssociatedParticipantIds().contains(participantId) || m_assignment.targetParticipantId() == participantId)
{
const QPixmap &pm = decorations.value(participantId);
m_ui->cmbParticipants->addItem(QIcon(pm), hierarchy, participantId);
// Tooltip:
int idx = m_ui->cmbParticipants->findData(participantId);
QString tooltip(QStringLiteral("<html>"));
// without a temporary file:
QByteArray baData;
QBuffer buffer(&baData);
pm.save(&buffer, "PNG", 100);
tooltip.append(QStringLiteral("<center><img src='data:image/png;base64,%1'></center>").arg(QString::fromLatin1(baData.toBase64()))); // how can i center the image?
#ifndef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
#endif
tooltip.append(QStringLiteral("<center>id=%1</center>").arg(participantId));
tooltip.append(QStringLiteral("</html>"));
m_ui->cmbParticipants->setItemData(idx, tooltip, Qt::ToolTipRole);
}
}
int newIdx = m_ui->cmbParticipants->findData(m_assignment.targetParticipantId());
if (newIdx >= 0)
m_ui->cmbParticipants->setCurrentIndex(newIdx);
m_ui->cmbParticipants->model()->sort(0);
m_ui->cmbParticipants->setIconSize(QSize(50, 50));
connect(m_ui->cmbParticipants, QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &AssignmentEditDialog::onCmbParticipantsChanged, Qt::UniqueConnection);
onCmbParticipantsChanged();
}
void AssignmentEditDialog::fillCmbEffect(QComboBox *cmb)
{
if (!cmb)
return;
cmb->addItem(tr("Near Miss"), TargetManagement::Effect_def::NearMiss);
cmb->addItem(tr("Mobility Kill"), TargetManagement::Effect_def::MobilityKill);
cmb->addItem(tr("WeaponK ill"), TargetManagement::Effect_def::WeaponKill);
cmb->setCurrentIndex(0);
}
void AssignmentEditDialog::initCmbPreWarningEffect()
{
QComboBox *cmb = m_ui->cmb_preWarningEffect;
fillCmbEffect(cmb);
int newIdx = cmb->findData(m_assignment.configuration().effect1().underlying());
if (newIdx >= 0)
cmb->setCurrentIndex(newIdx);
}
void AssignmentEditDialog::initCmbTimeToEffectEffect()
{
QComboBox *cmb = m_ui->cmb_timeToEffectEffect;
fillCmbEffect(cmb);
int newIdx = cmb->findData(m_assignment.configuration().effect2().underlying());
if (newIdx >= 0)
cmb->setCurrentIndex(newIdx);
}
void AssignmentEditDialog::initCmbAreas()
{
m_ui->cmbAreas->clear();
auto cb = [this](const TargetManagement::ShootbackArea & area)
{
m_ui->cmbAreas->addItem(QString::fromStdString(area.name()), area.id());
};
m_dtc->shootbackAreas(cb);
}
//slots
void AssignmentEditDialog::onCmbParticipantsChanged()
{
const auto decorations(m_assignmentParticipantModel->getParticipantDecorations());
int participantId = m_ui->cmbParticipants->currentData().toInt();
const auto it = decorations.find(participantId);
if (it != decorations.constEnd())
{
const QPixmap &pm = decorations.value(it.key());
{
QString tooltip(QStringLiteral("<html>"));
QByteArray data;
QBuffer buffer(&data);
// XML-Symbol with scale = 4 will produce huge images. Limit the size:
pm.save(&buffer, "PNG", 100);
tooltip += QStringLiteral("<center>");
tooltip += QStringLiteral("<img src='data:image/png;base64,%1'>").arg(QString::fromLatin1(data.toBase64()));
tooltip += QStringLiteral("</center>");
#ifndef LTS_DEBUG
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
#endif
tooltip.append(QStringLiteral("<center>id=%1</center>").arg(participantId));
tooltip += QStringLiteral("</html>");
m_ui->cmbParticipants->setToolTip(tooltip);
}
}
}
bool AssignmentEditDialog::apply()
{
// name:
m_assignment.name(m_ui->leName->text().toStdString());
// selected participant:
int32_t participantId = m_ui->cmbParticipants->currentData().toInt();
m_assignment.targetParticipantId(participantId);
// selected area:
m_assignment.areaId(m_ui->cmbAreas->currentData().toInt());
// configuration:
{
ShootbackConfiguration &configRef = m_assignment.configuration();
configRef.interval1(m_ui->sb_preWarningInterval->value());
configRef.effect1( static_cast<Effect::inner_enum>(m_ui->cmb_preWarningEffect->currentData().toInt()) );
configRef.flash1(m_ui->cb_flashAfterExpiration_1->isChecked());
configRef.interval2(m_ui->sb_timeToEffectInterval->value());
configRef.effect2( static_cast<Effect::inner_enum>(m_ui->cmb_timeToEffectEffect->currentData().toInt()) );
configRef.flash2(m_ui->cb_flashAfterExpiration_2->isChecked());
}
emit updateItem(m_assignment);
emit readyToClose();
return true;
}
//private
void AssignmentEditDialog::setData(const TargetAreaAssignment &assignment)
{
m_assignment = assignment;
m_ui->leName->setText(QString::fromStdString(assignment.name()));
// update combo box:
{
int newIdx = m_ui->cmbParticipants->findData(m_assignment.targetParticipantId());
if (newIdx >= 0)
m_ui->cmbParticipants->setCurrentIndex(newIdx);
}
// update combo box:
{
int newIdx = m_ui->cmbAreas->findData(m_assignment.areaId());
if (newIdx >= 0)
m_ui->cmbAreas->setCurrentIndex(newIdx);
}
// Shootback-/Behaviour-configuration
const ShootbackConfiguration &config = assignment.configuration();
{
m_ui->sb_preWarningInterval->setValue(config.interval1());
m_ui->cb_flashAfterExpiration_1->setChecked(config.flash1());
int newIdx = m_ui->cmb_preWarningEffect->findData(config.effect1().underlying());
if (newIdx >= 0)
m_ui->cmb_preWarningEffect->setCurrentIndex(newIdx);
}
{
m_ui->sb_timeToEffectInterval->setValue(config.interval2());
m_ui->cb_flashAfterExpiration_2->setChecked(config.flash1());
int newIdx = m_ui->cmb_timeToEffectEffect->findData(config.effect2().underlying());
if (newIdx >= 0)
m_ui->cmb_timeToEffectEffect->setCurrentIndex(newIdx);
}
}
}
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* TargetManagement - Target Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <Services/TargetManagement/tgt_dtc.h>
#include <Services/TargetManagement/tgt_ftc.h>
#include <TargetManagement/logger.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace Ui
{
class AssignmentEdit;
}
namespace TargetManagement
{
class AssignmentParticipantModel;
class AssignmentEditDialog : public LtsWidgets::LtsDialog,
protected TargetManagement::Interface::Ftc::TargetAreaAssignmentModifyReplyHandler
{
Q_OBJECT
public:
explicit AssignmentEditDialog(QWidget *parent = nullptr);
~AssignmentEditDialog();
bool init(const std::shared_ptr<TargetManagement::Interface::Dtc> &dtc,
const std::shared_ptr<TargetManagement::Interface::Ftc> &ftc,
AssignmentParticipantModel *assignmentParticipantModel,
const TargetAreaAssignment &assignment = TargetAreaAssignment());
void lockTargetParticipantAndArea();
//virtual functions from TargetManagement::Interface::Ftc::..
void onTargetAreaAssignmentModifyReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
Q_SIGNALS:
void readyToClose();
// void addItem(const QModelIndex &parent, const ParticipantData &newData);
void updateItem(const TargetAreaAssignment &assignment);
public Q_SLOTS:
void initCmbParticipants();
void initCmbPreWarningEffect();
void initCmbTimeToEffectEffect();
void initCmbAreas();
private Q_SLOTS:
void onCmbParticipantsChanged();
private:
void fillCmbEffect(QComboBox *cmb);
void setData(const TargetAreaAssignment &assignment);
bool apply() override;
void retranslate() override;
TargetAreaAssignment m_assignment;
AssignmentParticipantModel *m_assignmentParticipantModel{nullptr};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
Ui::AssignmentEdit *m_ui{nullptr};
LOGGER_T m_logger;
};
} //namespace TargetManagement
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssignmentEdit</class>
<widget class="QWidget" name="AssignmentEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>963</width>
<height>318</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<widget class="QLabel" name="label_assoArea">
<property name="text">
<string>Area</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_assoParticipant">
<property name="text">
<string>Target/Participant:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="leName"/>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lbl_name">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="LtsWidgets::LtsComboBox" name="cmbAreas"/>
</item>
<item row="1" column="2">
<widget class="LtsWidgets::LtsComboBox" name="cmbParticipants"/>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>221</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3" rowspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="4" rowspan="3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lb_preWarningInterval">
<property name="text">
<string>Pre-Warning Interval [sec]:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="sb_preWarningInterval"/>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="cb_flashAfterExpiration_1">
<property name="text">
<string>Flash after expiration</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lb_preWarningEffect">
<property name="text">
<string>Pre-Warning Effekt:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cmb_preWarningEffect"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lb_timeToEffectInterval">
<property name="text">
<string>Time-To-Effect Interval [sec]:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="sb_timeToEffectInterval"/>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="cb_flashAfterExpiration_2">
<property name="text">
<string>Flash after expiration</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lb_timeToEffectEffect">
<property name="text">
<string>Time-to-Effect Effect:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cmb_timeToEffectEffect"/>
</item>
</layout>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leName</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,188 @@
/**
* @RDE_HEADER@
* Gui Plugin for TargetManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#include "tgt_target_gui_plugin.h"
#include "tgt_target_part_dialog.h"
#include "tgt_target_area_assignment_dialog.h"
#include "tgt_area_dialog.h"
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_base_layout_widget.h>
//#include <Services/ParticipantManagement/ppm_operator_rights.h>
namespace TargetManagement
{
const char s_targetAreaAssignmentIdentifier[] = "tgtAssignments";
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Tgt.Target"))
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<TargetManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<TargetManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
return false;
if (!m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc))
return false;
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
m_ftc = nullptr;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Participants / Targets");
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
//
// "TargetBaseConfiguration"
//
plData.menuText = tr("Assign/Configure Targets"); // BaseConfiguration like ActivateLaserDesignation...
plData.identifier = QLatin1String("tgtTargetBaseConfiguration");
plData.menuIcon = QIcon(QLatin1String("icon:target.svg"));
// plData.operatorRight = OperatorRights::PartyEdit::PartiesShow;
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowTargetBaseConfiguration(parent);
};
ret.append(plData);
if (m_session->app() == LtsAppDescriptor::App::Shootback)
{
//
// "ShootbackApp"
//
plData.menuText = tr("Configure Shootback");
plData.identifier = QLatin1String("tgtAssignConfigureTarget");
plData.menuIcon = QIcon(QLatin1String("icon:party_edit.svg"));
// plData.operatorRight = OperatorRights::PartyEdit::PartiesShow;
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowTargets(parent);
};
ret.append(plData);
plData.menuText = tr("Shootback Overview"); //areaId
plData.identifier = QLatin1String(s_targetAreaAssignmentIdentifier);
plData.menuIcon = QIcon(QLatin1String("icon:party_edit.svg"));
// plData.operatorRight = OperatorRights::PartyEdit::PartiesShow;
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowTargetAreaAssignment(parent);
};
ret.append(plData);
plData.menuText = tr("Configure Areas");
plData.identifier = QLatin1String("tgtAreas");
plData.menuIcon = QIcon(QLatin1String("icon:party_edit.svg"));
// plData.operatorRight = OperatorRights::PartyEdit::PartiesShow;
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowAreas(parent);
};
ret.append(plData);
} // if (m_session->app() == LtsAppDescriptor::App::Shootback)
return ret;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowTargetBaseConfiguration(QWidget *parent)
{
TargetPartDialog *dlg = new TargetPartDialog(menuGroup(), m_session, parent);
if (!dlg->init(TargetPartDialog::MODE::TARGET_BASE_CONFIGURATION))
{
dlg->deleteLater();
return nullptr;
}
const QString identifier(QStringLiteral("tgtTargetBaseConfigurationXX"));
if (!m_session->addWidget(dlg, menuGroup(), identifier, LtsWidgets::LayoutArea::eDialogTab))
dlg->deleteLater();
return dlg;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowTargets(QWidget *parent)
{
TargetPartDialog *dlg = new TargetPartDialog(menuGroup(), m_session, parent);
if (!dlg->init(TargetPartDialog::MODE::TARGET_OVERVIEW))
{
dlg->deleteLater();
return nullptr;
}
const QString identifier(QStringLiteral("tgtAssignConfigureTargetXX"));
if (!m_session->addWidget(dlg, menuGroup(), identifier, LtsWidgets::LayoutArea::eDialogTab))
dlg->deleteLater();
return dlg;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowTargetAreaAssignment(QWidget *parent)
{
// init with parameter
m_targetAreaAssignmentDialog = LtsWidgets::initDialog(new AssignmentDialog(menuGroup(), m_session, parent));
return m_targetAreaAssignmentDialog;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowAreas(QWidget *parent)
{
// init without parameter
return LtsWidgets::initDialog(new AreaDialog(menuGroup(), m_session, parent));
}
} // namespace TargetManagement
@@ -0,0 +1,83 @@
/**
* @RDE_HEADER@
* Gui Plugin for TargetManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-05-29
*/
#pragma once
#include <TargetManagement/logger.h>
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/tgt_ftc.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_target_gui_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
namespace TargetManagement
{
// forward:
class AssignmentDialog;
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:tgt.shootbacktarget")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("TargetManagement.GuiPlugin.ShootbackTarget"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QVector<LtsWidgets::PluginData> getActions() override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Exercise;
}
private:
LtsWidgets::LtsDialog *onShowTargetBaseConfiguration(QWidget *parent);
LtsWidgets::LtsDialog *onShowTargets(QWidget *parent);
LtsWidgets::LtsDialog *onShowTargetAreaAssignment(QWidget *parent);
LtsWidgets::LtsDialog *onShowAreas(QWidget *parent);
QPointer<AssignmentDialog> m_targetAreaAssignmentDialog;
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
};
} // namespace TargetManagement
@@ -0,0 +1,557 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_target_part_dialog.h"
#include "ui_tgt_target_part_dialog.h"
#include "tgt_shootback_target_edit.h"
#include "tgt_telegrams.h"
#include <LtsSession/lts_session_data.h>
#include <FileManagement/flm_translation.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include "tgt_target_area_assignment_dialog.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QDebug>
namespace TargetManagement
{
TargetPartDialog::TargetPartDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_session(session)
, m_ui(new Ui::TargetPartDialog)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("TargetPartDialog"))
{
m_ui->setupUi(this);
setOnlineHelpFilename(QStringLiteral("Situation-Assign/Configure_Targets"));
}
TargetPartDialog::~TargetPartDialog()
{
clearSelectionOfMapObjects();
delete m_ui;
}
bool TargetPartDialog::init(TargetManagement::TargetPartDialog::MODE mode)
{
if (!m_session)
return false;
if (!m_session->getDtc<TargetManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<TargetManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
return false;
if (!m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc))
return false;
// initialize model:
INFO_LOG(m_logger) << "TargetPartDialog::init";
m_targetParticipantModel = new TargetParticipantModel(this);
m_targetParticipantModel->initModel(m_dtc, m_ppmDtc, m_ppmGuiCbxIfc, m_session);
// proxyModel:
auto proxyModel = new TargetParticipantProxyModel(this);
proxyModel->setSourceModel(m_targetParticipantModel);
proxyModel->setDynamicSortFilter(false);
// set view: (LtsDataView)
m_ui->widget->setModel(m_targetParticipantModel);
// to allow remove off some rows at once. Anoying in all other cases -> stay at singleSelection
// m_ui->widget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
m_assignAreaBtn = m_buttonBox->getButton(LtsWidgets::DialogButton::Import);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &TargetPartDialog::onAssignAreaClicked);
// connects for gui
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &TargetPartDialog::onSelectionChanged);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &TargetPartDialog::onEditTargetPart);
connect(this, &TargetPartDialog::escapePressed, this,
&TargetPartDialog::onEscapePressed, Qt::UniqueConnection);
// Create Add-Button
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, true);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &TargetPartDialog::onNewTargetPart);
// Create Remove-Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &TargetPartDialog::onRemoveTargetPart);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
// Create Modify-Button
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &TargetPartDialog::onEditTargetPart);
// connect signals of TableView/CustomView:
connect(m_ui->widget, &LtsDataView::LtsDataView::clicked, this, &TargetPartDialog::onTableViewClicked);
// it´s possible to evaluate signalEntered, but seems to be overkill here:
// connect(m_ui->widget, &LtsDataView::LtsDataView::signalEntered, this, &TargetPartDialog::onObjectEntered);
#ifndef LTS_DEBUG
m_ui->widget->hideColumn(TargetParticipantModel::Columns::Id);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::TargetPartipantId);
#endif
// Save/Load from Library Button
m_buttonBox->connectLibraryButton(this,
&TargetPartDialog::onImportButtonClicked,
&TargetPartDialog::onExportButtonClicked);
if (!m_flmGui)
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
// 'Map' Button(s)
m_buttonBox->connectButton(LtsWidgets::DialogButton::CenterMap, this, &TargetPartDialog::onMapCenterClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::ZoomMapTo, this, &TargetPartDialog::onMapZoomToClicked);
// call eneDisa / onSelectionChanged once:
onSelectionChanged();
setMode(mode);
return true;
}
void TargetPartDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
return BaseClass::keyPressEvent(event);
}
void TargetPartDialog::setMode(TargetPartDialog::MODE mode)
{
m_mode = mode;
switch (m_mode)
{
case MODE::TARGET_BASE_CONFIGURATION:
m_assignAreaBtn->setVisible(false);
break;
case MODE::TARGET_OVERVIEW:
m_assignAreaBtn->setVisible(true);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::TargetPartipantId);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivateLaserDesignation);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivateLights);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivatePopupAutomatic);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::HitsToKill);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::PermanentInstalledTarget);
m_ui->widget->hideColumn(TargetParticipantModel::Columns::VisibleParticipants);
break;
} // switch
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, (m_mode == MODE::TARGET_BASE_CONFIGURATION));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Edit, (m_mode == MODE::TARGET_BASE_CONFIGURATION));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Remove, (m_mode == MODE::TARGET_BASE_CONFIGURATION));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Library, (m_mode == MODE::TARGET_BASE_CONFIGURATION));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::CenterMap, m_sitMapGuiIfc && (m_mode == MODE::TARGET_BASE_CONFIGURATION));
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::ZoomMapTo, m_sitMapGuiIfc && (m_mode == MODE::TARGET_BASE_CONFIGURATION));
}
void TargetPartDialog::retranslate()
{
switch (m_mode)
{
case MODE::TARGET_BASE_CONFIGURATION:
translate(m_ui, tr("Assign/Configure Targets"));
m_assignAreaBtn->setText(tr("Assign Area"));
break;
case MODE::TARGET_OVERVIEW:
translate(m_ui, tr("Configure Shootback"));
m_assignAreaBtn->setText(tr("Assign Area"));
break;
}
}
void TargetPartDialog::onNewTargetPart()
{
INFO_LOG(m_logger) << "onNewTargetPart";
ShootbackTargetEdit *dialog = new ShootbackTargetEdit(this);
if (!dialog->init(m_dtc, m_ftc, m_targetParticipantModel))
{
ERROR_LOG(m_logger) << QLatin1String("Can't initialize shootbackTargetEdit!");
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("Add Target"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
void TargetPartDialog::onRemoveTargetPart()
{
const QModelIndexList &selectedRows = m_ui->widget->selectedRows();
for (const auto &mi : selectedRows)
{
Core::RemoveElementRequest req;
req.id(m_targetParticipantModel->getRowData(mi.row()).id());
m_requestHelper->addRequest([req, this]()
{
return m_ftc->shootbackTargetRemoveRequest(req, this);
});
}
m_requestHelper->startRequests();
}
void TargetPartDialog::onEditTargetPart()
{
if (m_mode == MODE::TARGET_OVERVIEW)
return;
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
INFO_LOG(m_logger) << " onEditTargetPart";
ShootbackTargetEdit *dialog = new ShootbackTargetEdit(this);
const TargetManagement::ShootbackTarget &tgt = m_targetParticipantModel->getRowData(curIdx.row());
if (!dialog->init(m_dtc, m_ftc, m_targetParticipantModel, tgt))
{
ERROR_LOG(m_logger) << LOGFUNCTION << QLatin1String("Can't initialize shootbackTargetEdit!");
delete dialog;
return;
}
addDialog(dialog, m_menuGroup, QStringLiteral("Edit Target"), LtsWidgets::LayoutArea::eDialogTab, true, true);
}
QByteArray TargetPartDialog::toJson() const
{
QJsonObject obj;
// operatorId just for convenience:
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
obj[QStringLiteral("OperatorId")] = operatorId;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration);
{
const QVector<TargetManagement::ShootbackTarget> &modelData = m_targetParticipantModel->getData();
QJsonArray jArray;
for (const TargetManagement::ShootbackTarget &sbt : modelData)
{
ShootbackTargetData sbtd;
sbtd.id = sbt.id();
sbtd.name = QString::fromStdString(sbt.name());
sbtd.targetParticipantEquipmentNumber = -1;
if (m_ppmDtc)
{
const ParticipantManagement::Participant &participant = m_ppmDtc->participant(sbt.targetParticipantId());
if (participant.id() == sbt.targetParticipantId() &&
participant.equipmentNumber().is_set())
sbtd.targetParticipantEquipmentNumber = participant.equipmentNumber().get();
}
sbtd.activateLaserDesignation = sbt.activateLaserDesignation();
sbtd.activateLights = sbt.activateLights();
sbtd.activatePopupAutomatic = sbt.activatePopupAutomatic();
sbtd.hitsToKill = sbt.hitsToKill();
sbtd.permanentInstalledTarget = sbt.permanentInstalledTarget();
// volatile data: position, visibleParticipants -> do not save -> skip
jArray.append(sbtd.toJson());
}
obj[QStringLiteral("ShootbackTargets")] = jArray;
}
QJsonDocument doc(obj);
DEBUG_LOG(m_logger) << " json = " << doc.toJson();
return doc.toJson(QJsonDocument::Compact);
}
QVector<TargetManagement::ShootbackTarget> TargetPartDialog::fromJson(const QByteArray &content)
{
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
// operatorId just for convenience:
const int operatorId = obj[QStringLiteral("operatorId")].toInt();
Q_UNUSED(operatorId);
const QJsonArray &jArray = obj[QStringLiteral("ShootbackTargets")].toArray();
QVector<TargetManagement::ShootbackTarget> vecData;
vecData.reserve(jArray.size());
for (const auto &item : jArray)
{
const ShootbackTargetData &sbtd = ShootbackTargetData::fromJson(item.toObject());
TargetManagement::ShootbackTarget sbt;
sbt.id(sbtd.id);
sbt.name(sbtd.name.toStdString());
if (m_ppmDtc)
sbt.targetParticipantId(m_ppmDtc->participantIdByEquipmentNumber(sbtd.targetParticipantEquipmentNumber));
sbt.activateLaserDesignation(sbtd.activateLaserDesignation);
sbt.activateLights(sbtd.activateLights);
sbt.activatePopupAutomatic(sbtd.activatePopupAutomatic);
sbt.hitsToKill(sbtd.hitsToKill);
sbt.permanentInstalledTarget(sbtd.permanentInstalledTarget);
vecData.push_back(std::move(sbt));
}
return vecData;
}
void TargetPartDialog::onEscapePressed()
{
m_ui->widget->clearSelection();
}
void TargetPartDialog::onExportButtonClicked()
{
QByteArray byteArray = toJson();
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
if (fileId > 0)
DEBUG_LOG(m_logger) << LOGFUNCTION << "Saved file with id = " << fileId;
else
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not save file in library ";
}
void TargetPartDialog::onImportButtonClicked()
{
QHash<LtsWidgets::Button, QString> buttonTexts;
buttonTexts.insert(LtsWidgets::Button::Ok, tr("Overwrite"));
buttonTexts.insert(LtsWidgets::Button::Cancel, tr("Cancel"));
LtsWidgets::LtsMessageDialogNew *dlg = new LtsWidgets::LtsMessageDialogNew(this,
tr("Overwrite existing data?"),
tr("Load from Library"),
LtsWidgets::Behaviour::Popup,
LtsWidgets::Button::Ok | LtsWidgets::Button::Cancel,
buttonTexts);
connect(dlg, &LtsWidgets::LtsMessageDialogNew::ok,
this, &TargetPartDialog::onImport);
}
void TargetPartDialog::onImport()
{
INFO_LOG(m_logger) << LOGFUNCTION << "--- onImportButtonClicked() ";
QByteArray content;
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml},
m_session->exerciseId(),
FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration));
if (fileId > 0)
{
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration)))
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Invalid xml file content"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes,
texts);
}
else
{
// update svc via clear and (re-)insert:
// 1) clear svc:
const QVector<ShootbackTarget> &curData = m_targetParticipantModel->getData();
for (auto item : curData)
{
Core::RemoveElementRequest req(item.id());
m_requestHelper->addRequest([this, req]()
{
return m_ftc->shootbackTargetRemoveRequest(req, this);
});
}
// 2) re-insert:
const QVector<TargetManagement::ShootbackTarget> vecDataCandidate(fromJson(content));
for (ShootbackTarget shootbackTargetCandidate : vecDataCandidate)
{
shootbackTargetCandidate.id(0); // force create
m_requestHelper->addRequest([this, shootbackTargetCandidate]()
{
return m_ftc->shootbackTargetModifyRequest(shootbackTargetCandidate, this);
});
}
// clear view *before* performing the requests:
m_targetParticipantModel->clear();
m_requestHelper->startRequests();
}
}
}
void TargetPartDialog::onAssignAreaClicked()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
const int targetParticipantId = m_targetParticipantModel->getRowData(curIdx.row()).targetParticipantId();
// instead of emit a signal, create the according dialog frome here directly
//emit assignAreasRequested(targetParticipantId);
auto dlg = new AssignmentDialog(menuGroup(), m_session, this->parentWidget());
if (!dlg->init(AssignmentDialog::MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT, targetParticipantId))
{
dlg->deleteLater();
return;
}
if (!m_session->addWidget(dlg, menuGroup(), QStringLiteral("ConfigureAreasToTargetParticipantId_%1").arg(targetParticipantId), LtsWidgets::LayoutArea::eDialogTab))
dlg->deleteLater();
}
void TargetPartDialog::onMapCenterClicked()
{
if (!m_sitMapGuiIfc)
return;
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
const QModelIndex curIdx = selectedRows.first();
if (!curIdx.isValid())
return;
const int pId = m_targetParticipantModel->getRowData(curIdx.row()).targetParticipantId();
m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_Participant, pId);
}
void TargetPartDialog::onMapZoomToClicked()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
if (selectedRows.isEmpty())
return;
QModelIndex index = selectedRows.first();
if (!index.isValid())
return;
if (!m_targetParticipantModel || !m_sitMapGuiIfc)
return;
int pId = m_targetParticipantModel->getRowData(index.row()).targetParticipantId();
if (pId<=0)
return;
// Assigned Areas:
QVector<int> assignedAreas;
auto cb = [pId, &assignedAreas](const TargetManagement::TargetAreaAssignment &assignment)
{
if (assignment.targetParticipantId() == pId)
assignedAreas.push_back(assignment.areaId());
};
m_dtc->targetAreaAssignments(cb);
{
QVector<QPair<SituationMap::MapObjectType, int>> entities;
entities.reserve(assignedAreas.size()+1);
entities.push_back({SituationMap::MapObjectType::MOT_Participant, pId});
for (auto item : assignedAreas)
entities.push_back({SituationMap::MapObjectType::MOT_ShootbackArea, item});
m_sitMapGuiIfc->zoomMapTo(entities);
}
}
void TargetPartDialog::onObjectEntered(const QModelIndex &index)
{
if (!m_sitMapGuiIfc)
return;
if (!index.isValid())
{
m_sitMapGuiIfc->removeObjectIndicator();
return;
}
int pId = m_targetParticipantModel->getRowData(index.row()).targetParticipantId();
if (pId>0)
{
// Target/Participant
m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_Participant, pId, true);
// Assigned Areas:
QVector<int> assignedAreas;
auto cb = [pId, &assignedAreas](const TargetManagement::TargetAreaAssignment &assignment)
{
if (assignment.targetParticipantId() == pId)
assignedAreas.push_back(assignment.areaId());
};
m_dtc->targetAreaAssignments(cb);
m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_ShootbackArea, assignedAreas, true);
}
else
m_sitMapGuiIfc->removeObjectIndicator();
}
void TargetPartDialog::onTableViewClicked(const QModelIndex &index)
{
if (!index.isValid())
return;
if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
onMapCenterClicked();
}
void TargetPartDialog::clearSelectionOfMapObjects()
{
if (!m_sitMapGuiIfc)
return;
// remove MapObjectIndicator:
m_sitMapGuiIfc->removeObjectIndicator();
}
void TargetPartDialog::onSelectionChanged()
{
QModelIndexList selectedRows = m_ui->widget->selectedRows();
const int cntSelectedRows = selectedRows.size();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::CenterMap, cntSelectedRows == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::ZoomMapTo, cntSelectedRows == 1);
m_assignAreaBtn->setEnabled(cntSelectedRows == 1); // LtsWidgets::DialogButton::Library
if (selectedRows.isEmpty())
onObjectEntered({}); // use invalid Idx to removeObjectIndicator
else
onObjectEntered(selectedRows.first());
}
//-----------------------------------------------------------------------------
} // namespace TargetManagement
@@ -0,0 +1,108 @@
/**
* @RDE_HEADER@
* Target Configuration
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/tgt_ftc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <TargetManagement/logger.h>
#include <Plugins/TargetManagement/Gui/ShootbackTargetConfiguration/tgt_target_part_model.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
class QPushButton;
namespace Ui
{
class TargetPartDialog;
}
namespace TargetManagement
{
class TargetPartDialog final : public LtsWidgets::LtsDialog
, protected TargetManagement::Interface::Ftc::ShootbackTargetModifyReplyHandler
, protected TargetManagement::Interface::Ftc::ShootbackTargetRemoveReplyHandler
{
Q_OBJECT
public:
using BaseClass = LtsWidgets::LtsDialog;
enum class MODE
{
TARGET_BASE_CONFIGURATION,
TARGET_OVERVIEW
};
explicit TargetPartDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~TargetPartDialog();
bool init(MODE mode);
void retranslate() override;
Q_SIGNALS:
void assignAreasRequested(int targetParticpantId);
void escapePressed();
protected:
void keyPressEvent(QKeyEvent *event) override final;
void onShootbackTargetModifyReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onShootbackTargetRemoveReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void setMode(MODE mode = MODE::TARGET_BASE_CONFIGURATION);
QByteArray toJson() const;
QVector<ShootbackTarget> fromJson(const QByteArray &content);
private Q_SLOTS:
void onEscapePressed();
void onSelectionChanged();
void onNewTargetPart();
void onRemoveTargetPart();
void onEditTargetPart();
void onExportButtonClicked();
void onImportButtonClicked();
void onImport();
void onAssignAreaClicked();
void onMapCenterClicked();
void onMapZoomToClicked();
void onObjectEntered(const QModelIndex &index);
void onTableViewClicked(const QModelIndex &index);
void clearSelectionOfMapObjects();
private:
QPushButton *m_assignAreaBtn{nullptr};
TargetParticipantModel *m_targetParticipantModel{nullptr};
MODE m_mode{MODE::TARGET_BASE_CONFIGURATION};
std::shared_ptr<TargetManagement::Interface::Dtc> m_dtc;
std::shared_ptr<TargetManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
LtsSession::LtsSession *m_session{nullptr};
Ui::TargetPartDialog *m_ui{nullptr};
QString m_menuGroup;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LOGGER_T m_logger;
};
} // namespace TargetManagement
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TargetPartDialog</class>
<widget class="QWidget" name="TargetPartDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">AlarmView</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,388 @@
/**
* @RDE_HEADER@
* TargetParticipantModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_target_part_model.h"
#include "tgt_common.h"
#include <LtsUtilsCore/variant_operators.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QApplication> // pixelMetric
#include <QBuffer>
namespace TargetManagement
{
QString toString(const std::vector< int32_t > &ids)
{
QString ret;
for (auto id : ids)
ret.append(QString::number(id));
return ret;
}
//---------------------------------
// TargetParticipantModel
//---------------------------------
TargetParticipantModel::TargetParticipantModel(QObject *parent)
: BaseClass(
{
tr("Id"),
tr("Target Name"),
// associated participant:
tr("Participant Id"),
tr("Equipmentnumber"),
tr("Type"), // Equipmenttype
tr("Participant"),
// main/base config
tr("Position"),
tr("ActivateLaserDesignation"),
tr("ActivateLights"),
tr("ActivatePopupAutomatic"),
tr("HitsToKill"),
tr("PermanentInstalledTarget"),
tr("VisibleParticipants")
},
parent)
, m_logger(getLogger("TargetParticipantModel"))
{}
bool TargetParticipantModel::initModel(const std::shared_ptr<TargetManagement::Interface::Dtc> &tgtDtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
LtsSession::LtsSession *session)
{
m_tgt_dtc = tgtDtc;
m_session = session;
delete m_participantHandler;
m_participantHandler = new ParticipantHandler(this);
m_participantHandler->init(m_tgt_dtc, ppmDtc, ppmGuiCbxIfc);
connect(m_participantHandler, &ParticipantHandler::signalParticipantNamesChanged,
this, &TargetParticipantModel::signalParticipantNamesChanged);
connect(m_participantHandler, &ParticipantHandler::signalParticipantChanged,
this, &TargetParticipantModel::update);
// insert Model
const QMap<qint32, TargetManagement::ShootbackTarget> targetParticipants = m_tgt_dtc->shootbackTargets();
INFO_LOG(m_logger) << "initModel - #TargetParticipantModel: " << targetParticipants.size();
connect(m_tgt_dtc.get(), &Interface::Dtc::shootbackTargetChanged,
this, &TargetParticipantModel::onShootbackTargetChanged);
{
auto cb = [this](const TargetManagement::ShootbackTarget & d) { onShootbackTargetChanged(d, DataModification::eAdded); };
m_tgt_dtc->shootbackTargets(cb);
}
// updateColumnFilter
connect(this, &TargetParticipantModel::rowsInserted, this, &TargetParticipantModel::updateColumnFilter);
connect(this, &TargetParticipantModel::rowsRemoved, this, &TargetParticipantModel::updateColumnFilter);
connect(this, &TargetParticipantModel::modelReset, this, &TargetParticipantModel::updateColumnFilter);
// in case of changing value like hitsToKill:
connect(this, &TargetParticipantModel::dataChanged, this, &TargetParticipantModel::updateColumnFilter);
updateColumnFilter();
return true;
}
QVariant TargetParticipantModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
orientation == Qt::Horizontal)
{
// a few Set<int> ==>
const auto processBoolean = [this](const QSet<int> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (int value : usedXYCont)
{
cfd.data = value;
cfd.text = value ? tr("Yes") : tr("No");
cfd.icon = value ? m_yes : m_no;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
// a few Set<int> ==>
const auto processInt = [](const QSet<int> &usedXYCont) -> QVariant
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(usedXYCont.size());
LtsWidgets::ComboboxFilterData cfd;
for (int value : usedXYCont)
{
cfd.data = value;
cfd.text = QString::number(value);
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
};
if (section == ActivateLaserDesignation)
return processBoolean(m_usedActiveLaserDesignations);
else if (section == ActivateLights)
return processBoolean(m_usedActivateLights);
else if (section == ActivatePopupAutomatic)
return processBoolean(m_usedActivatePopupAutomatic);
else if (section == HitsToKill)
return processInt(m_usedHitsToKill);
else if (section == PermanentInstalledTarget)
return processBoolean(m_usedPermanetTargetInstalled);
}
return BaseClass::headerData(section, orientation, role);
}
QVariant TargetParticipantModel::data(const QModelIndex &index, int role) const
{
INFO_LOG(m_logger) << LOGFUNCTION << " role=" << role
<< " index = " << index.column();
if (!indexIsValid(index))
return QVariant();
if (role != Qt::DisplayRole &&
role != Qt::DecorationRole &&
role != Qt::BackgroundRole &&
role != Qt::ToolTipRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
return QVariant();
const TargetManagement::ShootbackTarget &shootbackTarget = m_vecData.at(index.row());
if (role == Qt::DecorationRole)
{
if (index.column() == Participant)
{
static const int pmSize = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
const QPixmap &pm = m_participantHandler->getParticipantDecoration(shootbackTarget.targetParticipantId());
if (!pm.isNull())
return pm.scaled(pmSize, pmSize);
}
else if ((index.column() == ActivateLaserDesignation))
return shootbackTarget.activateLaserDesignation() ? m_yes : m_no;
else if ((index.column() == ActivateLights))
return shootbackTarget.activateLights() ? m_yes : m_no;
else if ((index.column() == ActivatePopupAutomatic))
return shootbackTarget.activatePopupAutomatic() ? m_yes : m_no;
else if ((index.column() == PermanentInstalledTarget))
return shootbackTarget.permanentInstalledTarget() ? m_yes : m_no;
return QVariant();
}
else if (role == Qt::BackgroundRole)
{
if ((index.column() == TargetPartipantId) && (shootbackTarget.targetParticipantId() <= 0))
return getWarningBackgroundRole(); // orange
if (index.column() == TargetPartipantEquipmentNumber)
{
const int eqNo = m_participantHandler->getParticipantIdToEquipmentNumber(shootbackTarget.targetParticipantId());
if (eqNo <= 0)
return getWarningBackgroundRole(); // orange
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == Participant)
{
QString tooltip(QStringLiteral("<html>"));
const QPixmap &img = m_participantHandler->getParticipantDecoration(shootbackTarget.targetParticipantId());
if (!img.isNull())
{
// without a temporary file:
QByteArray data;
QBuffer buffer(&data);
img.save(&buffer, "PNG", 100);
tooltip.append(QStringLiteral("<center><img src='data:image/png;base64,%1'></center>").arg(QString::fromLatin1(data.toBase64())));
QString hdr = this->headerData(ShootbackTargetName, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, QString::fromStdString(shootbackTarget.name())));
hdr = this->headerData(Participant, Qt::Horizontal, Qt::DisplayRole).toString();
const QString &val = m_participantHandler->getParticipantHierarchie(shootbackTarget.targetParticipantId());
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, val));
tooltip.append(QStringLiteral("</html>"));
return tooltip;
}
}
}
else if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
// following static_cast<int> are important!!!
if (index.column() == ActivateLaserDesignation)
return static_cast<int>(shootbackTarget.activateLaserDesignation());
if (index.column() == ActivateLights)
return static_cast<int>(shootbackTarget.activateLights());
if (index.column() == ActivatePopupAutomatic)
return static_cast<int>(shootbackTarget.activatePopupAutomatic());
if (index.column() == HitsToKill)
return shootbackTarget.hitsToKill();
}
switch (index.column())
{
case Id:
return shootbackTarget.id();
// associated participant:
case ShootbackTargetName:
return QString::fromStdString(shootbackTarget.name());
case TargetPartipantId:
return shootbackTarget.targetParticipantId();
case TargetPartipantEquipmentNumber:
{
const int eqNo = m_participantHandler->getParticipantIdToEquipmentNumber(shootbackTarget.targetParticipantId());
if (eqNo <= 0)
return QStringLiteral("-");
return eqNo;
}
case TargetPartipantEquipmentType:
{
const auto type = m_participantHandler->getParticipantIdToWmsTypeClass(shootbackTarget.targetParticipantId());
return ParticipantHandler::target_wmsTypeClassToString(type);
}
case Participant:
return m_participantHandler->getParticipantHierarchie(shootbackTarget.targetParticipantId());
// main/base config
case Position:
{
const Core::GeoPosition2D &pos = shootbackTarget.position();
return LtsCoordTrans::mgrsFromGeographic(pos.lon(), pos.lat());
}
case ActivateLaserDesignation:
return shootbackTarget.activateLaserDesignation() ? tr("Yes") : tr("No");
case ActivateLights:
return shootbackTarget.activateLights() ? tr("Yes") : tr("No");
case ActivatePopupAutomatic:
return shootbackTarget.activatePopupAutomatic() ? tr("Yes") : tr("No");
case HitsToKill:
return shootbackTarget.hitsToKill();
case PermanentInstalledTarget:
return shootbackTarget.permanentInstalledTarget() ? tr("Yes") : tr("No");
case VisibleParticipants:
return TargetManagement::toString(shootbackTarget.visibleParticipants());
} // switch
return QVariant();
}
QSet<int> TargetParticipantModel::getAssociatedParticipantIds() const
{
QSet<int> ret;
ret.reserve(m_vecData.size());
for (const TargetManagement::ShootbackTarget &data : m_vecData)
ret += data.targetParticipantId();
return ret;
}
void TargetParticipantModel::onShootbackTargetChanged(const TargetManagement::ShootbackTarget &data,
const DataModification modType)
{
BaseClass::onDataChanged(data, modType);
emit signalParticipantNamesChanged();
}
void TargetParticipantModel::updateColumnFilter()
{
m_usedActiveLaserDesignations.clear();
m_usedActivateLights.clear();
m_usedActivatePopupAutomatic.clear();
m_usedHitsToKill.clear();
m_usedPermanetTargetInstalled.clear();
for (const ShootbackTarget &item : qAsConst(m_vecData))
{
m_usedActiveLaserDesignations.insert(item.activateLaserDesignation());
m_usedActivateLights.insert(item.activateLights());
m_usedActivatePopupAutomatic.insert(item.activatePopupAutomatic());
m_usedHitsToKill.insert(item.hitsToKill());
m_usedPermanetTargetInstalled.insert(item.permanentInstalledTarget());
}
}
// --------------------------------------------------------
// TargetParticipantProxyModel
// --------------------------------------------------------
void TargetParticipantProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<TargetParticipantModel *>(sourceModel);
BaseClass::setSourceModel(sourceModel);
}
bool TargetParticipantProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel || !m_sourceModel->m_participantHandler ||
source_left.column() != source_right.column() ||
source_left.row() < 0 || source_left.row() >= m_sourceModel->m_vecData.size() ||
source_right.row() < 0 || source_right.row() >= m_sourceModel->m_vecData.size()
)
return BaseClass::lessThan(source_left, source_right);
const TargetManagement::ShootbackTarget &left = m_sourceModel->m_vecData.at(source_left.row());
const TargetManagement::ShootbackTarget &right = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case TargetParticipantModel::Columns::Id:
return left.id() < right.id();
case TargetParticipantModel::Columns::ShootbackTargetName:
return left.name() < right.name();
case TargetParticipantModel::Columns::TargetPartipantId:
return left.targetParticipantId() < right.targetParticipantId();
case TargetParticipantModel::Columns::TargetPartipantEquipmentNumber:
{
const int eqNoLeft = m_sourceModel->m_participantHandler->getParticipantIdToEquipmentNumber(left.targetParticipantId());
const int eqNoRight = m_sourceModel->m_participantHandler->getParticipantIdToEquipmentNumber(left.targetParticipantId());
return eqNoLeft < eqNoRight;
}
// case TargetParticipantModel::Columns::Position:
case TargetParticipantModel::Columns::ActivateLaserDesignation:
return left.activateLaserDesignation() < right.activateLaserDesignation();
case TargetParticipantModel::Columns::ActivateLights:
return left.activateLights() < right.activateLights();
case TargetParticipantModel::Columns::ActivatePopupAutomatic:
return left.activatePopupAutomatic() < right.activatePopupAutomatic();
case TargetParticipantModel::Columns::HitsToKill:
return left.hitsToKill() < right.hitsToKill();
case TargetParticipantModel::Columns::PermanentInstalledTarget:
return left.permanentInstalledTarget() < right.permanentInstalledTarget();
case TargetParticipantModel::Columns::VisibleParticipants:
return toString(left.visibleParticipants()) < toString(right.visibleParticipants());
case TargetParticipantModel::Columns::Participant:
// QString compare
return LtsUtils::lessThan(source_left.data(), source_right.data());
}
return BaseClass::lessThan(source_left, source_right);
}
} // namespace TargetManagement
@@ -0,0 +1,118 @@
/**
* @RDE_HEADER@
* TargetParticipantModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include "tgt_participant_handler.h"
#include <TargetManagement/tgt_dtc.h>
#include <TargetManagement/logger.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsSession/lts_session.h>
namespace TargetManagement
{
// Forward:
class ParticipantHandler;
// --------------------------------------------------------
// TargetParticipantModel
// --------------------------------------------------------
class TargetParticipantModel final : public LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackTarget>
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsAbstractTableModel<TargetManagement::ShootbackTarget>;
public:
enum Columns
{
Id,
// linked participant:
ShootbackTargetName,
TargetPartipantId,
TargetPartipantEquipmentNumber,
TargetPartipantEquipmentType,
Participant,
// main/base config
Position,
ActivateLaserDesignation,
ActivateLights,
ActivatePopupAutomatic,
HitsToKill,
PermanentInstalledTarget,
VisibleParticipants,
};
explicit TargetParticipantModel(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<Interface::Dtc> &tgtDtc,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
LtsSession::LtsSession *session);
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
QVariant data(const QModelIndex &, int) const override;
const QHash <int, QString> &getParticipantHierarchies() const { return m_participantHandler->getParticipantHierarchies(); }
const QHash <int, QPixmap> &getParticipantDecorations() const { return m_participantHandler->getParticipantDecorations(); }
QSet<int> getAssociatedParticipantIds() const;
const QVector<ShootbackTarget> &getData() const { return m_vecData; }
Q_SIGNALS:
void signalParticipantNamesChanged();
private Q_SLOTS:
void onShootbackTargetChanged(const TargetManagement::ShootbackTarget &data,
const DataModification modType);
void updateColumnFilter();
private:
friend class TargetParticipantProxyModel;
std::shared_ptr<TargetManagement::Interface::Dtc> m_tgt_dtc;
ParticipantHandler *m_participantHandler{nullptr};
LtsSession::LtsSession *m_session{nullptr};
QIcon m_yes{QLatin1String("icon:yes.svg")};
QIcon m_no{QLatin1String("icon:no.svg")};
// column filter
QSet<int> m_usedActiveLaserDesignations;
QSet<int> m_usedActivateLights;
QSet<int> m_usedActivatePopupAutomatic;
QSet<int> m_usedHitsToKill;
QSet<int> m_usedPermanetTargetInstalled;
LOGGER_T m_logger;
};
// --------------------------------------------------------
// TargetParticipantProxyModel
// --------------------------------------------------------
class TargetParticipantProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsColumnFilterProxyModel;
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
protected:
TargetParticipantModel *m_sourceModel{nullptr};
};
} //namespace TargetManagement
@@ -0,0 +1,266 @@
/**
* Telegrams toJSON
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#include "tgt_telegrams.h"
#include <QJsonDocument>
#include <QJsonObject>
namespace TargetManagement
{
//
// Helpers
//
JsonException::JsonException(const QJsonObject &obj, const QString &key)
: m_obj(obj)
, m_key(key)
, m_what("Could not find key '" + key.toUtf8() + "' in json ('" + QJsonDocument(obj).toJson(QJsonDocument::Compact) + "')")
{}
template <typename E>
QJsonValue enumToJson(E e)
{
static_assert(std::is_enum<E>::value, "Only useable with enumerations");
return static_cast<int>(e);
}
template <typename T>
bool get(const QJsonObject &obj, const QString &key, T &val, bool bOptional = false)
{
if (bOptional)
{
try
{
val = T::fromJson(obj[key].toObject());
}
catch (const JsonException &e)
{
Q_UNUSED(e);
return false;
}
}
else
val = T::fromJson(obj[key].toObject());
return true;
}
// POD getter
template <>
bool get(const QJsonObject &obj, const QString &key, bool &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isBool())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toBool();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, int &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble()) // ToDo: Check
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toInt();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, double &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isDouble())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toDouble();
return true;
}
template <>
bool get(const QJsonObject &obj, const QString &key, QString &val, bool bOptional)
{
const auto jVal = obj[key];
if (!jVal.isString())
{
if (bOptional)
return false;
throw JsonException(obj, key);
}
val = jVal.toString();
return true;
}
//
// enum getter
//
// Effect
template <>
bool get(const QJsonObject &obj, const QString &key, Effect &val, bool bOptional)
{
int iVal;
get(obj, key, iVal, bOptional);
switch (static_cast<Effect_def::type>(iVal))
{
case Effect_def::NearMiss:
case Effect_def::MobilityKill:
case Effect_def::WeaponKill:
val = Effect( static_cast<Effect_def::type>(iVal) );
return true;
}
throw JsonException(obj, key);
}
//
// Structs
//
// ------------------------------------------------------------------
//
// GeoPosition2D
//
QJsonObject GeoPosition2D::toJson() const
{
return QJsonObject({{QStringLiteral("lat"), lat},
{QStringLiteral("lon"), lon},
});
}
GeoPosition2D GeoPosition2D::fromJson(const QJsonObject &obj)
{
GeoPosition2D ret;
get(obj, QStringLiteral("lat"), ret.lat);
get(obj, QStringLiteral("lon"), ret.lon);
return ret;
}
//
// ShootbackTargetData
//
QJsonObject ShootbackTargetData::toJson() const
{
return QJsonObject({{QStringLiteral("id"), id},
{QStringLiteral("targetDataId"), targetDataId},
{QStringLiteral("name"), name},
{QStringLiteral("targetParticipantEquipmentNumber"), targetParticipantEquipmentNumber},
{QStringLiteral("activateLaserDesignation"), activateLaserDesignation},
{QStringLiteral("activateLights"), activateLights},
{QStringLiteral("activatePopupAutomatic"), activatePopupAutomatic},
{QStringLiteral("hitsToKill"), hitsToKill},
{QStringLiteral("permanentInstalledTarget"), permanentInstalledTarget},
});
}
ShootbackTargetData ShootbackTargetData::fromJson(const QJsonObject &obj)
{
ShootbackTargetData ret;
get(obj, QStringLiteral("id"), ret.id);
get(obj, QStringLiteral("targetDataId"), ret.targetDataId);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("targetParticipantEquipmentNumber"), ret.targetParticipantEquipmentNumber);
get(obj, QStringLiteral("activateLaserDesignation"), ret.activateLaserDesignation);
get(obj, QStringLiteral("activateLights"), ret.activateLights);
get(obj, QStringLiteral("activatePopupAutomatic"), ret.activatePopupAutomatic);
get(obj, QStringLiteral("hitsToKill"), ret.hitsToKill);
get(obj, QStringLiteral("permanentInstalledTarget"), ret.permanentInstalledTarget);
return ret;
}
//
// ShootbackAreaData
//
QJsonObject ShootbackAreaData::toJson() const
{
return QJsonObject({{QStringLiteral("id"), id},
{QStringLiteral("name"), name},
{QStringLiteral("position"), position.toJson()},
{QStringLiteral("width"), width},
{QStringLiteral("height"), height},
});
}
ShootbackAreaData ShootbackAreaData::fromJson(const QJsonObject &obj)
{
ShootbackAreaData ret;
get(obj, QStringLiteral("id"), ret.id);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("position"), ret.position);
get(obj, QStringLiteral("width"), ret.width);
get(obj, QStringLiteral("height"), ret.height);
return ret;
}
//
// ShootbackConfigurationData
//
QJsonObject ShootbackConfigurationData::toJson() const
{
return QJsonObject({{QStringLiteral("interval1"), interval1},
{QStringLiteral("flash1"), flash1},
{QStringLiteral("effect1"), enumToJson(effect1.underlying())},
{QStringLiteral("interval2"), interval2},
{QStringLiteral("flash2"), flash2},
{QStringLiteral("effect2"), enumToJson(effect2.underlying())},
});
}
ShootbackConfigurationData ShootbackConfigurationData::fromJson(const QJsonObject &obj)
{
ShootbackConfigurationData ret;
get(obj, QStringLiteral("interval1"), ret.interval1);
get(obj, QStringLiteral("flash1"), ret.flash1);
get(obj, QStringLiteral("effect1"), ret.effect1);
get(obj, QStringLiteral("interval2"), ret.interval2);
get(obj, QStringLiteral("flash2"), ret.flash2);
get(obj, QStringLiteral("effect2"), ret.effect2);
return ret;
}
//
// TargetAreaAssignmentData
//
QJsonObject TargetAreaAssignmentData::toJson() const
{
return QJsonObject({{QStringLiteral("id"), id},
{QStringLiteral("name"), name},
{QStringLiteral("areaId"), areaId},
{QStringLiteral("targetParticipantId"), targetParticipantId},
{QStringLiteral("configuration"), configuration.toJson()},
{QStringLiteral("isActive"), isActive},
});
}
TargetAreaAssignmentData TargetAreaAssignmentData::fromJson(const QJsonObject &obj)
{
TargetAreaAssignmentData ret;
get(obj, QStringLiteral("id"), ret.id);
get(obj, QStringLiteral("name"), ret.name);
get(obj, QStringLiteral("areaId"), ret.areaId);
get(obj, QStringLiteral("targetParticipantId"), ret.targetParticipantId);
get(obj, QStringLiteral("configuration"), ret.configuration);
get(obj, QStringLiteral("isActive"), ret.isActive);
return ret;
}
} // namespace TargetManagement
@@ -0,0 +1,173 @@
/**
* Telegrams toJSON
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLE, 2020-06-29
*/
#pragma once
#include <cstdint>
#include <exception>
#include <QJsonObject>
#include <QString>
#include <Services/TargetManagement/tgt_dtc.h>
namespace TargetManagement
{
class JsonException final : public std::exception
{
public:
JsonException(const QJsonObject &obj, const QString &key);
const char *what() const noexcept override { return m_what.data(); }
private:
QJsonObject m_obj;
QString m_key;
QByteArray m_what;
};
template <typename T>
struct Constraints;
//
// Enumerations
//
//
// Structs
//
// ------------------------------------------------------------------
// ------------------------------------------------------------------
struct Target
{
virtual ~Target() = default;
virtual QJsonObject toJson() const = 0;
virtual QString type() const = 0;
};
struct GeoPosition2D
{
GeoPosition2D() = default;
explicit GeoPosition2D(const Core::GeoPosition2D pos)
: lat(pos.lat()), lon(pos.lon()) {}
double lat = 0; // in degree, WGS-84
double lon = 0; // in degree, WGS-84
static GeoPosition2D fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
// Core::GeoPosition2D toCoreGeoPosition2D() const { return {lon, lat}; }
};
// ------------------------------------------------------------------
template <typename T>
struct TargetBaseTmpl : Target
{
QString type() const override final { return Constraints<T>::type(); }
};
// ------------------------------------------------------------------
struct ShootbackTargetData final : public TargetBaseTmpl<ShootbackTargetData>
{
// use simple members and not generated dds struct to be independent
int32_t id{-1};
int32_t targetDataId{-1};
QString name;
int32_t targetParticipantEquipmentNumber{-1};
bool activateLaserDesignation{false};
bool permanentInstalledTarget{false};
bool activateLights{false};
int32_t hitsToKill{-1};
bool activatePopupAutomatic{false};
// conversion functions
QJsonObject toJson() const override;
static ShootbackTargetData fromJson(const QJsonObject &obj);
};
template <> struct Constraints<ShootbackTargetData>
{
static QString type() { return QStringLiteral("ShootbackTargetData"); }
};
// ------------------------------------------------------------------
struct ShootbackAreaData final : public TargetBaseTmpl<ShootbackAreaData>
{
// use simple members and not generated dds struct to be independent
int32_t id{-1};
QString name;
GeoPosition2D position;
double width{.0};
double height{.0};
// conversion functions
QJsonObject toJson() const override;
static ShootbackAreaData fromJson(const QJsonObject &obj);
};
template <> struct Constraints<ShootbackAreaData>
{
static QString type() { return QStringLiteral("ShootbackAreaData"); }
};
// ------------------------------------------------------------------
struct ShootbackConfigurationData final : public TargetBaseTmpl<ShootbackConfigurationData>
{
// use simple members and not generated dds struct to be independent
int interval1{-1};
bool flash1{false};
TargetManagement::Effect effect1{TargetManagement::Effect_def::NearMiss};
int interval2{-1};
bool flash2{false};
TargetManagement::Effect effect2{TargetManagement::Effect_def::NearMiss};
// conversion functions
QJsonObject toJson() const override;
static ShootbackConfigurationData fromJson(const QJsonObject &obj);
};
template <> struct Constraints<ShootbackConfigurationData>
{
static QString type() { return QStringLiteral("ShootbackConfigurationData"); }
};
// ------------------------------------------------------------------
struct TargetAreaAssignmentData final : public TargetBaseTmpl<TargetAreaAssignmentData>
{
// use simple members and not generated dds struct to be independent
int32_t id{-1};
QString name;
int areaId;
int targetParticipantId;
ShootbackConfigurationData configuration;
bool isActive{false};
// conversion functions
QJsonObject toJson() const override;
static TargetAreaAssignmentData fromJson(const QJsonObject &obj);
};
template <> struct Constraints<TargetAreaAssignmentData>
{
static QString type() { return QStringLiteral("TargetAreaAssignmentData"); }
};
}
+30
View File
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* HMI Plugin for AreaEffectSimulation (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <TargetManagement//tgt_dtc.h>
#include <TargetManagement/tgt_ftc.h>
namespace TargetManagement
{
/**
* @brief The DataInterface class provides the Topics Clients only for the GUI Plugins
*/
class DataInterface : public DataPluginBase::Interface
{
public:
using DataPluginBase::Interface::Interface;
virtual std::shared_ptr<TargetManagement::Interface::Dtc> getDtc() = 0;
virtual std::shared_ptr<TargetManagement::Interface::Ftc> getFtc() = 0;
};
}
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#pragma once
namespace ParticipantManagement
{
class ForeignPartyGuiInterface
{
public:
ForeignPartyGuiInterface() = default;
virtual ~ForeignPartyGuiInterface() = default;
};
}