423 lines
14 KiB
C++
Executable File
423 lines
14 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* HMI Plugin for ParticipantManagement - Participant Pool Model
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Patric Karwat, SLSE, 2016-10-17
|
|
*/
|
|
|
|
#include "participant_pool_model.h"
|
|
#include <Plugins/ParticipantManagement/ppm_mime_datas.h>
|
|
#include <ParticipantManagement/ppm_translation.h>
|
|
#include <LtsSession/lts_session_data_dds.h>
|
|
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
|
|
#include <Symbology/symbol_data_to_render_role.h>
|
|
|
|
#include <QMimeData>
|
|
#include <QTimer>
|
|
|
|
namespace ParticipantManagement
|
|
{
|
|
//----------------------------------------------------------------------------
|
|
ParticipantPoolModel::ParticipantPoolModel(QObject *parent,
|
|
LtsSession::LtsSessionDataDds *session,
|
|
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
|
|
bool asSupportService)
|
|
: LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>({tr("Delete"),
|
|
tr("Designator/Identifier"),
|
|
tr("Type Class"),
|
|
tr("Type"),
|
|
tr("Participant Id") },
|
|
parent)
|
|
, AdvancedSymbology::TableModelSymbolRenderer<ParticipantPoolModel>(ColDesignatorIdentifier)
|
|
, m_asSupportService(asSupportService)
|
|
, m_dtc(dtc)
|
|
, m_logger(getLogger("ParticipantPoolModel"))
|
|
{
|
|
// optional
|
|
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> asb;
|
|
session->getForeignDataInterface<AdvancedSymbology::DataInterface>(asb);
|
|
AdvancedSymbology::TableModelSymbolRenderer<ParticipantPoolModel>::init(asb, this);
|
|
|
|
onReinitModel();
|
|
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
|
this, &ParticipantPoolModel::onParticipantDataChanged);
|
|
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::participantOrganisationChanged,
|
|
this, &ParticipantPoolModel::onParticipantOrganisationChanged);
|
|
m_dtc->participantOrganisations([this](const ParticipantOrganisation &org) { onParticipantOrganisationChanged(org, DataModification::eAdded); });
|
|
|
|
const ParticipantManagement::Party &party = m_dtc->party(poolPartyId());
|
|
setDefaultRoleAndColor(AdvancedSymbology::roleToRole<>(party.role()),
|
|
QColor::fromRgb(QRgb(party.color())));
|
|
}
|
|
|
|
bool ParticipantPoolModel::canRemoveRow(int row) const
|
|
{
|
|
if (row < 0 || row >= m_vecData.size())
|
|
return false;
|
|
return true;
|
|
/*
|
|
// commented out - we want to be able to also deleted detached structures.
|
|
const ParticipantManagement::ParticipantData &data = m_vecData.at(row);
|
|
if (data.id() == 0)
|
|
return true;
|
|
return !(m_participantOrganization.contains(data.id()));
|
|
*/
|
|
}
|
|
|
|
bool ParticipantPoolModel::removeRow(int row)
|
|
{
|
|
if (row < 0 || row >= m_vecData.size())
|
|
return false;
|
|
QVector<ParticipantData> datasToDelete;
|
|
ParticipantManagement::ParticipantData dataToDelete = getRowData(row);
|
|
removeRenderedSymbol(dataToDelete.id());
|
|
|
|
if (dataToDelete.id() != 0) //remove from DDS
|
|
{
|
|
dataToDelete.isDeleted(true);
|
|
datasToDelete.append(dataToDelete);
|
|
}
|
|
|
|
LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>::removeRow(row);
|
|
emit modifyParticipantData(datasToDelete, QString());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
QVariant ParticipantPoolModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!indexIsValid(index) || (role != Qt::DisplayRole && role != Qt::DecorationRole))
|
|
return QVariant();
|
|
|
|
const ParticipantManagement::ParticipantData &participantData = m_vecData.at(index.row());
|
|
if (role == Qt::DecorationRole)
|
|
return decorationData(index, participantData.id());
|
|
|
|
switch (index.column())
|
|
{
|
|
case ColRemove:
|
|
break;
|
|
case ColDesignatorIdentifier:
|
|
return QString(QString::fromStdString(participantData.designator()) + QLatin1Char('/') +
|
|
QString::fromStdString(participantData.tacticalIdentifier()));
|
|
case ColTypeClass:
|
|
return ParticipantManagement::toString(m_dtc->type(participantData.typeId()).typeClass());
|
|
case ColType:
|
|
return ParticipantManagement::trTypeName(m_dtc->type(participantData.typeId()).name());
|
|
case ColParticipantId:
|
|
return participantData.id();
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
int ParticipantPoolModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
int cc = LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>::columnCount(parent);
|
|
#ifndef LTS_DEBUG
|
|
// participant id only in dev mode
|
|
cc -= 1;
|
|
#endif
|
|
return cc;
|
|
}
|
|
|
|
QMimeData *ParticipantPoolModel::mimeData(const QModelIndexList &indexes) const
|
|
{
|
|
// nicht != 1 da eine komplette Zeile markiert ist
|
|
if (indexes.size() < 1)
|
|
return nullptr;
|
|
|
|
const QModelIndex &idx = indexes.first();
|
|
if (!indexIsValid(idx))
|
|
return nullptr;
|
|
|
|
const ParticipantData &data = m_vecData.at(idx.row());
|
|
if (data.id() == 0)
|
|
return nullptr;
|
|
|
|
const QByteArray encodedData(QByteArray::number(data.id()));
|
|
QMimeData *mimeData = new QMimeData;
|
|
const QString mimeType = m_participantOrganization.contains(data.id()) ? ParticipantPoolDetached : ParticipantPoolRoot;
|
|
mimeData->setData(mimeType, encodedData);
|
|
return mimeData;
|
|
}
|
|
|
|
Qt::ItemFlags ParticipantPoolModel::flags(const QModelIndex &index) const
|
|
{
|
|
Qt::ItemFlags retFlags = LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>::flags(index);
|
|
retFlags |= Qt::ItemIsDragEnabled;
|
|
retFlags |= Qt::ItemIsDropEnabled;
|
|
|
|
return retFlags;
|
|
}
|
|
|
|
|
|
bool ParticipantPoolModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
|
{
|
|
Q_UNUSED(row);
|
|
Q_UNUSED(column);
|
|
Q_UNUSED(parent);
|
|
|
|
if (action != Qt::CopyAction && action != Qt::MoveAction)
|
|
return false;
|
|
|
|
DEBUG_LOG(m_logger) << "dropMimeData: " << data->formats().join(QLatin1Char(','));
|
|
|
|
if (!data->hasFormat(ParticipantTemplateRoot) &&
|
|
!data->hasFormat(ParticipantPartyRoot) &&
|
|
!data->hasFormat(ParticipantPartyAttached))
|
|
return false;
|
|
|
|
if (data->hasFormat(ParticipantManagement::ParticipantTemplateRoot))
|
|
{
|
|
bool bOk;
|
|
const int id = data->data(ParticipantManagement::ParticipantTemplateRoot).toInt(&bOk);
|
|
if (!bOk)
|
|
return false;
|
|
emit startUnitNamer(id);
|
|
}
|
|
else // == ParticipantPartyRoot | ParticipantPartyAttached
|
|
{
|
|
const QString mimeType = data->hasFormat(ParticipantPartyRoot) ? ParticipantPartyRoot : ParticipantPartyAttached;
|
|
bool bOk;
|
|
const int id = data->data(mimeType).toInt(&bOk);
|
|
if (!bOk)
|
|
return false;
|
|
|
|
moveFromPartyToPool(id, mimeType);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
QStringList ParticipantPoolModel::mimeTypes() const
|
|
{
|
|
return { ParticipantTemplateRoot, ParticipantPartyRoot, ParticipantPartyAttached};
|
|
}
|
|
|
|
QVector<ParticipantData> ParticipantPoolModel::getPoolData() const
|
|
{
|
|
return m_dataToDelete + m_fullPoolData;
|
|
}
|
|
|
|
bool ParticipantPoolModel::onReinitModel()
|
|
{
|
|
clear();
|
|
const QMap<qint32, ParticipantManagement::Participant> participantMap(m_dtc->participants());
|
|
|
|
for (const ParticipantManagement::Participant &part : participantMap)
|
|
{
|
|
if (part.superiorId() > 0 || part.partyId() != poolPartyId() || part.isDeleted())
|
|
continue;
|
|
if (!isValidTypeClass(part.typeId()))
|
|
continue;
|
|
insertRow(part);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ParticipantPoolModel::addNewTemplateToPool(int id, const QString &designator, const QString &tactIdentifier)
|
|
{
|
|
QVector<TemplateParticipant> templateDatas;
|
|
m_dtc->templateParticipantsFromTemplateId(id, templateDatas);
|
|
|
|
//replace first UnitName
|
|
TemplateParticipant &root = templateDatas[0];
|
|
root.superiorTemplateId(0);
|
|
root.hierarchyNumber(1);
|
|
root.designator(designator.toStdString());
|
|
root.tacticalIdentifier(tactIdentifier.toStdString());
|
|
|
|
|
|
QVector<ParticipantManagement::ParticipantData> newPool;
|
|
newPool.reserve(templateDatas.size());
|
|
for (const TemplateParticipant &participant : qAsConst(templateDatas))
|
|
{
|
|
ParticipantData newData;
|
|
convertFromParticipantTemplateToParticipantData(participant, newData);
|
|
newPool.append(newData);
|
|
}
|
|
emit modifyParticipantData(newPool, QString());
|
|
return true;
|
|
}
|
|
|
|
void ParticipantPoolModel::onParticipantDataChanged(const Participant &data, DataModification modType)
|
|
{
|
|
if (!isValidTypeClass(data.typeId()))
|
|
return;
|
|
|
|
if (data.isDeleted())
|
|
modType = DataModification::eRemoved;
|
|
|
|
switch (modType)
|
|
{
|
|
case DataModification::eModified:
|
|
for (int i = 0; i < m_vecData.size(); ++i)
|
|
{
|
|
const ParticipantData &part = m_vecData.at(i);
|
|
if (part.id() == data.id())
|
|
{
|
|
DEBUG_LOG(m_logger) << "Modifed participant " << data.id() << ", old party: " << part.partyId() << ", new: " << data.partyId();
|
|
// no longer in pool?
|
|
if (data.partyId() != poolPartyId())
|
|
{
|
|
// do not call ParticipantPoolModel::removeRow() since the participant was not removed
|
|
// from within ParticipantPoolModel
|
|
// delay the remove of this participant since it can happen due to a dnd move operation
|
|
// which will cause a removeRow() afterwards and another entry will be removed then too ...
|
|
const int participantId = data.id();
|
|
QTimer::singleShot(100, this, [this, participantId]() { tryRemoveParticipantFromModel(participantId); });
|
|
}
|
|
else
|
|
{
|
|
setRowData(i, m_dtc->convertParticipantToParticipantData(data));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
// new item -> try to add
|
|
Q_FALLTHROUGH();
|
|
case DataModification::eAdded:
|
|
if (data.superiorId() != 0 && !m_participantOrganization.contains(data.id()))
|
|
return;
|
|
if (data.partyId() != poolPartyId())
|
|
return;
|
|
insertRow(data);
|
|
break;
|
|
case DataModification::eRemoved:
|
|
if (data.partyId() != poolPartyId())
|
|
return;
|
|
tryRemoveParticipantFromModel(data.id());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ParticipantPoolModel::onParticipantOrganisationChanged(const ParticipantOrganisation &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
m_participantOrganization[data.participantId()] = data;
|
|
break;
|
|
case DataModification::eRemoved:
|
|
m_participantOrganization.remove(data.participantId());
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool ParticipantPoolModel::moveFromPartyToPool(int rootParticipantId, const QString &mimeType)
|
|
{
|
|
ERROR_LOG(m_logger) << "Moving participant " << rootParticipantId << " from party to root with mime type " << mimeType;
|
|
//start with building the tree
|
|
const Participant part = m_dtc->participant(rootParticipantId);
|
|
const QVector<Participant> newParticipants = getSuperiorParticipants(part.id());
|
|
QVector<ParticipantData> dataToSend;
|
|
dataToSend.reserve(newParticipants.size());
|
|
for (const Participant &part : newParticipants)
|
|
{
|
|
ParticipantData data = m_dtc->convertParticipantToParticipantData(part);
|
|
data.partyId(poolPartyId());
|
|
if (data.id() == rootParticipantId)
|
|
{
|
|
// the new root has no superior and a hierarchy number of 1
|
|
data.superiorModId(0);
|
|
data.hierarchyNumber(1);
|
|
}
|
|
dataToSend.append(data);
|
|
}
|
|
if (dataToSend.isEmpty())
|
|
return false;
|
|
emit modifyParticipantData(dataToSend, mimeType);
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
QVector<Participant> ParticipantPoolModel::getSuperiorParticipants(int participantId)
|
|
{
|
|
Participant part = m_dtc->participant(participantId);
|
|
QVector<Participant> retParticipants;
|
|
retParticipants.append(part);
|
|
for (auto const &inferierPart : part.inferiorIds())
|
|
retParticipants.append(getSuperiorParticipants(inferierPart));
|
|
return retParticipants;
|
|
}
|
|
|
|
bool ParticipantPoolModel::convertFromParticipantTemplateToParticipantData(const TemplateParticipant &inputParticipant, ParticipantData &outPutData)
|
|
{
|
|
//No assignsState out of template
|
|
outPutData.assignState(ParticipantManagement::ParticipantAssignState::NotAssigned);
|
|
// no participantId out of template
|
|
outPutData.id(0);
|
|
|
|
outPutData.partyId(poolPartyId());
|
|
|
|
//this could be intensive.. what about the second template with equipNumbers/
|
|
if (inputParticipant.equipmentNumber() != 0)
|
|
{
|
|
outPutData.equipmentNumber(inputParticipant.equipmentNumber());
|
|
outPutData.assignState(ParticipantAssignState::HandoutExcon);
|
|
}
|
|
outPutData.hierarchyNumber(inputParticipant.hierarchyNumber());
|
|
|
|
outPutData.info() = inputParticipant.info();
|
|
outPutData.name() = inputParticipant.name();
|
|
outPutData.designator() = inputParticipant.designator();
|
|
outPutData.tacticalIdentifier(inputParticipant.tacticalIdentifier());
|
|
outPutData.symbol(inputParticipant.symbol());
|
|
|
|
outPutData.typeId(inputParticipant.typeId());
|
|
outPutData.isSimulated(false);
|
|
//modIDgames
|
|
outPutData.modId(inputParticipant.templateId());
|
|
outPutData.superiorModId(inputParticipant.superiorTemplateId());
|
|
outPutData.hierarchyNumber(inputParticipant.hierarchyNumber());
|
|
return true;
|
|
}
|
|
|
|
bool ParticipantPoolModel::isValidTypeClass(int typeId) const
|
|
{
|
|
const TypeClass tc = m_dtc->type(typeId).typeClass();
|
|
switch (tc.underlying())
|
|
{
|
|
case TypeClass_def::Unit:
|
|
return !m_asSupportService;
|
|
case TypeClass_def::SupportUnit:
|
|
return m_asSupportService;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ParticipantPoolModel::insertRow(const Participant &participant)
|
|
{
|
|
tryRenderSymbol(QString::fromStdString(participant.symbol()), participant.id());
|
|
|
|
LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>::insertRow(
|
|
m_dtc->convertParticipantToParticipantData(participant));
|
|
}
|
|
|
|
void ParticipantPoolModel::tryRemoveParticipantFromModel(int participantId)
|
|
{
|
|
for (int i = 0; i < m_vecData.size(); ++i)
|
|
{
|
|
const ParticipantData &part = m_vecData.at(i);
|
|
if (part.id() == participantId)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing participant " << participantId;
|
|
// we must not call removeRow(i) since this will trigger a ModifyRequest which removes the complete subtree ...
|
|
LtsWidgets::LtsAbstractTableModel<ParticipantManagement::ParticipantData>::removeRow(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} //namespace ParticipantManagement
|