From 713f38c44bbf7158fffc8eee17846655465047ff Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 2 Nov 2023 10:51:12 +0100 Subject: [PATCH] Refs #19533: Add filter to status layout properly Signed-off-by: JesusPoderoso --- include/fastdds_monitor/Engine.h | 3 + include/fastdds_monitor/backend/Listener.h | 4 +- .../backend/SyncBackendConnection.h | 4 + .../model/tree/ProblemTreeItem.h | 11 ++ .../model/tree/ProblemTreeModel.h | 27 ++++ mock/complex_mock/database/Database.cpp | 2 +- qml/DomainGraphLayout.qml | 1 - qml/ProblemTreeView.qml | 55 +++++--- qml/ProblemTreeViewItem.qml | 27 ++-- qml/StatusLayout.qml | 57 ++++++--- src/Engine.cpp | 119 ++++++++++++++---- src/backend/Listener.cpp | 2 +- src/backend/SyncBackendConnection.cpp | 6 + src/model/tree/ProblemTreeItem.cpp | 26 ++++ src/model/tree/ProblemTreeModel.cpp | 89 +++++++++++++ 15 files changed, 353 insertions(+), 80 deletions(-) diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index 8ea5e361..d688a43c 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -749,6 +749,9 @@ public slots: //! Data Model for Fast DDS Monitor problem view. Collects all entities problems detected by the monitor service models::ProblemTreeModel* problem_model_; + //! Display and allow to filter Model for Fast DDS Monitor problem view. + models::ProblemTreeModel* problem_proxy_model_; + //! TODO models::ListModel* source_entity_id_model_; diff --git a/include/fastdds_monitor/backend/Listener.h b/include/fastdds_monitor/backend/Listener.h index 49f2d424..bc743928 100644 --- a/include/fastdds_monitor/backend/Listener.h +++ b/include/fastdds_monitor/backend/Listener.h @@ -91,8 +91,8 @@ class Listener : public PhysicalListener EntityId datawriter_id, const Status& status) override; - //! Callback when a problem is reported - void on_problem_reported( + //! Callback when a status problem is reported + void on_status_reported( EntityId domain_id, EntityId entity_id, StatusKind data_kind) override; diff --git a/include/fastdds_monitor/backend/SyncBackendConnection.h b/include/fastdds_monitor/backend/SyncBackendConnection.h index b48633a2..d7e82fae 100644 --- a/include/fastdds_monitor/backend/SyncBackendConnection.h +++ b/include/fastdds_monitor/backend/SyncBackendConnection.h @@ -117,6 +117,10 @@ class SyncBackendConnection std::string get_name( backend::EntityId id); + //! Get the status level of an entity from the Backend by calling \c get_status + StatusLevel get_status( + backend::EntityId id); + //! Get the alive status of an entity from the Backend by calling \c is_active bool get_alive( backend::EntityId id); diff --git a/include/fastdds_monitor/model/tree/ProblemTreeItem.h b/include/fastdds_monitor/model/tree/ProblemTreeItem.h index 17bfcc4d..1b3eaae2 100644 --- a/include/fastdds_monitor/model/tree/ProblemTreeItem.h +++ b/include/fastdds_monitor/model/tree/ProblemTreeItem.h @@ -129,6 +129,17 @@ class ProblemTreeItem backend::StatusKind kind(); + bool is_error(); + + void is_error( + bool val); + + std::string name_str(); + + std::string value_str(); + + std::string description_str(); + //! Increases the issues counter of a top level entity item int recalculate_entity_counter(); diff --git a/include/fastdds_monitor/model/tree/ProblemTreeModel.h b/include/fastdds_monitor/model/tree/ProblemTreeModel.h index d97e941f..cd149063 100644 --- a/include/fastdds_monitor/model/tree/ProblemTreeModel.h +++ b/include/fastdds_monitor/model/tree/ProblemTreeModel.h @@ -103,6 +103,10 @@ class ProblemTreeModel : public QAbstractItemModel const QVariant& value, int role = Qt::EditRole) override; + bool removeRow( + int row, + const QModelIndex &index = QModelIndex()); + QHash roleNames() const override; public: @@ -144,6 +148,10 @@ class ProblemTreeModel : public QAbstractItemModel ProblemTreeItem* parent, ProblemTreeItem* child); + // Returns the child in the given position + ProblemTreeItem* child( + int row); + // Check if default empty value is the only element bool is_empty(); @@ -156,13 +164,32 @@ class ProblemTreeModel : public QAbstractItemModel const bool& is_error, const std::string& description); + void set_source_model( + ProblemTreeModel* source_model); + + /*! + * Filters the model if it is defined as proxy + */ + Q_INVOKABLE void filter_proxy( + const QVariant& entity_id); + private: ProblemTreeItem* internalPointer( const QModelIndex& index) const; + ProblemTreeItem* copy( + ProblemTreeItem* source, + const backend::EntityId entity_id); + + void filter( + const backend::EntityId entity_id); + private: + ProblemTreeModel* source_model_; ProblemTreeItem* root_item_; bool is_empty_; + + backend::EntityId current_filter_; }; } // namespace models diff --git a/mock/complex_mock/database/Database.cpp b/mock/complex_mock/database/Database.cpp index 6ed54462..1dffb6ee 100644 --- a/mock/complex_mock/database/Database.cpp +++ b/mock/complex_mock/database/Database.cpp @@ -362,7 +362,7 @@ void Database::callback_listener_thread_() } // add status callback - listener_->on_problem_reported(std::get<2>(entity), std::get<0>(entity), StatusKind::PROXY); + listener_->on_status_reported(std::get<2>(entity), std::get<0>(entity), StatusKind::PROXY); } } diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 39d83ac8..bbb27a41 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -1384,7 +1384,6 @@ Item "topic":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["topic"], "accum_y":accum_y } - accum_y += endpoint_height_ + elements_spacing_ } accum_y += endpoint_height_ + elements_spacing_ pending_endpoints_[pending_endpoints_.length] = endpoint diff --git a/qml/ProblemTreeView.qml b/qml/ProblemTreeView.qml index 581c75b7..7644e6ec 100644 --- a/qml/ProblemTreeView.qml +++ b/qml/ProblemTreeView.qml @@ -88,8 +88,8 @@ Flickable { Arrow } - signal problem_focused() - signal clean_filter() + property int current_filter_: -2 // backend::ID_ALL + signal problem_filtered() property int handleStyle: ProblemTreeView.Handle.TriangleSmallOutline @@ -98,6 +98,18 @@ Flickable { boundsBehavior: Flickable.StopAtBounds ScrollBar.vertical: ScrollBar {} + Component.onCompleted:{ + root.clean_filter() + } + + Connections + { + target: root.model + function onLayoutChanged() { + root.filter_model() + } + } + Connections { function onCurrentIndexChanged() { if(currentIndex) currentData = model.data(currentIndex) } } ProblemTreeViewItem { @@ -116,18 +128,12 @@ Flickable { defaultIndicator: indicatorToString(handleStyle) z: 1 - onToggled: { - root.clean_filter() - } - Connections { target: root.model ignoreUnknownSignals: true function onLayoutChanged() { tree.childCount = root.model ? root.model.rowCount(tree.parentIndex) : 0 } - - } } @@ -160,16 +166,29 @@ Flickable { } } - function focus_entity(entityId) { - var found = false - for (var i = 0; i< model.rowCount(); i++){ - if (model.data(model.index(i,0),ProblemTreeViewItem.Role.Id) == entityId) { - tree.focus(entityId) - found = true - } - } - if (found){ - root.problem_focused() + + function clean_filter() + { + root.filter_model() + model.filter_proxy(-2) + tree.unfilter() + } + + function filter_model() + { + var filter_all = -2 // backend::ID_ALL + + if (current_filter_ != filter_all) + { + current_filter_ = filter_all + root.filter_model_by_id(current_filter_) } } + + function filter_model_by_id(entityId) + { + model.filter_proxy(entityId) + root.problem_filtered() + tree.filter(entityId) + } } diff --git a/qml/ProblemTreeViewItem.qml b/qml/ProblemTreeViewItem.qml index 057266da..9ff53c30 100644 --- a/qml/ProblemTreeViewItem.qml +++ b/qml/ProblemTreeViewItem.qml @@ -86,7 +86,8 @@ Item { signal toggled() // private (internal) signals - signal focus_(int entityId) + signal filter_(int entityId) + signal unfilter_() implicitWidth: parent.width implicitHeight: childrenRect.height @@ -115,7 +116,6 @@ Item { property Component contentItem: Item { id: contentData - IconSVG { id: status_icon visible: !(currentRow.currentId === "all" && currentRow.currentKind === "INVALID") @@ -157,8 +157,8 @@ Item { anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignRight - height: parent.height elide: Text.ElideRight + height: parent.height color:currentRow.currentAlive ? currentRow.isSelectedIndex ? root.selectedItemColor : root.color : root.inactive text: currentRow.currentId != "all" && currentRow.currentKind === "INVALID" ? @@ -212,7 +212,7 @@ Item { property var currentDescription: root.model.data(currentIndex, ProblemTreeViewItem.Role.Description) property var currentAlive: root.model.data(currentIndex, ProblemTreeViewItem.Role.Alive) property Item currentItem: repeater.itemAt(index) - property bool expanded: false + property bool expanded: true property bool selected: false property int itemChildCount: root.model.rowCount(currentIndex) readonly property int depth: root.model.depth(currentIndex) @@ -254,13 +254,16 @@ Item { Connections { target: root - function onFocus_(entityId){ - if(parseInt(_prop.currentId) === parseInt(entityId)){ + function onFilter_(entityId) { + if (_prop.currentId == entityId) + { _prop.expanded = true - } else { - _prop.expanded = false } } + + function onUnfilter_(){ + _prop.expanded = false + } } Item { @@ -408,7 +411,11 @@ Item { } } - function focus (entityId) { - root.focus_(entityId) + function filter (entityId) { + root.filter_(entityId) + } + + function unfilter() { + root.unfilter_() } } diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index 4f7a6817..b240d35f 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -76,19 +76,19 @@ Item model: problemModel - onProblem_focused:{ + onProblem_filtered:{ collapse_status_layout() } - onClean_filter: { - statusLayout.clean_filter_() - } - Connections { target: statusLayout + function onClean_filter_() { + status_tree_view.clean_filter() + } + function onFocus_entity_(entityId) { - status_tree_view.focus_entity(entityId) + status_tree_view.filter_model_by_id(entityId) } } } @@ -178,25 +178,38 @@ Item } } - IconSVG { - id: filter_empty_icon - visible: !statusLayout.filter_visible_ + Rectangle { + id: filter_rect anchors.right: rect.left anchors.rightMargin: elements_spacing_ *2 anchors.verticalCenter: parent.verticalCenter - name: "filter_empty" - size: parent.height - elements_spacing_ - } + height: parent.height - elements_spacing_ + width: parent.height - elements_spacing_ + color: "transparent" - IconSVG { - id: filter_full_icon - visible: statusLayout.filter_visible_ - anchors.right: rect.left - anchors.rightMargin: elements_spacing_ *2 - anchors.verticalCenter: parent.verticalCenter - name: "filter_full" - size: parent.height - elements_spacing_ + IconSVG { + id: filter_empty_icon + visible: !statusLayout.filter_visible_ + anchors.centerIn: parent + name: "filter_empty" + size: parent.width + } + + IconSVG { + id: filter_full_icon + visible: statusLayout.filter_visible_ + anchors.centerIn: parent + name: "filter_full" + size: parent.width + } + + MouseArea { + id: filter_btn + anchors.fill: parent + onClicked: statusLayout.clean_filter_() + } } + Connections { target: statusLayout @@ -302,4 +315,8 @@ Item function filter_problem_log(entityId) { statusLayout.focus_entity_(entityId) } + function clean_filter() + { + statusLayout.clean_filter_() + } } diff --git a/src/Engine.cpp b/src/Engine.cpp index 42f74da3..070953cd 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -91,6 +91,11 @@ QObject* Engine::enable() problem_model_ = new models::ProblemTreeModel(); update_problem(backend::ID_ALL, backend::StatusKind::INVALID); + // Creates the proxy model to allow filtering + problem_proxy_model_ = new models::ProblemTreeModel(); + problem_proxy_model_->set_source_model(problem_model_); + + source_entity_id_model_ = new models::ListModel(new models::EntityItem()); fill_available_entity_id_list_(backend::EntityKind::HOST, "getDataDialogSourceEntityId"); destination_entity_id_model_ = new models::ListModel(new models::EntityItem()); @@ -113,7 +118,7 @@ QObject* Engine::enable() rootContext()->setContextProperty("issueModel", issue_model_); rootContext()->setContextProperty("logModel", log_model_); rootContext()->setContextProperty("statusModel", status_model_); - rootContext()->setContextProperty("problemModel", problem_model_); + rootContext()->setContextProperty("problemModel", problem_proxy_model_); rootContext()->setContextProperty("entityModelFirst", source_entity_id_model_); rootContext()->setContextProperty("entityModelSecond", destination_entity_id_model_); @@ -200,7 +205,12 @@ Engine::~Engine() if (problem_model_) { - //delete problem_model_; + delete problem_model_; + } + + if (problem_proxy_model_) + { + //delete problem_proxy_model_; } // Auxiliar models @@ -983,7 +993,7 @@ bool Engine::update_problem( } else { - backend::EntityStatus new_status = backend::EntityStatus::OK; + backend::StatusLevel new_status = backend::StatusLevel::OK; std::string description = backend::problem_description(kind); switch (kind) @@ -992,17 +1002,26 @@ bool Engine::update_problem( { backend::DeadlineMissedSample sample; backend_connection_.get_status_data(id, sample); - if (sample.status != backend::EntityStatus::OK) + if (sample.status != backend::StatusLevel::OK) { auto entity_item = problem_model_->getTopLevelItem( id, backend_connection_.get_name(id), - sample.status == backend::EntityStatus::ERROR, description); + sample.status == backend::StatusLevel::ERROR, description); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + if (entity_status == backend::StatusLevel::ERROR && !entity_item->is_error()) + { + entity_item->is_error(true); + } + else if (entity_status == backend::StatusLevel::WARNING && entity_item->is_error()) + { + entity_item->is_error(false); + } new_status = sample.status; std::string handle_string; auto deadline_missed_item = new models::ProblemTreeItem(id, kind, std::string("Deadline missed"), - sample.status == backend::EntityStatus::ERROR, std::string(""), description); + sample.status == backend::StatusLevel::ERROR, std::string(""), description); auto total_count_item = new models::ProblemTreeItem(id, kind, std::string("Total count:"), - sample.status == backend::EntityStatus::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.deadline_missed_status.total_count()), description); for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) { @@ -1010,7 +1029,7 @@ bool Engine::update_problem( } auto last_instance_handle_item = new models::ProblemTreeItem(id, kind, std::string("Last instance handle:"), - sample.status == backend::EntityStatus::ERROR, handle_string, description); + sample.status == backend::StatusLevel::ERROR, handle_string, description); problem_model_->addItem(deadline_missed_item, total_count_item); problem_model_->addItem(deadline_missed_item, last_instance_handle_item); problem_model_->addItem(entity_item, deadline_missed_item); @@ -1022,22 +1041,31 @@ bool Engine::update_problem( { backend::IncompatibleQosSample sample; backend_connection_.get_status_data(id, sample); - if (sample.status != backend::EntityStatus::OK) + if (sample.status != backend::StatusLevel::OK) { std::string fastdds_version = "v2.12.0"; auto entity_item = problem_model_->getTopLevelItem( id, backend_connection_.get_name(id), - sample.status == backend::EntityStatus::ERROR, description); + sample.status == backend::StatusLevel::ERROR, description); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + if (entity_status == backend::StatusLevel::ERROR && !entity_item->is_error()) + { + entity_item->is_error(true); + } + else if (entity_status == backend::StatusLevel::WARNING && entity_item->is_error()) + { + entity_item->is_error(false); + } new_status = sample.status; auto incompatible_qos_item = new models::ProblemTreeItem(id, kind, std::string("Incompatible QoS"), - sample.status == backend::EntityStatus::ERROR, std::string(""), description); + sample.status == backend::StatusLevel::ERROR, std::string(""), description); for (eprosima::fastdds::statistics::QosPolicyCount_s policy : sample.incompatible_qos_status.policies()) { if (policy.count() > 0) { auto policy_item = new models::ProblemTreeItem(id, kind, std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), - sample.status == backend::EntityStatus::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(policy.count()), std::string("Check for compatible rules ") + std::string("getTopLevelItem( id, backend_connection_.get_name(id), - sample.status == backend::EntityStatus::ERROR, description); + sample.status == backend::StatusLevel::ERROR, description); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + if (entity_status == backend::StatusLevel::ERROR && !entity_item->is_error()) + { + entity_item->is_error(true); + } + else if (entity_status == backend::StatusLevel::WARNING && entity_item->is_error()) + { + entity_item->is_error(false); + } new_status = sample.status; auto inconsistent_topic_item = new models::ProblemTreeItem(id, kind, std::string("Inconsistent topics:"), - sample.status == backend::EntityStatus::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.inconsistent_topic_status.total_count()), description); problem_model_->addItem(entity_item, inconsistent_topic_item); counter = entity_item->recalculate_entity_counter(); @@ -1074,14 +1111,23 @@ bool Engine::update_problem( { backend::LivelinessLostSample sample; backend_connection_.get_status_data(id, sample); - if (sample.status != backend::EntityStatus::OK) + if (sample.status != backend::StatusLevel::OK) { auto entity_item = problem_model_->getTopLevelItem( id, backend_connection_.get_name(id), - sample.status == backend::EntityStatus::ERROR, description); + sample.status == backend::StatusLevel::ERROR, description); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + if (entity_status == backend::StatusLevel::ERROR && !entity_item->is_error()) + { + entity_item->is_error(true); + } + else if (entity_status == backend::StatusLevel::WARNING && entity_item->is_error()) + { + entity_item->is_error(false); + } new_status = sample.status; auto liveliness_lost_item = new models::ProblemTreeItem(id, kind, std::string("Liveliness lost:"), - sample.status == backend::EntityStatus::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_lost_status.total_count()), description); problem_model_->addItem(entity_item, liveliness_lost_item); counter = entity_item->recalculate_entity_counter(); @@ -1092,14 +1138,23 @@ bool Engine::update_problem( { backend::SampleLostSample sample; backend_connection_.get_status_data(id, sample); - if (sample.status != backend::EntityStatus::OK) + if (sample.status != backend::StatusLevel::OK) { auto entity_item = problem_model_->getTopLevelItem( id, backend_connection_.get_name(id), - sample.status == backend::EntityStatus::ERROR, description); + sample.status == backend::StatusLevel::ERROR, description); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + if (entity_status == backend::StatusLevel::ERROR && !entity_item->is_error()) + { + entity_item->is_error(true); + } + else if (entity_status == backend::StatusLevel::WARNING && entity_item->is_error()) + { + entity_item->is_error(false); + } new_status = sample.status; auto samples_lost_item = new models::ProblemTreeItem(id, kind, std::string("Samples lost:"), - sample.status == backend::EntityStatus::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.sample_lost_status.total_count()), description); problem_model_->addItem(entity_item, samples_lost_item); counter = entity_item->recalculate_entity_counter(); @@ -1117,12 +1172,12 @@ bool Engine::update_problem( break; } } - if (new_status != backend::EntityStatus::OK) + if (new_status != backend::StatusLevel::OK) { std::map::iterator it; uint32_t total_counter = 0; bool found = false; - if (new_status == backend::EntityStatus::ERROR) + if (new_status == backend::StatusLevel::ERROR) { for (it = controller_->status_counters.errors.begin(); it != controller_->status_counters.errors.end(); it++) { @@ -1140,7 +1195,7 @@ bool Engine::update_problem( } controller_->status_counters.total_errors = total_counter; } - else if (new_status == backend::EntityStatus::WARNING) + else if (new_status == backend::StatusLevel::WARNING) { for (it = controller_->status_counters.warnings.begin(); it != controller_->status_counters.warnings.end(); it++) { @@ -1159,7 +1214,7 @@ bool Engine::update_problem( controller_->status_counters.total_warnings = total_counter; } // notify problem model layout changed to refresh layout view - emit problem_model_->layoutAboutToBeChanged(); + emit problem_proxy_model_->layoutAboutToBeChanged(); emit controller_->update_status_counters( QString::number(controller_->status_counters.total_errors), @@ -1170,8 +1225,12 @@ bool Engine::update_problem( { problem_model_->removeEmptyItem(); } + + // update view + problem_proxy_model_->set_source_model(problem_model_); + // notify problem model layout changed to refresh layout view - emit problem_model_->layoutChanged(); + emit problem_proxy_model_->layoutChanged(); } } return true; @@ -1227,11 +1286,17 @@ bool Engine::update_problem_entities( controller_->status_counters.warnings.erase(id); // refresh layout - emit problem_model_->layoutAboutToBeChanged(); + emit problem_proxy_model_->layoutAboutToBeChanged(); emit controller_->update_status_counters( QString::number(controller_->status_counters.total_errors), QString::number(controller_->status_counters.total_warnings)); + + // update view + problem_proxy_model_->set_source_model(problem_model_); + + // notify problem model layout changed to refresh layout view + emit problem_proxy_model_->layoutChanged(); } return true; } diff --git a/src/backend/Listener.cpp b/src/backend/Listener.cpp index e224b3ae..ee5ab2ad 100644 --- a/src/backend/Listener.cpp +++ b/src/backend/Listener.cpp @@ -169,7 +169,7 @@ void Listener::on_topic_discovery( } } -void Listener::on_problem_reported( +void Listener::on_status_reported( EntityId domain_id, EntityId entity_id, StatusKind status_kind) diff --git a/src/backend/SyncBackendConnection.cpp b/src/backend/SyncBackendConnection.cpp index 4353e5f8..6d6f2847 100644 --- a/src/backend/SyncBackendConnection.cpp +++ b/src/backend/SyncBackendConnection.cpp @@ -619,6 +619,12 @@ std::string SyncBackendConnection::get_name( return backend::get_info_value(get_info(id), "name"); } +StatusLevel SyncBackendConnection:: get_status( + EntityId id) +{ + return StatisticsBackend::get_status(id); +} + std::vector SyncBackendConnection::get_data( DataKind data_kind, EntityId source_entity_id, diff --git a/src/model/tree/ProblemTreeItem.cpp b/src/model/tree/ProblemTreeItem.cpp index af09e651..d10ae97b 100644 --- a/src/model/tree/ProblemTreeItem.cpp +++ b/src/model/tree/ProblemTreeItem.cpp @@ -287,6 +287,32 @@ backend::StatusKind ProblemTreeItem::kind() return kind_; } +bool ProblemTreeItem::is_error() +{ + return is_status_error_; +} + +void ProblemTreeItem::is_error( + bool val) +{ + is_status_error_ = val; + is_status_error_variant_ = QVariant(val); +} + +std::string ProblemTreeItem::name_str() +{ + return name_; +} + +std::string ProblemTreeItem::value_str() +{ + return value_; +} + +std::string ProblemTreeItem::description_str() +{ + return description_; +} int ProblemTreeItem::recalculate_entity_counter() { diff --git a/src/model/tree/ProblemTreeModel.cpp b/src/model/tree/ProblemTreeModel.cpp index 2576775f..95ca7f85 100644 --- a/src/model/tree/ProblemTreeModel.cpp +++ b/src/model/tree/ProblemTreeModel.cpp @@ -51,8 +51,10 @@ namespace models { ProblemTreeModel::ProblemTreeModel( QObject* parent) : QAbstractItemModel(parent) + , source_model_(nullptr) , root_item_{ new ProblemTreeItem() } , is_empty_(false) + , current_filter_(backend::ID_ALL) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -62,6 +64,63 @@ ProblemTreeModel::~ProblemTreeModel() delete root_item_; } +void ProblemTreeModel::set_source_model( + ProblemTreeModel* source_model) +{ + source_model_ = source_model; + filter(current_filter_); +} + +void ProblemTreeModel::filter_proxy( + const QVariant& entity_id) +{ + if (source_model_) + { + filter(entity_id.toInt()); + } +} + +void ProblemTreeModel::filter( + const backend::EntityId entity_id) +{ + clear(); + if (current_filter_ != entity_id) + { + current_filter_ = entity_id; + } + if (source_model_) + { + for (int i = 0; i < source_model_->rootItem()->childCount(); i++) + { + addTopLevelItem(copy(source_model_->rootItem()->child(i), entity_id)); + } + } +} + +ProblemTreeItem* ProblemTreeModel::copy( + ProblemTreeItem* source, + const backend::EntityId entity_id) +{ + // copy source data in destiny data + if (source->id() == entity_id || entity_id == backend::ID_ALL) + { + ProblemTreeItem* destiny = new ProblemTreeItem( + source->id(), + source->kind(), + source->name_str(), + source->is_error(), + source->value_str(), + source->description_str()); + for (int i = 0; i < source->childCount(); i++) + { + addItem(destiny, copy(source->child(i), entity_id)); + } + return destiny; + } + return nullptr; +} + + int ProblemTreeModel::rowCount( const QModelIndex& parent) const { @@ -159,6 +218,25 @@ bool ProblemTreeModel::setData( return false; } +bool ProblemTreeModel::removeRow( + int /*row*/, + const QModelIndex& index) +{ + if (!index.isValid()) + { + return false; + } + + if (auto item = internalPointer(index)) + { + std::cout << "removing" << std::endl; + removeItem(item); + std::cout << "removed" << std::endl; + } + + return false; +} + void ProblemTreeModel::addTopLevelItem( ProblemTreeItem* child) { @@ -313,6 +391,17 @@ bool ProblemTreeModel::contains( return false; } +ProblemTreeItem* ProblemTreeModel::child( + int row) +{ + if (row >= 0 && row < root_item_->childCount()) + { + return root_item_->child(row); + } + + return nullptr; +} + bool ProblemTreeModel::is_empty() { return is_empty_;