Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+422
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
* @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
|
||||
Reference in new issue
Block a user