/** * @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 #include #include #include #include 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 &ppmDtc, const std::shared_ptr &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 &checkedParticipants = QSet(), 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 &selectItem, const QModelIndex &parent = QModelIndex()); QModelIndexList getIndexesByParticipantIds(const std::vector &participantIds, const QModelIndex &parent = QModelIndex()) const; void setRowsCheckable(bool bCheckable); void setUnitsSelectable(bool bSelectable) { m_bUnitsSelectable = bSelectable; } bool setCheckStateForParticipants(const QSet &checkedParticipants, Qt::CheckState cs); ParticipantManagement::ParticipantData getParticipantData(const QModelIndex &idx) const; std::vector participantData(bool bOnlyModified = true) const; QSet participantIds() const; QSet checkStateForParticipants(Qt::CheckState cs) const; QVector 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 &tmap, QHash> &parentId2id) const; std::vector getChildrenOf(NGLTreeItem *item, int parentId, int hierarchyNumber, bool bOnlyModifed, int &highestModId) const; bool updateChildrenOf(int parentId, NGLTreeItem *parent, const QHash> &parentId2id, const QHash &tmap); void insertChildrenOf(int parentId, NGLTreeItem *parent, const QModelIndex &parentIdx, const QHash> &parentId2id, const QHash &tmap, const QSet &checkedParticipants, Qt::CheckState cs); bool isParentOf(const NGLTreeItem *item, int participantId) const; QSet participantIds(NGLTreeItem *parentItem) const; QSet checkState(CheckedTreeItem *parentItem, Qt::CheckState cs) const; QVector usedEquipmentNumbers(NGLTreeItem *parentItem) const; void setCheckState(CheckedTreeItem *parentItem, const QSet &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 m_dataToDelete; QTimer *m_missingSuperiorIdTimer; QSet m_missingSuperiorId; QSet m_usedTypeIds; QSet m_usedTypeClassIds; FiringUnitValidator *m_firingUnitValidator; }; //============================================================================================================================= // PARTICIPANTTREEFILTERPROXYMODEL //============================================================================================================================= class PPMCOMMON_EXPORT ParticipantTreeFilterProxyModel : public LtsWidgets::LtsColumnFilterProxyModel { Q_OBJECT public: using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel; void setAllowedTypes(const QSet &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 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 m_mapToSource; QHash m_mapFromSource; QHash m_mapToSourceInternal; QHash m_mapFromSourceInternal; QHash m_mapToSourceFiltered; QHash m_mapFromSourceFiltered; QVector 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)