Files
qt5-legatus-legacy/Lts/Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h
T
2026-08-13 18:33:10 +02:00

315 lines
13 KiB
C++
Executable File

/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#pragma once
#include "participant_icon_model_base.h"
#include <ParticipantManagement/logger.h>
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <nglwidgets/ngltreeitem.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QSet>
class QTreeView;
namespace ParticipantManagement
{
class CheckedTreeItem;
class FiringUnitValidator;
//=============================================================================================================================
// PARTICIPANTEDITMODEL
//=============================================================================================================================
class PPMCOMMON_EXPORT ParticipantEditModel : public ParticipantIconModelBase
{
Q_OBJECT
public:
enum Columns
{
ColDesignator,
ColIdentifier,
ColTypeClass,
ColType,
ColEquipmentNumber,
ColParticipantId,
ColInfo,
ColSign
};
class CheckedTreeItem final : public NGLTreeItem
{
public:
using NGLTreeItem::NGLTreeItem;
ParticipantData participant;
bool bIsChecked = false;
};
ParticipantEditModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
bool canDropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) override;
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
virtual bool onReinitModel(int partyId, const QSet<int> &checkedParticipants = QSet<int>(), Qt::CheckState cs = Qt::Checked);
bool insertRow(int row, const QModelIndex &parent, NGLTreeItem *item);
bool removeRow(int row, const QModelIndex &parent = QModelIndex());
bool isRowRemovable(const CheckedTreeItem *parentItem) const;
bool rowsCheckable() const { return m_bRowsAreCheckable; }
bool unitsSelectable() const { return m_bUnitsSelectable; }
int partyId() const { return m_partyId; }
void dataCommitted();
void processMissingSuperiorId();
void selectItemByParticipantId(int participantId,
const std::function<void(const QModelIndex &)> &selectItem,
const QModelIndex &parent = QModelIndex());
QModelIndexList getIndexesByParticipantIds(const std::vector<int32_t> &participantIds,
const QModelIndex &parent = QModelIndex()) const;
void setRowsCheckable(bool bCheckable);
void setUnitsSelectable(bool bSelectable) { m_bUnitsSelectable = bSelectable; }
bool setCheckStateForParticipants(const QSet<int> &checkedParticipants, Qt::CheckState cs);
ParticipantManagement::ParticipantData getParticipantData(const QModelIndex &idx) const;
std::vector<ParticipantData> participantData(bool bOnlyModified = true) const;
QSet<int> participantIds() const;
QSet<int> checkStateForParticipants(Qt::CheckState cs) const;
QVector<int> usedEquipmentNumbers() const;
CheckedTreeItem *privateData(const QModelIndex &index);
const CheckedTreeItem *privateData(const QModelIndex &index) const;
QModelIndex indexFromParticipantId(int participantId) const;
QString getHierarchyFromIndex(const QModelIndex &index) const;
protected:
void gatherParticipants(QHash<int, ParticipantData> &tmap,
QHash<int, QSet<int>> &parentId2id) const;
std::vector<ParticipantData> getChildrenOf(NGLTreeItem *item,
int parentId,
int hierarchyNumber,
bool bOnlyModifed,
int &highestModId) const;
bool updateChildrenOf(int parentId,
NGLTreeItem *parent,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, ParticipantData> &tmap);
void insertChildrenOf(int parentId,
NGLTreeItem *parent,
const QModelIndex &parentIdx,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, ParticipantData> &tmap,
const QSet<int> &checkedParticipants,
Qt::CheckState cs);
bool isParentOf(const NGLTreeItem *item, int participantId) const;
QSet<int> participantIds(NGLTreeItem *parentItem) const;
QSet<int> checkState(CheckedTreeItem *parentItem, Qt::CheckState cs) const;
QVector<int> usedEquipmentNumbers(NGLTreeItem *parentItem) const;
void setCheckState(CheckedTreeItem *parentItem, const QSet<int> &checkedParticipants, Qt::CheckState cs);
QModelIndex indexFromParticipantId(int participantId, const CheckedTreeItem *cti) const;
int participantIdFromItem(NGLTreeItem *item) const;
int equipmentNumberFromItem(NGLTreeItem *item) const;
CheckedTreeItem *searchParticipant(const NGLTreeItem *parentItem, int participantId) const;
NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const override;
QVariant getItemData(const NGLTreeItem *item) const override;
public slots:
int insertParticipant(const QModelIndex &parent, ParticipantData participantData, bool bNewParticipant);
int onInsertRow(const QModelIndex &parent, const ParticipantData &participantData);
bool onUpdateRow(const QModelIndex &index, const ParticipantData &participantData);
bool onDeleteRow(const QModelIndex &idx, bool isFirstItem = true);
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
signals:
void internalDataChanged();
protected:
int m_partyId;
bool m_bRowsAreCheckable;
bool m_bUnitsSelectable;
std::vector<ParticipantManagement::ParticipantData> m_dataToDelete;
QTimer *m_missingSuperiorIdTimer;
QSet<int> m_missingSuperiorId;
QSet<int> m_usedTypeIds;
QSet<TypeClass> m_usedTypeClassIds;
FiringUnitValidator *m_firingUnitValidator;
};
//=============================================================================================================================
// PARTICIPANTTREEFILTERPROXYMODEL
//=============================================================================================================================
class PPMCOMMON_EXPORT ParticipantTreeFilterProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setAllowedTypes(const QSet<int> &allowedTypes);
void setSourceModel(QAbstractItemModel *sourceModel) override;
int partyId() const { return m_sourceModel ? m_sourceModel->partyId() : -1; }
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
bool filterTypeRecursive(const ParticipantEditModel::CheckedTreeItem *item) const;
#endif
private:
QSet<int> m_allowedTypes;
ParticipantEditModel *m_sourceModel{nullptr};
}; // class ParticipantTreeFilterProxyModel
//=============================================================================================================================
// PARTICIPANTTABLEFILTERPROXYMODEL
//=============================================================================================================================
/**
* @brief The ParticipantTableFilterProxyModel class enables a hierarchical tree model of
* participants to be treated like a flat table model.
*
* Important connect statements that must be implemented are:
* - LtsDataView::filterChanged -> onFilter()
* - LtsDataView::sortOrderChanged -> onSort()
* - ParticipantEditModel::internalDataChanged -> init()
* In order to keep the selection after sorting, LtsDataView::sortOrderChanged can be connected to
* another function that handles that and calls onSort() instead. Otherwise, after sorting, the same
* row will be selected with most likely a different tree item than the one selected before sorting.
*
* When using this model in parallel to a standard tree model, in order to have two views that are
* consistent with each other, additional connects and workarounds are necessary. Connects include:
* - LtsDataView::filterChanged -> some function that asserts consistency
* - LtsDataView::selectionChanged -> some function that asserts consistency
* An important workaround is required when the party is changed (s.
* ParticipantEdit::onPartyChanged).
*/
class PPMCOMMON_EXPORT ParticipantTableFilterProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
struct SortData
{
bool isActive{false};
int column{-1};
Qt::SortOrder order{Qt::DescendingOrder};
bool ascending() const
{
return order == Qt::AscendingOrder;
}
bool descending() const
{
return order == Qt::DescendingOrder;
}
QString toString()
{
QString str{QStringLiteral("active=")};
str += isActive ? QStringLiteral("true") : QStringLiteral("false");
str += QStringLiteral(", column=") + QString::number(column) + QStringLiteral(", order=");
str += order == Qt::DescendingOrder ? QStringLiteral("Descending") : QStringLiteral("Ascending");
return str;
}
}; // struct SortData
explicit ParticipantTableFilterProxyModel(QObject *parent = nullptr);
void init();
void resetMapping();
void disableSorting() { m_sortData.isActive = false; }
void setSourceModel(QAbstractItemModel *sourceModel) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
bool isFilterActive() const { return m_isFilterActive; }
bool hasChildren(const QModelIndex &parent) const override;
SortData sortData() const { return m_sortData; }
protected:
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool filterAcceptsRowInternal(int sourceRow, const QModelIndex &sourceParent) const;
private:
/**
* @brief mapTreeToTable initializes m_mapFromSource and m_mapToSource. Do NOT USE this method
* directly! Call init() instead.
* @param parent index of the parent in the source model
* @param row parent's child at rowth position
* @return current row count
*/
int mapTreeToTable(const QModelIndex &parent = QModelIndex(), int row = 0);
public slots:
void onFilter();
void onSort(int column, Qt::SortOrder order);
private:
QHash<int, QModelIndex> m_mapToSource;
QHash<QModelIndex, int> m_mapFromSource;
QHash<int, QModelIndex> m_mapToSourceInternal;
QHash<QModelIndex, int> m_mapFromSourceInternal;
QHash<int, QModelIndex> m_mapToSourceFiltered;
QHash<QModelIndex, int> m_mapFromSourceFiltered;
QVector<int> m_sortMap;
bool m_isFilterActive{false};
SortData m_sortData;
ParticipantEditModel *m_sourceModel{nullptr};
NGL::INGLLogger &m_logger;
}; // class ParticipantTableFilterProxyModel
} //namespace ParticipantManagement
Q_DECLARE_METATYPE(ParticipantManagement::ParticipantData)