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

@@ -0,0 +1,73 @@
/**
* @RDE_HEADER@
* CustomView for MapObjects
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2017-04-11
*/
// Own
#include "map_object_custom_view.h"
#include "ui_map_object_custom_view.h"
#include "map_object_model.h"
#include <LtsSession/lts_session_data.h>
// Ot
#include <QDataWidgetMapper>
namespace SituationMap
{
MapObjectCustomView::MapObjectCustomView(QWidget *parent)
: BaseClass(parent)
, m_ui(new Ui::MapObjectCustomView)
, m_mapper(new QDataWidgetMapper(this))
{
m_ui->setupUi(this);
if (LtsSessionData::LtsSessionData::getInstance()->isTablet())
{
constexpr auto scaleFactor = 1.4;
resize(size() * scaleFactor);
m_ui->lbIcon->setMinimumSize(m_ui->lbIcon->minimumSize() * scaleFactor);
m_ui->lbIcon->setMaximumSize(m_ui->lbIcon->maximumSize() * scaleFactor);
}
}
MapObjectCustomView::~MapObjectCustomView()
{
delete m_ui;
}
bool MapObjectCustomView::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
if (idx.model() != m_mapper->model())
{
// create mapping;
m_mapper->setModel(const_cast<QAbstractItemModel *>(idx.model()));
m_mapper->addMapping(m_ui->lbDescription, MapObjectModel::Columns::SINGLE_DESCRIPTION, "text");
m_mapper->addMapping(m_ui->lbIcon, MapObjectModel::Columns::PICTURE, "pixmap");
}
setRow(idx.row());
return true;
}
void MapObjectCustomView::setRow(int row)
{
m_mapper->setCurrentIndex(row);
// assume for now, that the relation between row and uniqueMapId will not change:
QAbstractItemModel *modelPtr = m_mapper->model();
if (modelPtr)
m_uniqueMapId = modelPtr->data(modelPtr->index(row, MapObjectModel::Columns::UNIQUE_MAP_ID)).toInt();
else
m_uniqueMapId = -1;
}
} // namespace SituationMap
@@ -0,0 +1,46 @@
/**
* @RDE_HEADER@
* CustomView for MapObjects
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2017-04-11
*/
#pragma once
// Own
#include <Map/situation_map_types.h>
#include <Viewer/LtsDataView/abstract_display_widget.h>
class QDataWidgetMapper;
namespace Ui
{
class MapObjectCustomView;
}
namespace SituationMap
{
class MapObjectCustomView final : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
using BaseClass = AbstractDisplayWidget;
public:
explicit MapObjectCustomView(QWidget *parent = nullptr);
~MapObjectCustomView();
bool init(const QModelIndex &idx) override;
private:
void setRow(int row);
private:
Ui::MapObjectCustomView *m_ui;
QDataWidgetMapper *m_mapper = nullptr;
UniqueMapId m_uniqueMapId = INVALID_MAP_ID;
};
} // SituationMap
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MapObjectCustomView</class>
<widget class="QWidget" name="MapObjectCustomView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>63</width>
<height>88</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lbIcon">
<property name="minimumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbDescription">
<property name="text">
<string notr="true">&lt;Desc&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,545 @@
/**
* @RDE_HEADER@
* HMI Plugin for ExerciseManangement - Exercise Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
// Own
#include "map_object_model.h"
#include <Symbology/sidc_codec.h>
#include <SituationMap/Map/party_id_to_color_functor.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
// Qt
#include <QString>
#include <QBuffer>
#include <QPainter>
#include <QGuiApplication>
namespace SituationMap
{
static constexpr int ICON_RESOLUTION_CUSTOM = 128;
static constexpr int ICON_RESOLUTION_TABLE = 32;
void updateMapObjectDataToEnsureGoodQuality(MapObjectData *mod)
{
mod->m_symDataToRender.sizeL = ICON_RESOLUTION_CUSTOM;
}
MapObjectData::~MapObjectData()
{
delete m_symbolResultWatcher;
}
void MapObjectData::onResultReady()
{
if (!m_symbolResultWatcher)
return;
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = m_symbolResultWatcher->symbolResult();
if (!symResult)
return; // should NEVER happen! (Which object should have triggered the signal???)
setImage(symResult->symbolImage().image());
emit dataChanged(m_uniqueMapId);
m_symbolResultWatcher->deleteLater();
m_symbolResultWatcher = nullptr;
}
void MapObjectData::requestImage(AdvancedSymbology::SymbolDictionary *dict)
{
if (!m_symbolResultWatcher)
{
m_symbolResultWatcher = new AdvancedSymbology::SymbolResultWatcher;
connect(m_symbolResultWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady,
this, &MapObjectData::onResultReady);
}
updateMapObjectDataToEnsureGoodQuality(this);
m_symbolResultWatcher->setSymbolResult(dict->findImage(m_symDataToRender));
}
void MapObjectData::setImage(const QImage &img)
{
if (img.isNull())
{
m_pixIcon = QPixmap();
m_pixPicture = QPixmap();
return;
}
const auto dpr = qApp->devicePixelRatio(); // only works when all screens have the same dpr, otherwise
// the widget (= screen) must be known
m_pixIcon = QPixmap::fromImage(img.scaled(QSize(ICON_RESOLUTION_TABLE, ICON_RESOLUTION_TABLE) * dpr,
Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
m_pixPicture = QPixmap::fromImage(img.scaled(QSize(ICON_RESOLUTION_CUSTOM, ICON_RESOLUTION_CUSTOM) * dpr,
Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
m_pixIcon.setDevicePixelRatio(dpr);
m_pixPicture.setDevicePixelRatio(dpr);
}
//---------------------------------
// MapObjectModel
//---------------------------------
MapObjectModel::MapObjectModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<QSharedPointer<MapObjectData>>(
{
tr("UniqueMapid"),
tr("Sidc"),
tr("Description"),
tr("Icon"),
tr("ParticipantId"),
tr("Equipment number"),
tr("Party"),
tr("TypeId"),
tr("Type"),
tr("VulnerabilityStateId"),
tr("VulnerabilityState"),
tr("Designator"),
tr("Tact. Identifier"),
tr("Picture")
},
parent)
, m_logger(getLogger("MapObjectModel"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
MapObjectModel::~MapObjectModel()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void MapObjectModel::initModel(Map *map)
{
m_map = map;
m_dictionary = &(m_map->symbolDictionary());
// Assume that the dialog (and therefore this underlying model) is created
// AFTER all user-defined data is udes to update SymbolDictionary.
// So we can simply use the changedDELAYED:
connect(m_dictionary, &AdvancedSymbology::SymbolDictionary::changedDelayed, this, &MapObjectModel::requestCivilIcons, Qt::UniqueConnection);
connect(this, &MapObjectModel::rowsInserted, this, &MapObjectModel::updateUsedPartyIds);
connect(this, &MapObjectModel::rowsRemoved, this, &MapObjectModel::updateUsedPartyIds);
connect(this, &MapObjectModel::modelReset, this, &MapObjectModel::updateUsedPartyIds);
}
bool MapObjectModel::contains(UniqueMapId uniqueMapId) const
{
return findRowForUniqueMapId(uniqueMapId) >= 0;
}
void MapObjectModel::remove(UniqueMapId uniqueMapId)
{
const int row = findRowForUniqueMapId(uniqueMapId);
removeRow(row);
}
void MapObjectModel::setMapObjectData(const QVector<QSharedPointer<MapObjectData>> &mapObjectDataVec)
{
setData(mapObjectDataVec);
for (const QSharedPointer<MapObjectData> &mapObjectData : mapObjectDataVec)
if (mapObjectData)
{
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
}
}
bool MapObjectModel::addMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData)
{
const int row = findRowForUniqueMapId(mapObjectData->m_uniqueMapId);
if (row >= 0)
return false;
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
// APPEND
if (!insertRow(mapObjectData))
return false;
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
return true;
}
QImage markImage(const QPixmap &orgPixmap)
{
QImage newImage(orgPixmap.size(), QImage::Format_ARGB32);
static QColor fillColor = QColor(211, 211, 211, 120);
newImage.fill(fillColor);
QPainter painter(&newImage);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter.drawPixmap(orgPixmap.rect(), orgPixmap);
painter.end();
return newImage;
}
bool MapObjectModel::updateMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData)
{
const int row = findRowForUniqueMapId(mapObjectData->m_uniqueMapId);
if (row < 0)
return false;
// UPDATE
if (!mapObjectData->m_symDataToRender.sidc.isEmpty()) // if sidc is provided
{
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
const auto &oldRowData = m_vecData.at(row);
if (oldRowData->m_symDataToRender == mapObjectData->m_symDataToRender)
return true; // image will not change -> return;
// 1) 'mark' old image and reuse it:
mapObjectData->setImage(markImage(oldRowData->m_pixPicture));
// 2) icons are 'reused', but start update
requestIcon(mapObjectData);
}
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
return setRowData(row, mapObjectData);
}
void MapObjectModel::requestCivilIcons()
{
for (const DATA_T &moData : qAsConst(m_vecData))
{
if (!moData)
continue;
const QString &sidc = moData->m_symDataToRender.sidc;
if (!AdvancedSymbology::SidcCodec::isEncoded(sidc))
continue;
if (!AdvancedSymbology::SidcCodec::isCivil(sidc))
continue;
requestIcon(moData);
} // for
}
QVariant MapObjectModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
orientation == Qt::Horizontal)
{
if (section == PARTY)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedPartyIds.size());
LtsWidgets::ComboboxFilterData cfd;
for (const int partyId : m_usedPartyIds)
{
const PartyIdToColorFunctor::PartyData party = m_map->partyIdToColorFunctor().partyId(partyId);// m_parties.value(partyId);
cfd.data = partyId;
cfd.text = party.m_name;
cfd.icon = party.m_icon;
cfc.data.push_back(cfd);
}
cfc.sortItems = false;
return cfc.toVariant();
}
if (section == TYPE_NAME)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedTypeName.size());
LtsWidgets::ComboboxFilterData cfd;
for (const QString &typeName : m_usedTypeName)
{
cfd.data = typeName;
cfd.text = typeName;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
}
if (section == VULNERABILITY_STATE)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedVulnerabilities.size());
LtsWidgets::ComboboxFilterData cfd;
for (auto it = m_usedVulnerabilities.begin(); it != m_usedVulnerabilities.end(); ++it)
{
cfd.data = it.key();
cfd.text = it.value();
cfc.data.push_back(cfd);
}
cfc.sortItems = false;
return cfc.toVariant();
}
}
return BaseClass::headerData(section, orientation, role);
}
QVariant MapObjectModel::data(const QModelIndex &index, int role) const
{
if (!indexIsValid(index))
return QVariant();
if (role != Qt::DisplayRole &&
role != Qt::ToolTipRole &&
role != Qt::EditRole && // required by QDataWidgetMapper of MapObjectCustomView
role != Qt::DecorationRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
return QVariant();
const DATA_T &moData = m_vecData.at(index.row());
if (role == Qt::ToolTipRole)
{
switch (index.column())
{
case PARTY:
return QStringLiteral("%1 (%2)").arg(moData->m_partyName).arg(moData->m_partyId);
case UNIQUE_MAP_ID: // CustomView -> ToolTipRole and column==UNIQUE_MAP_ID (0)
case ICON: // TableView -> ToolTipRole and column==ICON
{
QString tooltip(QStringLiteral("<html>"));
const QPixmap &img = moData->m_pixPicture;
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())));
}
if (!moData->m_typeName.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::TYPE_NAME , Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_typeName));
}
if (!moData->m_typeName.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::VULNERABILITY_STATE, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_vulnerabilityString));
}
if (!moData->m_description1.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::DESCRIPTION1, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_description1));
}
if (!moData->m_description2.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::DESCRIPTION2, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_description2));
}
#ifdef LTS_DEBUG
tooltip.append(QStringLiteral("<p>participantId: %2</p>").arg(moData->m_participantId));
tooltip.append(QStringLiteral("<p>row: %2</p>").arg(index.row()));
tooltip.append(QStringLiteral("<p>uniqueMapId: %2</p>").arg(moData->m_uniqueMapId));
tooltip.append(QStringLiteral("<p>typeId: %2</p>").arg(moData->m_typeId));
tooltip.append(QStringLiteral("<p>vulnerabilityStateId: %2</p>").arg(moData->m_vulnerabilityState));
#endif // LTS_DEBUG
tooltip.append(QStringLiteral("</html>"));
return tooltip;
}
} // switch
} // if ((role == Qt::ToolTipRole))
if ((role == Qt::DisplayRole) || (role == Qt::EditRole) || (role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole))
{
const UniqueMapId &uniqueMapId = moData->m_uniqueMapId;
switch (index.column())
{
case UNIQUE_MAP_ID:
return uniqueMapId;
case SIDC:
return moData->m_symDataToRender.sidc;
case SINGLE_DESCRIPTION:
if (moData->m_equipmentNumber >= 0)
return moData->m_equipmentNumber;
else
return moData->m_description1;
case ICON:
{
// provided or already cached?
if (moData->m_pixIcon.isNull())
{
moData->setImage(AdvancedSymbology::SymbolDictionary::temporaryImage());
requestIcon(moData);
}
if (moData->m_pixIcon.isNull())
return QVariant();
return moData->m_pixIcon;
}
case PARTICIPANT_ID:
return moData->m_participantId <= 0 ? QVariant() : QVariant(moData->m_participantId);
case EQUIPMENT_NUMBER:
return moData->m_equipmentNumber <= 0 ? QVariant() : QVariant(moData->m_equipmentNumber);
case PARTY:
return moData->m_partyName;
case TYPE_ID:
return moData->m_typeId <= 0 ? QVariant() : QVariant(moData->m_typeId);
case TYPE_NAME:
return moData->m_typeName;
case VULNERABILITY_STATE:
return moData->m_vulnerabilityString;
case VULNERABILITY_STATE_ID:
return moData->m_vulnerabilityState <= 0 ? QVariant() : QVariant(moData->m_vulnerabilityState);
case DESCRIPTION1:
return moData->m_description1;
case DESCRIPTION2:
return moData->m_description2;
case PICTURE:
{
// provided or already cached?
if (moData->m_pixPicture.isNull())
{
moData->setImage(AdvancedSymbology::SymbolDictionary::temporaryImage());
requestIcon(moData);
}
if (moData->m_pixPicture.isNull())
return QVariant();
return moData->m_pixPicture;
} // case PICTURE
} // switch
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
if (index.column() == PARTY)
return moData->m_partyId;
if (index.column() == TYPE_NAME)
return moData->m_typeName;
if (index.column() == VULNERABILITY_STATE)
return moData->m_vulnerabilityState;
}
return QVariant();
}
UniqueMapId MapObjectModel::uniqueMapIdOfIndex(const QModelIndex &index) const
{
if (!indexIsValid(index))
return SituationMap::INVALID_MAP_ID;
const DATA_T &moData = m_vecData.at(index.row());
if (!moData)
return SituationMap::INVALID_MAP_ID;
return moData->m_uniqueMapId;
}
void MapObjectModel::onDataChanged(UniqueMapId uniqueMapId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapId=" << uniqueMapId;
// resultWatcher has generated a new image -> update view:
int row = findRowForUniqueMapId(uniqueMapId);
emit dataChanged(index(row, 0), index(row, LtsAbstractTableModel::columnCount(QModelIndex()) - 1));
}
int MapObjectModel::findRowForUniqueMapId(UniqueMapId uniqueMapId) const
{
for (int i = 0; i < m_vecData.size(); ++i)
{
if (m_vecData.at(i)->m_uniqueMapId == uniqueMapId)
return i;
}
return -1;
}
void MapObjectModel::requestIcon(const MapObjectModel::DATA_T &data) const
{
// start rendering using SymbolResultWatcher:
data->requestImage(m_dictionary);
}
void MapObjectModel::updateUsedPartyIds()
{
m_usedPartyIds.clear();
m_usedTypeName.clear();
m_usedVulnerabilities.clear();
for (const QSharedPointer<MapObjectData> &item : qAsConst(m_vecData))
{
if (!item)
continue;
m_usedPartyIds[item->m_partyId] = item->m_partyId;
m_usedTypeName.insert(item->m_typeName);
m_usedVulnerabilities.insert(item->m_vulnerabilityState,
item->m_vulnerabilityState < 0 ? QStringLiteral("-") : item->m_vulnerabilityString);
}
}
// --------------------------------------------------------
// MapObjectProxyModel
// --------------------------------------------------------
void MapObjectProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<MapObjectModel*>(sourceModel);
BaseClass::setSourceModel(sourceModel);
}
bool MapObjectProxyModel::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 QSharedPointer<MapObjectData> &left = m_sourceModel->m_vecData.at(source_left.row());
const QSharedPointer<MapObjectData>&right = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case MapObjectModel::Columns::UNIQUE_MAP_ID:
return left->m_uniqueMapId < right->m_uniqueMapId;
case MapObjectModel::Columns::SIDC:
return left->m_symDataToRender.sidc < right->m_symDataToRender.sidc;
case MapObjectModel::Columns::SINGLE_DESCRIPTION:
if (left->m_equipmentNumber && right->m_equipmentNumber)
return left->m_equipmentNumber < right->m_equipmentNumber;
if (left->m_equipmentNumber)
return true;
if (right->m_equipmentNumber)
return true;
return left->m_description1 < left->m_description1;
case MapObjectModel::Columns::PARTICIPANT_ID:
return left->m_participantId < right->m_participantId;
case MapObjectModel::Columns::EQUIPMENT_NUMBER:
return left->m_equipmentNumber < right->m_equipmentNumber;
case MapObjectModel::Columns::PARTY:
return left->m_partyId < right->m_partyId;
case MapObjectModel::Columns::TYPE_ID:
return left->m_typeId < right->m_typeId;
case MapObjectModel::Columns::TYPE_NAME:
return left->m_typeName < right->m_typeName;
case MapObjectModel::Columns::DESCRIPTION1:
return left->m_description1 < right->m_description1;
case MapObjectModel::Columns::DESCRIPTION2:
return left->m_description2 < right->m_description2;
}
return BaseClass::lessThan(source_left, source_right);
}
} // namespace SituationMap
@@ -0,0 +1,187 @@
/**
* @RDE_HEADER@
* MapObjectModel
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2017-04-11
*/
#pragma once
// Own
#include <Map/map.h>
#include <Symbology/symbol_result.h>
#include <Common/situation_map_logging.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
namespace SituationMap
{
// --------------------------------------------------------
// MapObjectData
// --------------------------------------------------------
class MapObjectData : public QObject
{
Q_OBJECT
public:
explicit MapObjectData(UniqueMapId uniqueMapId = INVALID_MAP_ID)
: m_uniqueMapId(uniqueMapId)
{}
~MapObjectData();
void requestImage(AdvancedSymbology::SymbolDictionary *dict);
void setImage(const QImage &img);
// basic data:
UniqueMapId m_uniqueMapId;
int m_participantId{-1};
int m_equipmentNumber{-1};
int m_partyId{-1};
int m_typeId{-1};
int m_vulnerabilityState{-1};
QString m_partyName;
QString m_typeName;
QString m_vulnerabilityString;
int m_buildingId{-1};
QString m_description1;
QString m_description2;
// sidc -> icon/image:
SymbolDataToRender m_symDataToRender;
QPixmap m_pixIcon;
QPixmap m_pixPicture;
private:
AdvancedSymbology::SymbolResultWatcher *m_symbolResultWatcher = nullptr;
Q_SIGNALS:
void dataChanged(UniqueMapId uniqueMapId);
public Q_SLOTS:
void onResultReady();
private:
};
// --------------------------------------------------------
// MapObjectModel
// --------------------------------------------------------
class MapObjectModel : public LtsWidgets::LtsAbstractTableModel<QSharedPointer<MapObjectData>>
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsAbstractTableModel<QSharedPointer<MapObjectData>>;
public:
enum Columns
{
UNIQUE_MAP_ID = 0,
SIDC,
SINGLE_DESCRIPTION,
ICON,
PARTICIPANT_ID,
EQUIPMENT_NUMBER,
PARTY,
TYPE_ID,
TYPE_NAME,
VULNERABILITY_STATE_ID,
VULNERABILITY_STATE,
DESCRIPTION1,
DESCRIPTION2,
PICTURE
};
explicit MapObjectModel(QObject *parent = nullptr);
~MapObjectModel();
void initModel(Map *map);
bool contains(UniqueMapId uniqueMapId) const;
void remove(UniqueMapId uniqueMapId);
void setMapObjectData(const QVector<QSharedPointer<MapObjectData>> &mapObjectDataVec);
bool addMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData);
bool updateMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData);
template<typename T = QVector<UniqueMapId>>
T allMapObjects() const
{
T uniqueMapIds;
uniqueMapIds.reserve(m_vecData.size());
for (const DATA_T &item : m_vecData)
if (item)
uniqueMapIds += item->m_uniqueMapId;
return uniqueMapIds;
}
template<typename T = QVector<int>>
T allEquipmentNumbers() const
{
T equipmentNumbers;
equipmentNumbers.reserve(m_vecData.size());
for (const DATA_T &item : m_vecData)
if (item && item->m_equipmentNumber > 0)
equipmentNumbers += item->m_equipmentNumber;
return equipmentNumbers;
}
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
QVariant data(const QModelIndex &, int) const override final;
UniqueMapId uniqueMapIdOfIndex(const QModelIndex &index) const;
private Q_SLOTS:
void onDataChanged(UniqueMapId uniqueMapId);
void requestCivilIcons();
void updateUsedPartyIds();
private:
using DATA_T = QSharedPointer<MapObjectData>;
int findRowForUniqueMapId(UniqueMapId uniqueMapId) const;
void requestIcon(const DATA_T &data) const;
Map *m_map = nullptr;
AdvancedSymbology::SymbolDictionary *m_dictionary = nullptr;
QMap<int, int> m_usedPartyIds; // keep sorted
QSet<QString> m_usedTypeName;
QMap<int, QString> m_usedVulnerabilities; // keep sorted
LOGGER_T m_logger;
friend class MapObjectProxyModel;
};
// MapObjectModel
// --------------------------------------------------------
// MapObjectProxyModel
// --------------------------------------------------------
class MapObjectProxyModel : 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:
MapObjectModel *m_sourceModel = nullptr;
};
} // namespace SituationMap
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MapObjectSelectionDialog</class>
<widget class="QWidget" name="MapObjectSelectionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Map Object Selection</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="ltsDataView">
<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,726 @@
/**
* @RDE_HEADER@
* Class MapObjectSelection
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "map_object_selection_widget.h"
#include "map_object_custom_view.h"
#include "map_object_model.h"
#include "ui_map_object_selection_dialog.h"
#include <Map/object_factory.h>
#include <Map/party_id_to_color_functor.h>
#include <Map/object_indicator.h>
#include <MapObjects/participant.h>
#include <Map/bounding_box.h>
#include <AdapterDds/adapter_dds.h>
// PDM (for Single Service Equipment Check)
#include <ProjectDataManagement/pdm_to_string.h>
// BLD
#include <Proxies/Buildings/bld_ftc.h>
// Qt
#include <QMenu>
#include <QItemSelection>
#include <QGridLayout>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
namespace SituationMap
{
//----------------------------------------------------------------------------
// MapObjectSelectionQDialog - Qt-Dialog - TestDialog
//----------------------------------------------------------------------------
MapObjectSelectionQDialog::MapObjectSelectionQDialog(QWidget *parent)
: BaseClass(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
QGridLayout *layout = new QGridLayout;
this->setLayout(layout);
m_mosw = new MapObjectSelectionWidget(this);
layout->addWidget(m_mosw);
}
bool MapObjectSelectionQDialog::init(Map *map, AdapterDds *adapterDds)
{
bool success = m_mosw->init(map, adapterDds);
if (map)
connect(map, &Map::beginDestroy, this, &MapObjectSelectionQDialog::onMapDestroyed, Qt::UniqueConnection);
return success;
}
void MapObjectSelectionQDialog::reset()
{
m_mosw->reset();
}
void MapObjectSelectionQDialog::setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList)
{
m_mosw->setMapObjectsToDisplay(mapObjList);
}
void MapObjectSelectionQDialog::setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds)
{
m_mosw->setMapObjectsToDisplay(uniqueMapIds);
}
void MapObjectSelectionQDialog::onMapDestroyed()
{
// commit suicide";
delete this;
}
//----------------------------------------------------------------------------
// MapObjectSelectionLtsDialog - LtsDialog
//----------------------------------------------------------------------------
MapObjectSelectionLtsDialog::MapObjectSelectionLtsDialog(QWidget *parent, LtsWidgets::ButtonCombination buttonCombination)
: BaseClass(parent, buttonCombination)
, m_mosw(new MapObjectSelectionWidget(this))
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_checkButtonHandler(nullptr)
{
// signal-signal connection:
connect(m_mosw, &MapObjectSelectionWidget::mapObjectsClicked,
this, &MapObjectSelectionLtsDialog::mapObjectsClicked);
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(m_mosw);
}
void MapObjectSelectionLtsDialog::retranslate()
{
if (!m_mosw)
return;
translate(m_mosw->m_ui, tr("Map Object Selection"));
}
bool MapObjectSelectionLtsDialog::init(Map *map, AdapterDds *adapterDds,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc,
const std::shared_ptr<Buildings::Interface::Ftc> &bldFtc)
{
bool success = m_mosw->init(map, adapterDds);
if (map)
{
connect(map, &Map::beginDestroy, this, &MapObjectSelectionLtsDialog::onMapDestroyed, Qt::UniqueConnection);
connect(map, &Map::escapePressed, this, &MapObjectSelectionLtsDialog::onEscapePressed, Qt::UniqueConnection);
}
m_ppmDtc = ppmDtc;
m_ppmFtc = ppmFtc;
m_bldFtc = bldFtc;
return success;
}
void MapObjectSelectionLtsDialog::enableServiceMonitorRequest(bool enable)
{
enableServiceMonitorRequestSendToServiceMonitor(enable);
enableServiceMonitorRequestCheckButton(enable);
}
void MapObjectSelectionLtsDialog::enableServiceMonitorRequestSendToServiceMonitor(bool enable)
{
// Import-Button is used as Open in Service Monitor-Button
QPushButton *btn = m_buttonBox->getButton(LtsWidgets::DialogButton::Import);
if (!btn)
return;
btn->setVisible(enable);
btn->setText(tr("Open in Service Monitor") + QStringLiteral(" ")); // since QMenu is added
btn->setIcon(QIcon(QLatin1String("icon:player_equipment_check.svg")));
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
if (!btn->menu())
{
QMenu *menu = new QMenu(this);
QAction *replaceAction = new QAction(tr("Replace in Service Monitor"), this);
QAction *addAction = new QAction(tr("Add to current Service Monitor"), this);
menu->addAction(replaceAction);
menu->addAction(addAction);
btn->setMenu(menu);
connect(replaceAction, &QAction::triggered, this, &MapObjectSelectionLtsDialog::onServiceMonitorRequestedReplace);
connect(addAction, &QAction::triggered, this, &MapObjectSelectionLtsDialog::onServiceMonitorRequestedAdd);
}
}
void MapObjectSelectionLtsDialog::enableServiceMonitorRequestCheckButton(bool enable)
{
// Export-Button is used as Check-Button
QPushButton *btn = m_buttonBox->getButton(LtsWidgets::DialogButton::Export);
if (!btn)
return;
btn->setVisible(enable);
btn->setEnabled(m_ppmFtc.get());
// Added QStringLiteral is workaround for REGG-3773. Author of this dialog should fix this properly.
btn->setText(tr("Check") + QStringLiteral(" "));
btn->setIcon(QIcon(QStringLiteral(":/style/dialog-ok.svg")));
if (!m_checkButtonHandler && m_ppmFtc.get())
{
m_checkButtonHandler = new ServiceMonitor::CheckButtonHandler(btn);
m_checkButtonHandler->setPpm(m_ppmDtc, m_ppmFtc);
m_checkButtonHandler->addReset();
m_checkButtonHandler->addTacticalState();
connect(m_mosw, &MapObjectSelectionWidget::visibleObjectsChanged,
this, &MapObjectSelectionLtsDialog::updateCheckButtonHandler);
// reset the buildings also:
connect(m_checkButtonHandler, &ServiceMonitor::CheckButtonHandler::combatReadyRequested,
this, &MapObjectSelectionLtsDialog::onServiceMonitorBtnCombatReadyRequested);
connect(m_checkButtonHandler, &ServiceMonitor::CheckButtonHandler::combatReadyResetContamintationRequested,
this, &MapObjectSelectionLtsDialog::onServiceMonitorBtnCombatReadyResetContaminationRequested);
connect(m_checkButtonHandler, &ServiceMonitor::CheckButtonHandler::resetContaminationRequested,
this, &MapObjectSelectionLtsDialog::onServiceMonitorBtnResetContaminationRequested);
}
}
std::vector<int> MapObjectSelectionLtsDialog::visibleParticipantIdsDds() const
{
if (!m_mosw)
return {};
return m_mosw->visibleParticipantIds();
}
void MapObjectSelectionLtsDialog::updateCheckButtonHandler()
{
if (!m_checkButtonHandler)
return;
const std::vector<int> &visiPart = visibleParticipantIdsDds();
m_checkButtonHandler->setSelectedParticipantIds(visiPart);
// [NLDEVCTRL-1357] MASIE-60: Zurücksetzen Gebäude über VorauswahlDialog - auch wenn nur Bldgs selektiert sind.
if (!m_mosw)
return;
const QVector<int> &visiBldgs = m_mosw->visibleBuildingIds();
if (visiBldgs.isEmpty())
return;
m_checkButtonHandler->enableForBuildingReset_OfMapObjectSelectionWidget();
}
void MapObjectSelectionLtsDialog::onServiceMonitorBtnCombatReadyRequested()
{
onServiceMonitorBtnVulnerabiltyResetRequested(ProjectDataManagement::VulnerabilityState_def::CombatReady, false);
}
void MapObjectSelectionLtsDialog::onServiceMonitorBtnCombatReadyResetContaminationRequested()
{
onServiceMonitorBtnVulnerabiltyResetRequested(ProjectDataManagement::VulnerabilityState_def::CombatReady, true);
}
void MapObjectSelectionLtsDialog::onServiceMonitorBtnResetContaminationRequested()
{
onServiceMonitorBtnVulnerabiltyResetRequested(ProjectDataManagement::VulnerabilityState_def::NoChange, true);
}
void MapObjectSelectionLtsDialog::onServiceMonitorBtnVulnerabiltyResetRequested( const ProjectDataManagement::VulnerabilityState &vs, bool resetContamination )
{
if (!m_mosw || !m_bldFtc)
return;
const QVector<int> &buildingIds = m_mosw->visibleBuildingIds();
if (buildingIds.empty())
return;
std::vector<Buildings::Building> buildings;
buildings.reserve(buildingIds.size());
Buildings::Building bldg;
for (int buildingId : buildingIds)
{
bldg.buildingId(buildingId);
buildings.push_back(bldg);
} // for
Buildings::SetBuildingStatesRequest request;
request.buildings(buildings);
request.vulnerabilityState(vs);
request.resetContamination(resetContamination);
m_requestHelper->addRequest([this, request]()
{
return m_bldFtc->setBuildingStatesRequest(request, this);
});
m_requestHelper->startRequests();
}
void MapObjectSelectionLtsDialog::onSetBuildingStatesReply(const Core::FunctionReplyObject &reply)
{
m_requestHelper->requestReply(reply);
}
void MapObjectSelectionLtsDialog::reset()
{
m_mosw->reset();
}
void MapObjectSelectionLtsDialog::setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList)
{
m_mosw->setMapObjectsToDisplay(mapObjList);
}
void MapObjectSelectionLtsDialog::setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds)
{
m_mosw->setMapObjectsToDisplay(uniqueMapIds);
}
void MapObjectSelectionLtsDialog::onMapDestroyed()
{
// commit suicide";
delete this;
}
void MapObjectSelectionLtsDialog::onEscapePressed()
{
if (!m_mosw)
return;
m_mosw->clearSelectionOfMapObjects(true);
}
void MapObjectSelectionLtsDialog::onServiceMonitorRequestedReplace()
{
const QVector<int> allEquipmentNumbers = m_mosw->visibleEquipmentNumbers();
if (allEquipmentNumbers.isEmpty())
return;
emit serviceMonitorRequested(allEquipmentNumbers, true);
}
void MapObjectSelectionLtsDialog::onServiceMonitorRequestedAdd()
{
const QVector<int> allEquipmentNumbers = m_mosw->visibleEquipmentNumbers();
if (allEquipmentNumbers.isEmpty())
return;
emit serviceMonitorRequested(allEquipmentNumbers, false);
}
//----------------------------------------------------------------------------
// MapObjectSelectionWidget
//----------------------------------------------------------------------------
MapObjectSelectionWidget::MapObjectSelectionWidget(QWidget *parent)
: BaseClass(parent)
, m_ui(new Ui::MapObjectSelectionDialog)
, m_logger(getLogger("MapObjectSelectionWidget"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->setupUi(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
MapObjectSelectionWidget::~MapObjectSelectionWidget()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// 'clear' current selection and MapObjectIndicator
clearSelectionOfMapObjects(true);
// delete ui:
delete m_ui;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool MapObjectSelectionWidget::init(Map *map, AdapterDds *adapterDds)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!map)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no map";
return false;
}
if (!adapterDds)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no adapterDds";
return false;
}
m_map = map;
m_adapterDds = adapterDds;
connect(m_adapterDds.data(), &AdapterDds::mapObjectChanged, this, &MapObjectSelectionWidget::updateMapObject, Qt::UniqueConnection);
connect(m_adapterDds.data(), &AdapterDds::mapObjectRemoved, this, &MapObjectSelectionWidget::onMapObjectRemoved, Qt::UniqueConnection);
connect(&m_map->partyIdToColorFunctor(), &PartyIdToColorFunctor::partyChanged,
this, &MapObjectSelectionWidget::onPartyIdsChanged, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void MapObjectSelectionWidget::reset()
{
if (m_map.isNull())
return;
// clear selection and MapObjectIndicator:
clearSelectionOfMapObjects(true);
// clear model:
if (m_mapObjectModel)
{
m_mapObjectModel->clear();
m_mapObjectModel->deleteLater();
}
}
void MapObjectSelectionWidget::clearSelectionOfMapObjects(bool clearMapObjectIndicator)
{
if (!m_mapObjectModel)
return;
if (!m_map)
return;
const QVector<UniqueMapId> &uniqueMapIds = m_mapObjectModel->allMapObjects();
if (uniqueMapIds.isEmpty())
return;
ObjectFactory &objFac = m_map->objectFactory();
for (auto uniqueMapId : uniqueMapIds)
{
RefPointer<AbstractMapObject> mapObj = objFac.get<AbstractMapObject>(uniqueMapId);
if (mapObj)
{
mapObj->setSelected(false);
mapObj->updateView();
}
}
if (clearMapObjectIndicator)
{
// remove MapObjectIndicator:
m_map->objectIndicator().remove();
}
}
void MapObjectSelectionWidget::setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList)
{
// 'clear' current selection:
clearSelectionOfMapObjects(false);
// apply Ids:
QVector<UniqueMapId> uniqueMapIds;
uniqueMapIds.reserve(mapObjList.size());
for (const auto &mapObj : mapObjList)
if (mapObj && (isUniqueMapIdValid(mapObj->uniqueMapId())))
uniqueMapIds.append(mapObj->uniqueMapId());
setMapObjectsToDisplay(uniqueMapIds);
}
void MapObjectSelectionWidget::setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapIds.size()=" << uniqueMapIds.size();
if (m_map.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no map";
return;
}
if (!m_mapObjectModel)
{
// initialize model:
m_mapObjectModel = QPointer<MapObjectModel>(new MapObjectModel(this));
m_mapObjectModel->initModel(m_map);
// proxyModel:
auto proxyModel = new MapObjectProxyModel(this);
proxyModel->setSourceModel(static_cast<MapObjectModel*>(m_mapObjectModel.data()));
proxyModel->setDynamicSortFilter(false);
// set view: (LtsDataView)
// m_ui->ltsDataView->seamless();
m_ui->ltsDataView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
m_ui->ltsDataView->selectCustomView();
m_ui->ltsDataView->setModel(proxyModel, [this]()
{
MapObjectCustomView *mocw = new MapObjectCustomView(this);
return mocw;
});
#ifndef LTS_DEBUG
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::UNIQUE_MAP_ID);
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::SIDC);
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::PARTICIPANT_ID);
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::TYPE_ID);
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::VULNERABILITY_STATE_ID);
#endif
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::SINGLE_DESCRIPTION);
m_ui->ltsDataView->hideColumn(MapObjectModel::Columns::PICTURE); // do not "print" the picture
// connect signals of TableView/CustomView:
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::clicked, this, &MapObjectSelectionWidget::onTableViewClicked);
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalEntered, this, &MapObjectSelectionWidget::onMapObjectEntered);
// signal-signal
connect(proxyModel, &MapObjectProxyModel::rowsInserted, this, &MapObjectSelectionWidget::visibleObjectsChanged);
connect(proxyModel, &MapObjectProxyModel::rowsRemoved, this, &MapObjectSelectionWidget::visibleObjectsChanged);
connect(proxyModel, &MapObjectProxyModel::modelReset, this, &MapObjectSelectionWidget::visibleObjectsChanged);
}
// old approach:
// add just the new items to avoid unneccessary m_adapterDds->unifiedMapObjectData
// leads to many GUI updates (CustomView of LtsDataView and therefore a few min for ~5000 entries.
// So simply replace completely.
// fill completely new:
QVector<QSharedPointer<MapObjectData>> mapObjectDataVec;
mapObjectDataVec.reserve(uniqueMapIds.size());
UnifiedMapObjectData umodOut;
for (const auto uniqueMapId : uniqueMapIds)
{
if (m_adapterDds->unifiedMapObjectData(uniqueMapId, umodOut))
mapObjectDataVec.append(dataFromUnified(uniqueMapId, umodOut));
else
ERROR_LOG(m_logger) << LOGFUNCTION << " unifiedMapObjectData failed, uniqueMapId=" << uniqueMapId;
} // for
m_mapObjectModel->setMapObjectData(mapObjectDataVec);
// so the data gets sorted by equipment number + party
m_ui->ltsDataView->setSortIndicator(MapObjectModel::Columns::EQUIPMENT_NUMBER, Qt::AscendingOrder);
m_ui->ltsDataView->setSortIndicator(MapObjectModel::Columns::PARTY, Qt::AscendingOrder);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueMapIds.size()=" << uniqueMapIds.size();
}
std::vector<int> MapObjectSelectionWidget::visibleParticipantIds() const
{
std::vector<int> ret;
if (!m_mapObjectModel)
return ret;
const auto filterProxy = m_ui->ltsDataView->proxyModel();
const int rowCount = filterProxy->rowCount();
ret.reserve(rowCount);
for (int r = 0; r < rowCount; ++r)
{
const QModelIndex idx = filterProxy->mapToSource(filterProxy->index(r, 0, QModelIndex()));
if (!idx.isValid())
continue;
const auto &item = m_mapObjectModel->getRowData(idx.row());
if (!item || item->m_participantId <= 0)
continue;
ret.push_back(item->m_participantId);
}
return ret;
}
QVector<int> MapObjectSelectionWidget::visibleEquipmentNumbers() const
{
QVector<int> ret;
if (!m_mapObjectModel)
return ret;
const auto filterProxy = m_ui->ltsDataView->proxyModel();
const int rowCount = filterProxy->rowCount();
ret.reserve(rowCount);
for (int r = 0; r < rowCount; ++r)
{
const QModelIndex idx = filterProxy->mapToSource(filterProxy->index(r, 0, QModelIndex()));
if (!idx.isValid())
continue;
const auto &item = m_mapObjectModel->getRowData(idx.row());
if (!item || item->m_equipmentNumber <= 0)
continue;
ret += item->m_equipmentNumber;
}
return ret;
}
QVector<int> MapObjectSelectionWidget::visibleBuildingIds() const
{
QVector<int> ret;
if (!m_mapObjectModel)
return ret;
const auto filterProxy = m_ui->ltsDataView->proxyModel();
const int rowCount = filterProxy->rowCount();
ret.reserve(rowCount);
for (int r = 0; r < rowCount; ++r)
{
const QModelIndex idx = filterProxy->mapToSource(filterProxy->index(r, 0, QModelIndex()));
if (!idx.isValid())
continue;
const auto &item = m_mapObjectModel->getRowData(idx.row());
if (!item || item->m_buildingId<0)
continue;
if (!ret.contains(item->m_buildingId)) // avoid duplicates
ret.push_back(item->m_buildingId);
}
return ret;
}
bool MapObjectSelectionWidget::addMapObject(const UniqueMapId &uniqueMapId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapId=" << uniqueMapId;
if (m_map.isNull() || m_adapterDds.isNull() || m_mapObjectModel.isNull())
return false;
if (m_mapObjectModel->contains(uniqueMapId))
return false;
UnifiedMapObjectData umodOut;
if (m_adapterDds->unifiedMapObjectData(uniqueMapId, umodOut))
return m_mapObjectModel->addMapObjectData(dataFromUnified(uniqueMapId, umodOut));
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueMapId=" << uniqueMapId;
return false;
}
bool MapObjectSelectionWidget::updateMapObject(const UniqueMapId &uniqueMapId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapId=" << uniqueMapId;
if (m_map.isNull() || m_adapterDds.isNull() || !m_mapObjectModel)
return false;
if (!m_mapObjectModel->contains(uniqueMapId))
return true;
UnifiedMapObjectData umodOut;
if (m_adapterDds->unifiedMapObjectData(uniqueMapId, umodOut))
return m_mapObjectModel->updateMapObjectData(dataFromUnified(uniqueMapId, umodOut));
ERROR_LOG(m_logger) << LOGFUNCTION << " unifiedMapObjectData failed, uniqueMapId=" << uniqueMapId;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueMapId=" << uniqueMapId;
return false;
}
void MapObjectSelectionWidget::onMapObjectRemoved(UniqueMapId uniqueMapId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapId=" << uniqueMapId;
if (!m_mapObjectModel)
return;
m_mapObjectModel->remove(uniqueMapId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueMapId=" << uniqueMapId;
}
void MapObjectSelectionWidget::onPartyIdsChanged()
{
if (!m_mapObjectModel)
return;
const QVector<UniqueMapId> &uniqueMapIds = m_mapObjectModel->allMapObjects();
this->setMapObjectsToDisplay(uniqueMapIds);
}
void MapObjectSelectionWidget::onTableViewClicked(const QModelIndex &index)
{
if (!m_mapObjectModel)
return;
onMapObjectClicked(m_mapObjectModel->uniqueMapIdOfIndex(index));
}
void MapObjectSelectionWidget::onMapObjectClicked(UniqueMapId uniqueMapId)
{
if (m_map && QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier))
{
RefPointer<AbstractMapObject> mapObj = m_map->objectFactory().get(uniqueMapId);
if (!mapObj)
return;
BoundingBox bbox;
mapObj->boundingBox(bbox);
if (bbox.isValid())
{
m_map->setCenterPoint(bbox.center().toPointF());
m_map->objectIndicator().remove();
return;
}
}
emit mapObjectsClicked(QVector<UniqueMapId>() << uniqueMapId);
}
void MapObjectSelectionWidget::onMapObjectEntered(const QModelIndex &index)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_mapObjectModel)
return;
if (m_map.isNull())
return;
const UniqueMapId uniqueMapId = m_mapObjectModel->uniqueMapIdOfIndex(index);
//
// MapObjectIndicator
//
m_map->objectIndicator().setMapObjectToPointTo(uniqueMapId);
//
// setSelected
//
// remove old:
ObjectFactory &objFac = m_map->objectFactory();
{
for (auto uid : qAsConst(m_selectedMapObjects))
{
RefPointer<AbstractMapObject> mapObj = objFac.get<AbstractMapObject>(uid);
if (mapObj)
{
mapObj->setSelected(false);
mapObj->updateView();
}
}
}
m_selectedMapObjects.clear();
{
m_selectedMapObjects.insert(uniqueMapId);
RefPointer<AbstractMapObject> mapObj = objFac.get<AbstractMapObject>(uniqueMapId);
if (mapObj)
{
mapObj->setSelected(true);
mapObj->updateView();
}
}
}
QSharedPointer<MapObjectData> MapObjectSelectionWidget::dataFromUnified(UniqueMapId uniqueMapId,
const UnifiedMapObjectData &umod)
{
// transfer data from Adapter/UnifiedMapObjectData to Model/MapObjectData;
QSharedPointer<MapObjectData> mod = QSharedPointer<MapObjectData>(new MapObjectData(uniqueMapId));
mod->m_equipmentNumber = umod.m_equipmentNumber;
mod->m_partyId = umod.m_partyId;
mod->m_partyName = m_map->partyIdToColorFunctor().partyIdToName(mod->m_partyId);
mod->m_participantId = umod.m_participantData.m_participantId;
mod->m_typeId = umod.m_participantData.m_typeId;
mod->m_typeName = umod.m_participantData.m_typeName.isEmpty() ? QStringLiteral("-") : umod.m_participantData.m_typeName;
mod->m_vulnerabilityState = umod.m_participantData.m_vulnerabilityState;
mod->m_vulnerabilityString = umod.m_participantData.m_vulnerabilityString.isEmpty() ? QStringLiteral("-") : umod.m_participantData.m_vulnerabilityString;
mod->m_buildingId = umod.m_buildingData.buildingId;
mod->m_description1 = umod.m_description1;
mod->m_description2 = umod.m_description2;
mod->m_symDataToRender = umod.m_symDataToRender;
mod->setImage(umod.m_image);
return mod;
}
} // namespace SituationMap
@@ -0,0 +1,226 @@
/**
* @RDE_HEADER@
* Class MapObjectSelection
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include <SituationMap/sitmapdds_export.h>
#include <Map/map.h>
#include <LtsWidgets/lts_dialog.h>
#include <Common/situation_map_logging.h>
// BLD
#include <Buildings/bld_ftc.h>
// PPM
#include <ParticipantManagement/ppm_ftc.h>
// SMO
#include <ServiceMonitor/Gui/Monitors/smo_check_button_handler.h>
// Qt
#include <QPointer>
#include <QDialog>
// forward
class QItemSelection;
class QGridLayout;
namespace Ui
{
class MapObjectSelectionDialog;
}
//----------------------------------------------------------------------------
namespace SituationMap
{
// forward
class AdapterDds;
class MapObjectModel;
class MapObjectData;
struct UnifiedMapObjectData;
//----------------------------------------------------------------------------
// Test Dialog
//----------------------------------------------------------------------------
// Forward:
class MapObjectSelectionWidget;
//----------------------------------------------------------------------------
// MapObjectSelectionQDialog - Qt-Dialog
//----------------------------------------------------------------------------
class SITMAPDDS_EXPORT MapObjectSelectionQDialog : public QDialog
{
Q_OBJECT
using BaseClass = QDialog;
public:
explicit MapObjectSelectionQDialog(QWidget *parent = nullptr);
~MapObjectSelectionQDialog() = default;
bool init(Map *map, AdapterDds *adapterDds);
void reset();
void setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList);
void setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds);
protected Q_SLOTS:
void onMapDestroyed();
protected:
MapObjectSelectionWidget *m_mosw = nullptr;
};
//----------------------------------------------------------------------------
// MapObjectSelectionLtsDialog - LtsDialog
//----------------------------------------------------------------------------
class SITMAPDDS_EXPORT MapObjectSelectionLtsDialog : public LtsWidgets::LtsDialog
, protected Buildings::Interface::Ftc::SetBuildingStatesReplyHandler
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsDialog;
public:
explicit MapObjectSelectionLtsDialog(QWidget *parent = nullptr,
LtsWidgets::ButtonCombination buttonCombination = LtsWidgets::ButtonCombination::CloseOnly);
~MapObjectSelectionLtsDialog() = default;
bool init(Map *map, AdapterDds *adapterDds,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc,
const std::shared_ptr<Buildings::Interface::Ftc> &bldFtc);
void enableServiceMonitorRequest(bool enable);
void reset();
void setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList);
void setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds);
Q_SIGNALS:
void mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds);
void serviceMonitorRequested(const QVector<int> &equipmentNumbers, bool replace);
protected Q_SLOTS:
void onMapDestroyed();
void onEscapePressed();
void onServiceMonitorRequestedReplace();
void onServiceMonitorRequestedAdd();
void updateCheckButtonHandler();
void onServiceMonitorBtnCombatReadyRequested();
void onServiceMonitorBtnCombatReadyResetContaminationRequested();
void onServiceMonitorBtnResetContaminationRequested();
void onServiceMonitorBtnVulnerabiltyResetRequested(const ProjectDataManagement::VulnerabilityState &vs, bool resetContamination);
protected:
virtual void onSetBuildingStatesReply(const Core::FunctionReplyObject &reply) override;
protected:
void enableServiceMonitorRequestSendToServiceMonitor(bool enable);
void enableServiceMonitorRequestCheckButton(bool enable);
std::vector<int> visibleParticipantIdsDds() const;
MapObjectSelectionWidget *m_mosw = nullptr;
// emulate Single Service Equipment Check:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
std::shared_ptr<Buildings::Interface::Ftc> m_bldFtc;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
ServiceMonitor::CheckButtonHandler *m_checkButtonHandler;
private:
void retranslate() override;
};
//----------------------------------------------------------------------------
// MapObjectSelectionWidget
//----------------------------------------------------------------------------
class MapObjectSelectionWidget : public QWidget
{
Q_OBJECT
using BaseClass = QWidget;
/*! \name Construction, Destruction */
//@{
public:
/*! @brief Constructor */
explicit MapObjectSelectionWidget(QWidget *parent = nullptr);
/*! @brief Destructor */
virtual ~MapObjectSelectionWidget();
bool init(Map *map, AdapterDds *adapterDds);
void reset();
//@}
void setMapObjectsToDisplay(const Map::RefPointerMapObjectList &mapObjList);
void setMapObjectsToDisplay(const QVector<UniqueMapId> &uniqueMapIds);
std::vector<int> visibleParticipantIds() const;
QVector<int> visibleEquipmentNumbers() const;
QVector<int> visibleBuildingIds() const;
signals:
void mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds);
void visibleObjectsChanged();
protected slots:
/**
* @brief clearSelectionOfMapObjects
* If new widgets appear, the other widgtes are re-arranged.
* This can swallow some leaveEvents.
* To ensure a consistent state, the selection of all MapObjects of the model can be removed.
* @param clearMapObjectIndicator removes MapObjectIndicator
*
*/
void clearSelectionOfMapObjects(bool clearMapObjectIndicator);
void onMapObjectRemoved(UniqueMapId uniqueMapId);
void onPartyIdsChanged();
// TableView
void onTableViewClicked(const QModelIndex &index);
// CustomView
void onMapObjectClicked(UniqueMapId uniqueMapId);
void onMapObjectEntered(const QModelIndex &index);
protected:
bool addMapObject(const UniqueMapId &uniqueMapId);
bool updateMapObject(const UniqueMapId &uniqueMapId);
QSharedPointer<MapObjectData> dataFromUnified(UniqueMapId uniqueMapId,
const UnifiedMapObjectData &umod);
private:
friend class MapObjectSelectionLtsDialog;
QPointer<MapObjectModel> m_mapObjectModel;
QPointer<Map> m_map;
QPointer<AdapterDds> m_adapterDds;
QSet<UniqueMapId> m_selectedMapObjects; //typically just one item
Ui::MapObjectSelectionDialog *m_ui;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
};
} // namespace SituationMap