From 5f8d281d07540196c4defccbb270e17f7d906f8c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 18 Sep 2023 15:06:29 +0200 Subject: [PATCH 01/43] Refs #19533: Add Status view to layout Signed-off-by: JesusPoderoso Refs #19533: Include problem callback backend connection Signed-off-by: JesusPoderoso Refs #19533: Sync with statistics backend to obtain StatusData Signed-off-by: JesusPoderoso Refs #19533: Take the samples and prepare a json structure Signed-off-by: JesusPoderoso Refs #19533: Display the problem data in status layout Signed-off-by: JesusPoderoso Refs #19533: Improve arrows based on internal feedback Signed-off-by: JesusPoderoso Refs #19533: Include external QMLTreeView module Signed-off-by: JesusPoderoso Refs #19533: Include external QMLTreeView module and adapt the tree with the required mechanisms Signed-off-by: JesusPoderoso Refs #19533: Adapt model to use roles Signed-off-by: JesusPoderoso Refs #19533: Include missing information through roles in the UI Signed-off-by: JesusPoderoso Refs #19533: Add status icon and homogenize fonts Signed-off-by: JesusPoderoso Refs #19533: Add incompatible qos policies links to documentation compatibility rules Signed-off-by: JesusPoderoso Refs #19533: Fix first click issue in status footer and remove dead code Signed-off-by: JesusPoderoso Refs #19533: Add view problem filter functionality Signed-off-by: JesusPoderoso Refs #19533: Display entity issues counter on its right Signed-off-by: JesusPoderoso Refs #19533: Avoid problem model destruction to avoid error messages when app closed Signed-off-by: JesusPoderoso Refs #19533: Catch entity dispose and remove entity problems from model Signed-off-by: JesusPoderoso Refs #19533: Update icons Signed-off-by: JesusPoderoso Refs #19533: Fix visual details Signed-off-by: JesusPoderoso Refs #19533: Fix error counting Signed-off-by: JesusPoderoso Refs #19533: Adapt changes Signed-off-by: JesusPoderoso --- CMakeLists.txt | 4 + fastdds_monitor.pro | 4 + include/fastdds_monitor/Controller.h | 14 + include/fastdds_monitor/Engine.h | 68 ++- include/fastdds_monitor/backend/Listener.h | 6 + .../fastdds_monitor/backend/ProblemCallback.h | 60 +++ .../backend/SyncBackendConnection.h | 37 ++ .../fastdds_monitor/backend/backend_types.h | 17 + .../fastdds_monitor/backend/backend_utils.h | 14 +- .../model/tree/ProblemTreeItem.h | 168 ++++++++ .../model/tree/ProblemTreeModel.h | 170 ++++++++ qml.qrc | 44 ++ qml/ChangeAliasDialog.qml | 2 + qml/DomainGraphLayout.qml | 291 ++++++++++--- qml/EntitiesMenu.qml | 7 +- qml/EntityList.qml | 6 +- qml/GraphConnection.qml | 111 ++--- qml/LeftPanel.qml | 33 +- qml/LogicalView.qml | 5 +- qml/Panels.qml | 83 +++- qml/PhysicalView.qml | 6 +- qml/ProblemTreeView.qml | 175 ++++++++ qml/ProblemTreeViewItem.qml | 406 ++++++++++++++++++ qml/StatusLayout.qml | 305 +++++++++++++ qml/TabLayout.qml | 102 ++++- qml/TopicMenu.qml | 45 ++ resources/images/domain_graph.svg | 76 ++++ .../images/icons/collapse/collapse_black.svg | 1 + .../collapse/collapse_eProsimaLightBlue.svg | 1 + .../images/icons/collapse/collapse_grey.svg | 1 + .../images/icons/collapse/collapse_white.svg | 1 + resources/images/icons/cross/cross_red.svg | 5 + resources/images/icons/error/error_black.svg | 10 + .../icons/error/error_eProsimaLightBlue.svg | 10 + resources/images/icons/error/error_grey.svg | 10 + resources/images/icons/error/error_red.svg | 10 + resources/images/icons/error/error_white.svg | 10 + .../images/icons/expand/expand_black.svg | 1 + .../icons/expand/expand_eProsimaLightBlue.svg | 1 + resources/images/icons/expand/expand_grey.svg | 1 + .../images/icons/expand/expand_white.svg | 1 + .../icons/filter_empty/filter_empty_black.svg | 3 + .../filter_empty_eProsimaLightBlue.svg | 3 + .../icons/filter_empty/filter_empty_grey.svg | 3 + .../icons/filter_empty/filter_empty_white.svg | 3 + .../icons/filter_full/filter_full_black.svg | 3 + .../filter_full_eProsimaLightBlue.svg | 3 + .../icons/filter_full/filter_full_grey.svg | 3 + .../icons/filter_full/filter_full_white.svg | 3 + .../icons/left_arrow/left_arrow_black.svg | 7 + .../left_arrow_eProsimaLightBlue.svg | 7 + .../icons/left_arrow/left_arrow_grey.svg | 7 + .../icons/left_arrow/left_arrow_white.svg | 7 + .../icons/right_arrow/right_arrow_black.svg | 7 + .../right_arrow_eProsimaLightBlue.svg | 7 + .../icons/right_arrow/right_arrow_grey.svg | 7 + .../icons/right_arrow/right_arrow_white.svg | 7 + .../rounded_left_arrow_black.svg | 12 + .../rounded_left_arrow_eProsimaLightBlue.svg | 12 + .../rounded_left_arrow_grey.svg | 12 + .../rounded_left_arrow_white.svg | 12 + .../rounded_right_arrow_black.svg | 12 + .../rounded_right_arrow_eProsimaLightBlue.svg | 12 + .../rounded_right_arrow_grey.svg | 12 + .../rounded_right_arrow_white.svg | 12 + resources/images/topic_graph.svg | 37 ++ src/Engine.cpp | 344 +++++++++++++++ src/backend/Listener.cpp | 10 + src/backend/SyncBackendConnection.cpp | 57 +++ src/backend/backend_utils.cpp | 169 ++++++++ src/model/tree/ProblemTreeItem.cpp | 318 ++++++++++++++ src/model/tree/ProblemTreeModel.cpp | 375 ++++++++++++++++ 72 files changed, 3648 insertions(+), 160 deletions(-) create mode 100644 include/fastdds_monitor/backend/ProblemCallback.h create mode 100644 include/fastdds_monitor/model/tree/ProblemTreeItem.h create mode 100644 include/fastdds_monitor/model/tree/ProblemTreeModel.h create mode 100644 qml/ProblemTreeView.qml create mode 100644 qml/ProblemTreeViewItem.qml create mode 100644 qml/StatusLayout.qml create mode 100644 qml/TopicMenu.qml create mode 100644 resources/images/domain_graph.svg create mode 100644 resources/images/icons/collapse/collapse_black.svg create mode 100644 resources/images/icons/collapse/collapse_eProsimaLightBlue.svg create mode 100644 resources/images/icons/collapse/collapse_grey.svg create mode 100644 resources/images/icons/collapse/collapse_white.svg create mode 100644 resources/images/icons/cross/cross_red.svg create mode 100644 resources/images/icons/error/error_black.svg create mode 100644 resources/images/icons/error/error_eProsimaLightBlue.svg create mode 100644 resources/images/icons/error/error_grey.svg create mode 100644 resources/images/icons/error/error_red.svg create mode 100644 resources/images/icons/error/error_white.svg create mode 100644 resources/images/icons/expand/expand_black.svg create mode 100644 resources/images/icons/expand/expand_eProsimaLightBlue.svg create mode 100644 resources/images/icons/expand/expand_grey.svg create mode 100644 resources/images/icons/expand/expand_white.svg create mode 100644 resources/images/icons/filter_empty/filter_empty_black.svg create mode 100644 resources/images/icons/filter_empty/filter_empty_eProsimaLightBlue.svg create mode 100644 resources/images/icons/filter_empty/filter_empty_grey.svg create mode 100644 resources/images/icons/filter_empty/filter_empty_white.svg create mode 100644 resources/images/icons/filter_full/filter_full_black.svg create mode 100644 resources/images/icons/filter_full/filter_full_eProsimaLightBlue.svg create mode 100644 resources/images/icons/filter_full/filter_full_grey.svg create mode 100644 resources/images/icons/filter_full/filter_full_white.svg create mode 100644 resources/images/icons/left_arrow/left_arrow_black.svg create mode 100644 resources/images/icons/left_arrow/left_arrow_eProsimaLightBlue.svg create mode 100644 resources/images/icons/left_arrow/left_arrow_grey.svg create mode 100644 resources/images/icons/left_arrow/left_arrow_white.svg create mode 100644 resources/images/icons/right_arrow/right_arrow_black.svg create mode 100644 resources/images/icons/right_arrow/right_arrow_eProsimaLightBlue.svg create mode 100644 resources/images/icons/right_arrow/right_arrow_grey.svg create mode 100644 resources/images/icons/right_arrow/right_arrow_white.svg create mode 100644 resources/images/icons/rounded_left_arrow/rounded_left_arrow_black.svg create mode 100644 resources/images/icons/rounded_left_arrow/rounded_left_arrow_eProsimaLightBlue.svg create mode 100644 resources/images/icons/rounded_left_arrow/rounded_left_arrow_grey.svg create mode 100644 resources/images/icons/rounded_left_arrow/rounded_left_arrow_white.svg create mode 100644 resources/images/icons/rounded_right_arrow/rounded_right_arrow_black.svg create mode 100644 resources/images/icons/rounded_right_arrow/rounded_right_arrow_eProsimaLightBlue.svg create mode 100644 resources/images/icons/rounded_right_arrow/rounded_right_arrow_grey.svg create mode 100644 resources/images/icons/rounded_right_arrow/rounded_right_arrow_white.svg create mode 100644 resources/images/topic_graph.svg create mode 100644 src/model/tree/ProblemTreeItem.cpp create mode 100644 src/model/tree/ProblemTreeModel.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 89858132..910d7578 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,6 +233,8 @@ set(PROJECT_HEADERS ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/statistics/EntityItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/SubListedListItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/SubListedListModel.h + ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/ProblemTreeItem.h + ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/ProblemTreeModel.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/TreeItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/TreeModel.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/statistics/DataChartBox.h @@ -261,6 +263,8 @@ set(PROJECT_SOURCES_NO_MAIN ${PROJECT_SOURCE_DIR}/src/model/physical/ProcessModelItem.cpp ${PROJECT_SOURCE_DIR}/src/model/statistics/EntityItem.cpp ${PROJECT_SOURCE_DIR}/src/model/SubListedListModel.cpp + ${PROJECT_SOURCE_DIR}/src/model/tree/ProblemTreeItem.cpp + ${PROJECT_SOURCE_DIR}/src/model/tree/ProblemTreeModel.cpp ${PROJECT_SOURCE_DIR}/src/model/tree/TreeItem.cpp ${PROJECT_SOURCE_DIR}/src/model/tree/TreeModel.cpp ${PROJECT_SOURCE_DIR}/src/statistics/DataChartBox.cpp diff --git a/fastdds_monitor.pro b/fastdds_monitor.pro index f96cf855..d3771b80 100644 --- a/fastdds_monitor.pro +++ b/fastdds_monitor.pro @@ -24,6 +24,8 @@ SOURCES += \ src/model/physical/ProcessModelItem.cpp \ src/model/statistics/EntityItem.cpp \ src/model/SubListedListModel.cpp \ + src/model/tree/ProblemTreeItem.cpp \ + src/model/tree/ProblemTreeModel.cpp \ src/model/tree/TreeItem.cpp \ src/model/tree/TreeModel.cpp \ src/statistics/DataChartBox.cpp \ @@ -75,6 +77,8 @@ HEADERS += \ include/fastdds_monitor/model/statistics/EntityItem.h \ include/fastdds_monitor/model/SubListedListItem.h \ include/fastdds_monitor/model/SubListedListModel.h \ + include/fastdds_monitor/model/tree/ProblemTreeModel.h \ + include/fastdds_monitor/model/tree/ProblemTreeItem.h \ include/fastdds_monitor/model/tree/TreeItem.h \ include/fastdds_monitor/model/tree/TreeModel.h \ include/fastdds_monitor/statistics/DataChartBox.h \ diff --git a/include/fastdds_monitor/Controller.h b/include/fastdds_monitor/Controller.h index 17f61ace..b1f5a40b 100644 --- a/include/fastdds_monitor/Controller.h +++ b/include/fastdds_monitor/Controller.h @@ -26,6 +26,8 @@ #include #include +#include + class Engine; enum class ErrorType : int @@ -59,6 +61,15 @@ class Controller : public QObject QString error_msg, ErrorType error_type = ErrorType::GENERIC); + //! Status counters displayed in the QML + struct StatusCounters + { + std::map errors; + std::map warnings; + uint32_t total_errors = 0; + uint32_t total_warnings = 0; + } status_counters; + public slots: // Methods to be called from QML @@ -275,6 +286,9 @@ public slots: //! Signal to inform qml that a new monitor has been initialized void monitorInitialized(); + //! Signal to notify status counters have been updated + void update_status_counters(QString errors, QString warnings); + protected: //! Reference to \c Engine object diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index 129b6d95..4cdc0bd1 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include struct EntityClicked { @@ -267,6 +269,13 @@ class Engine : public QQmlApplicationEngine bool new_entity = true, bool last_clicked = false); + bool update_problem( + const backend::EntityId& id, + backend::StatusKind kind); + + bool update_problem_entities( + const backend::EntityId& id); + /** * @brief Update the internal dds model with entities related with Entity referenced by \c id * @@ -348,6 +357,19 @@ class Engine : public QQmlApplicationEngine bool add_callback( backend::Callback callback); + /** + * @brief add a callback arrived from the backend to the callback queue + * + * Add a callback to the callback queue in order to process it afterwards by the main thread. + * Emit a signal that communicate the main thread that there are info to process in the callback queue. + * Add a callback issue. + * + * @param callback new callback to add + * @return true + */ + bool add_callback( + backend::ProblemCallback callback); + /** * @brief Refresh the view * @@ -390,6 +412,14 @@ class Engine : public QQmlApplicationEngine */ void process_callback_queue(); + /** + * @brief Pop problem callbacks from the callback queues while non empty and update the models + * + * @warning This method must be executed from the main Thread (or at least a QThread) so the models are + * updated in the view when modified. + */ + void process_problem_callback_queue(); + //! Refresh summary panel void refresh_summary(); @@ -507,14 +537,26 @@ class Engine : public QQmlApplicationEngine */ void new_callback_signal(); + /** + * Internal signal that communicate that there are callbacks to process by the main Thread. + * Arise from \c add_callback + */ + void new_problem_callback_signal(); + public slots: /** - * Receive the internal signal \c new_callback_signal and start the process of - * callback queue by \c process_callback_queue + * Receive the internal signal \c new_callback_signal and start the process of callback + * queue by \c process_callback_queue */ void new_callback_slot(); + /** + * Receive the internal signal \c new_problem_callback_signal and start the process of problem + * callback queue by \c process_problem_callback_queue + */ + void new_problem_callback_slot(); + protected: /** @@ -633,13 +675,23 @@ public slots: //! True if there are callbacks in the callback queue bool are_callbacks_to_process_(); + //! True if there are problem callbacks in the callback queue + bool are_problem_callbacks_to_process_(); + //! Pop a callback from callback queues and call \c read_callback for that callback bool process_callback_(); + //! Pop a problem callback from callback queues and call \c read_callback for that problem callback + bool process_problem_callback_(); + //! Update the model concerned by the entity in the callback bool read_callback_( backend::Callback callback); + //! Update the model concerned by the entity in the problem callback + bool read_callback_( + backend::ProblemCallback callback); + //! Common method to demultiplex to update functions depending on the entity kind bool update_entity_generic( backend::EntityId entity_id, @@ -695,6 +747,9 @@ public slots: //! Data that is represented in the Status Model when this model is refreshed backend::Info status_info_; + //! Data Model for Fast DDS Monitor problem view. Collects all entities problems detected by the monitor service + models::ProblemTreeModel* problem_model_; + //! TODO models::ListModel* source_entity_id_model_; @@ -722,9 +777,15 @@ public slots: //! Mutex to protect \c callback_queue_ std::recursive_mutex callback_queue_mutex_; + //! Mutex to protect \c problem_callback_queue_ + std::recursive_mutex problem_callback_queue_mutex_; + //! Queue of Callbacks that have arrived by the \c Listener and have not been processed QQueue callback_queue_; + //! Queue of Problem Callbacks that have arrived by the \c Listener and have not been processed + QQueue problem_callback_queue_; + //! Object that manage all the communications with the QML view Controller* controller_; @@ -746,6 +807,9 @@ public slots: * to happen) there are going to create entities already created. */ std::recursive_mutex initializing_monitor_; + + //! All status log + backend::Info problem_status_log_; }; #endif // _EPROSIMA_FASTDDS_MONITOR_ENGINE_H diff --git a/include/fastdds_monitor/backend/Listener.h b/include/fastdds_monitor/backend/Listener.h index 459509c4..49f2d424 100644 --- a/include/fastdds_monitor/backend/Listener.h +++ b/include/fastdds_monitor/backend/Listener.h @@ -91,6 +91,12 @@ class Listener : public PhysicalListener EntityId datawriter_id, const Status& status) override; + //! Callback when a problem is reported + void on_problem_reported( + EntityId domain_id, + EntityId entity_id, + StatusKind data_kind) override; + protected: //! Engine reference diff --git a/include/fastdds_monitor/backend/ProblemCallback.h b/include/fastdds_monitor/backend/ProblemCallback.h new file mode 100644 index 00000000..d4ca47d6 --- /dev/null +++ b/include/fastdds_monitor/backend/ProblemCallback.h @@ -0,0 +1,60 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +/** + * @file ProblemCallback.h + */ + +#ifndef _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H +#define _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H + +#include + +namespace backend { + +/* + * Struct that store the problem callback information required by the GUI. + * It encapsulates the domain id, entity id and the kind of the new problem reported. + */ +struct ProblemCallback +{ + //! Void constructor to use copy constructor afterwards + ProblemCallback() + { + } + + //! Standard constructor with the two fields required + ProblemCallback( + backend::EntityId domain_entity_id, + backend::EntityId entity_id, + backend::StatusKind status_kind) + : domain_entity_id(domain_entity_id) + , entity_id(entity_id) + , status_kind(status_kind) + { + } + //! Information of the domain \c EntityId the callback refers + backend::EntityId domain_entity_id; + //! Information of the \c EntityId the callback refers + backend::EntityId entity_id; + //! Information of the \c StatusKind the callback refers + backend::StatusKind status_kind; +}; + +} // namespace backend + +#endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H diff --git a/include/fastdds_monitor/backend/SyncBackendConnection.h b/include/fastdds_monitor/backend/SyncBackendConnection.h index ee4ab907..b48633a2 100644 --- a/include/fastdds_monitor/backend/SyncBackendConnection.h +++ b/include/fastdds_monitor/backend/SyncBackendConnection.h @@ -23,6 +23,7 @@ #define _EPROSIMA_FASTDDS_MONITOR_BACKEND_SYNCBACKENDCONNECTION_H #include +#include #include #include @@ -147,6 +148,42 @@ class SyncBackendConnection Timestamp start_time = Timestamp(), Timestamp end_time = std::chrono::system_clock::now()); + void get_status_data( + EntityId source_entity_id, + ConnectionListSample& sample); + + void get_status_data( + EntityId source_entity_id, + DeadlineMissedSample& sample); + + void get_status_data( + EntityId source_entity_id, + IncompatibleQosSample& sample); + + void get_status_data( + EntityId source_entity_id, + InconsistentTopicSample& sample); + + void get_status_data( + EntityId source_entity_id, + LivelinessChangedSample& sample); + + void get_status_data( + EntityId source_entity_id, + LivelinessLostSample& sample); + + void get_status_data( + EntityId source_entity_id, + ProxySample& sample); + + void get_status_data( + EntityId source_entity_id, + SampleLostSample& sample); + + /*void get_status_data( + EntityId source_entity_id, + StatusesSizeSample& sample);*/ + //! Get info from an entity from the Backend std::vector get_entities( EntityKind entity_type, diff --git a/include/fastdds_monitor/backend/backend_types.h b/include/fastdds_monitor/backend/backend_types.h index ec5753d8..6e2b5db8 100644 --- a/include/fastdds_monitor/backend/backend_types.h +++ b/include/fastdds_monitor/backend/backend_types.h @@ -33,15 +33,32 @@ namespace backend { using EntityId = eprosima::statistics_backend::EntityId; using EntityKind = eprosima::statistics_backend::EntityKind; using DataKind = eprosima::statistics_backend::DataKind; +using StatusKind = eprosima::statistics_backend::StatusKind; using StatisticKind = eprosima::statistics_backend::StatisticKind; using EntityInfo = eprosima::statistics_backend::Info; using Timestamp = eprosima::statistics_backend::Timestamp; +// Problem status types from backend +using ConnectionListSample = eprosima::statistics_backend::ConnectionListSample; +using DeadlineMissedSample = eprosima::statistics_backend::DeadlineMissedSample; +using IncompatibleQosSample = eprosima::statistics_backend::IncompatibleQosSample; +using InconsistentTopicSample = eprosima::statistics_backend::InconsistentTopicSample; +using LivelinessChangedSample = eprosima::statistics_backend::LivelinessChangedSample; +using LivelinessLostSample = eprosima::statistics_backend::LivelinessLostSample; +using ProxySample = eprosima::statistics_backend::ProxySample; +using SampleLostSample = eprosima::statistics_backend::SampleLostSample; +//using StatusesSizeSample = eprosima::statistics_backend::StatusesSizeSample; + //! Reference the ID_ALL in the project extern const EntityId ID_ALL; //! Reference the ID_NONE in the project extern const EntityId ID_NONE; +//! Reference for problem status (ok, error or warning) +static constexpr const char* PROBLEM_STATUS_ERROR = "error"; +static constexpr const char* PROBLEM_STATUS_OK = "ok"; +static constexpr const char* PROBLEM_STATUS_WARNING = "warning"; + } //namespace backend #endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_BACKENDTYPES_H diff --git a/include/fastdds_monitor/backend/backend_utils.h b/include/fastdds_monitor/backend/backend_utils.h index 009e6c03..25af9e1c 100644 --- a/include/fastdds_monitor/backend/backend_utils.h +++ b/include/fastdds_monitor/backend/backend_utils.h @@ -87,6 +87,10 @@ std::string data_kind_to_string( std::string statistic_kind_to_string( const StatisticKind& statistic_kind); +//! Converts the \c StatusKind to string +std::string status_kind_to_string( + const StatusKind& status_kind); + //! Retrieves the \c EntityKind related with its name in QString backend::EntityKind string_to_entity_kind( const QString& entity_kind); @@ -99,7 +103,6 @@ backend::DataKind string_to_data_kind( backend::StatisticKind string_to_statistic_kind( const QString& statistic_kind); - //! recursive function to convert array json subelements to dictionaries indexed by numbers backend::EntityInfo refactor_json( backend::EntityInfo json_data); @@ -108,6 +111,15 @@ backend::EntityInfo refactor_json( std::string timestamp_to_string( const backend::Timestamp timestamp); +std::string policy_id_to_string( + const uint32_t& id); + +std::string problem_description( + const backend::StatusKind kind); + +std::string policy_documentation_description( + const uint32_t& id); + } //namespace backend #endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_BACKENDUTILS_H diff --git a/include/fastdds_monitor/model/tree/ProblemTreeItem.h b/include/fastdds_monitor/model/tree/ProblemTreeItem.h new file mode 100644 index 00000000..17bfcc4d --- /dev/null +++ b/include/fastdds_monitor/model/tree/ProblemTreeItem.h @@ -0,0 +1,168 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H +#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H + +#include +#include + +namespace models { + +/*! + * This class represents a node of the ProblemTreeModel. + * The items are meant to be managed from the ProblemTreeModel, thus is only allowed + * to modify the stored data. + * Parenting and deletion are dealt from the ProblemTreeModel. Deleting a ProblemTreeItem + * will call the delete for each child node. + */ +class ProblemTreeItem +{ + friend class ProblemTreeModel; + +public: + + //! Create an empty item. + ProblemTreeItem(); + + //! Create an item with the given data. + explicit ProblemTreeItem( + const QVariant& data); + + //! Create an Entity item / top level item + explicit ProblemTreeItem( + const backend::EntityId& id, + const std::string& name, + const bool& is_error, + const std::string& description); + + //! Create an item with the problem parameters + explicit ProblemTreeItem( + const backend::EntityId& id, + const backend::StatusKind& kind, + const std::string& name, + const bool& is_error, + const std::string& value, + const std::string& description); + + //! Destroy the item. It will destroy every child. + ~ProblemTreeItem(); + + //! Return the stored data of the node. + const QVariant& data() const; + + //! Return the stored data of the node. + const QVariant& data( + int role) const; + + const QVariant& entity_id() const; + + const QVariant& status_kind() const; + + const QVariant& name() const; + + const QVariant& status() const; + + const QVariant& value() const; + + const QVariant& description() const; + + const QVariant& alive() const; + + //! Set the internal data of the node. + void setData( + const QVariant& data); + + //! Return the number of children nodes. + int childCount() const; + + int row() const; + + //! Return true if the node is a leaf node (no children). + bool isLeaf() const; + + //! Return the depth of this node inside the tree. + int depth() const; + + ProblemTreeItem* child( + int row); + + backend::EntityId id(); + + backend::StatusKind kind(); + + //! Increases the issues counter of a top level entity item + int recalculate_entity_counter(); + +private: + ProblemTreeItem* parentItem(); + + void setParentItem( + ProblemTreeItem* parentItem); + + void appendChild( + ProblemTreeItem* item); + + void removeChild( + ProblemTreeItem* item); + +private: + ProblemTreeItem* parent_item_; + QVector child_items_; + backend::EntityId id_; + backend::StatusKind kind_; + std::string name_; + bool is_status_error_; + std::string value_; + std::string description_; + bool is_active_; + QVariant id_variant_; + QVariant kind_variant_; + QVariant name_variant_; + QVariant is_status_error_variant_; + QVariant value_variant_; + QVariant description_variant_; + QVariant is_active_variant_; +}; + +} // namespace models + +#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H diff --git a/include/fastdds_monitor/model/tree/ProblemTreeModel.h b/include/fastdds_monitor/model/tree/ProblemTreeModel.h new file mode 100644 index 00000000..d97e941f --- /dev/null +++ b/include/fastdds_monitor/model/tree/ProblemTreeModel.h @@ -0,0 +1,170 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H +#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H + +#include + +#include + +namespace models { + +/*! + * The Tree Model works as List Model, using one column and using the row information + * referred to the parent node. + */ +class ProblemTreeModel : public QAbstractItemModel +{ + Q_OBJECT + //Q_ENUMS(models::ProblemTreeItem::ModelItemRoles) + +public: + explicit ProblemTreeModel( + QObject* parent = nullptr); + + ~ProblemTreeModel() override; + + // Overriden method from QAbstractItemModel + +public: + + //! Role names to allow queries to get some specific information from the Item + enum ModelItemRoles + { + idRole = Qt::UserRole + 1, //! Role for attribute Id + statusRole, //! Role for attribute Status + kindRole, //! Role for attribute Kind + valueRole, //! Role for attribute Value + descriptionRole, //! Role for attribute Description + aliveRole, //! Role for attribute Alive + nameRole //! Role for attribute Name + // The nameRole must always be the last one as it is used in child classes + // as the initial role of the enumeration) + }; + + int rowCount( + const QModelIndex& index) const override; + int columnCount( + const QModelIndex& index) const override; + + QModelIndex index( + int row, + int column, + const QModelIndex& parent) const override; + + QModelIndex parent( + const QModelIndex& childIndex) const override; + + QVariant data( + const QModelIndex& index, + int role = 0) const override; + + bool setData( + const QModelIndex& index, + const QVariant& value, + int role = Qt::EditRole) override; + + QHash roleNames() const override; + +public: + //! Add an item to the top level. + void addTopLevelItem( + ProblemTreeItem* child); + + //! Add a child to the parent item. + void addItem( + ProblemTreeItem* parent, + ProblemTreeItem* child); + + //! Remove the item from the model. + void removeItem( + ProblemTreeItem* item); + + //! Return the root item of the model. + ProblemTreeItem* rootItem() const; + + //! Return the depth for the given index + Q_INVOKABLE int depth( + const QModelIndex& index) const; + + //! Clear the model. + Q_INVOKABLE void clear(); + + /*! + * Return the root item to the QML Side. + * This method is not meant to be used in client code. + */ + Q_INVOKABLE QModelIndex rootIndex(); + + // Check if top level item is defined + bool containsTopLevelItem( + ProblemTreeItem* child); + + // Check if item is defined in the parent item + bool contains( + ProblemTreeItem* parent, + ProblemTreeItem* child); + + // Check if default empty value is the only element + bool is_empty(); + + void removeEmptyItem(); + + //! Looks for a TopLevelItem that matches that id. If not existing, creates new one and returns it + ProblemTreeItem* getTopLevelItem( + const backend::EntityId& id, + const std::string& data, + const bool& is_error, + const std::string& description); + +private: + ProblemTreeItem* internalPointer( + const QModelIndex& index) const; + +private: + ProblemTreeItem* root_item_; + bool is_empty_; +}; + +} // namespace models + +#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H diff --git a/qml.qrc b/qml.qrc index 22715c9e..28a42166 100644 --- a/qml.qrc +++ b/qml.qrc @@ -53,6 +53,8 @@ qml/MonitorToolBarButton.qml qml/Panels.qml qml/PhysicalView.qml + qml/ProblemTreeView.qml + qml/ProblemTreeViewItem.qml qml/QosView.qml qml/ScheduleClearDialog.qml qml/SeriesSetMaxPointsDialog.qml @@ -60,9 +62,11 @@ qml/StatisticsChartBox.qml qml/StatisticsChartView.qml qml/StatusPanel.qml + qml/StatusLayout.qml qml/StatusView.qml qml/SummaryView.qml qml/TabLayout.qml + qml/TopicMenu.qml qtquickcontrols2.conf @@ -70,6 +74,8 @@ resources/images/eprosima_logo.ico resources/images/fastdds-monitor-logo.png resources/images/graphs.svg + resources/images/domain_graph.svg + resources/images/topic_graph.svg resources/images/icons/clearissues/clearissues_black.svg @@ -80,10 +86,15 @@ resources/images/icons/clearlog/clearlog_eProsimaLightBlue.svg resources/images/icons/clearlog/clearlog_grey.svg resources/images/icons/clearlog/clearlog_white.svg + resources/images/icons/collapse/collapse_black.svg + resources/images/icons/collapse/collapse_eProsimaLightBlue.svg + resources/images/icons/collapse/collapse_grey.svg + resources/images/icons/collapse/collapse_white.svg resources/images/icons/cross/cross_black.svg resources/images/icons/cross/cross_eProsimaLightBlue.svg resources/images/icons/cross/cross_grey.svg resources/images/icons/cross/cross_white.svg + resources/images/icons/cross/cross_red.svg resources/images/icons/datareader/datareader_black.svg resources/images/icons/datareader/datareader_eProsimaLightBlue.svg resources/images/icons/datareader/datareader_grey.svg @@ -104,10 +115,27 @@ resources/images/icons/editaxis/editaxis_eProsimaLightBlue.svg resources/images/icons/editaxis/editaxis_grey.svg resources/images/icons/editaxis/editaxis_white.svg + resources/images/icons/error/error_black.svg + resources/images/icons/error/error_eProsimaLightBlue.svg + resources/images/icons/error/error_grey.svg + resources/images/icons/error/error_white.svg + resources/images/icons/error/error_red.svg + resources/images/icons/expand/expand_black.svg + resources/images/icons/expand/expand_eProsimaLightBlue.svg + resources/images/icons/expand/expand_grey.svg + resources/images/icons/expand/expand_white.svg resources/images/icons/explorer/explorer_black.svg resources/images/icons/explorer/explorer_eProsimaLightBlue.svg resources/images/icons/explorer/explorer_grey.svg resources/images/icons/explorer/explorer_white.svg + resources/images/icons/filter_empty/filter_empty_black.svg + resources/images/icons/filter_empty/filter_empty_eProsimaLightBlue.svg + resources/images/icons/filter_empty/filter_empty_grey.svg + resources/images/icons/filter_empty/filter_empty_white.svg + resources/images/icons/filter_full/filter_full_black.svg + resources/images/icons/filter_full/filter_full_eProsimaLightBlue.svg + resources/images/icons/filter_full/filter_full_grey.svg + resources/images/icons/filter_full/filter_full_white.svg resources/images/icons/grid1/grid1_black.svg resources/images/icons/grid1/grid1_eProsimaLightBlue.svg resources/images/icons/grid1/grid1_grey.svg @@ -195,5 +223,21 @@ resources/images/icons/help/help_eProsimaLightBlue.svg resources/images/icons/help/help_grey.svg resources/images/icons/help/help_white.svg + resources/images/icons/left_arrow/left_arrow_black.svg + resources/images/icons/left_arrow/left_arrow_eProsimaLightBlue.svg + resources/images/icons/left_arrow/left_arrow_grey.svg + resources/images/icons/left_arrow/left_arrow_white.svg + resources/images/icons/right_arrow/right_arrow_black.svg + resources/images/icons/right_arrow/right_arrow_eProsimaLightBlue.svg + resources/images/icons/right_arrow/right_arrow_grey.svg + resources/images/icons/right_arrow/right_arrow_white.svg + resources/images/icons/rounded_left_arrow/rounded_left_arrow_black.svg + resources/images/icons/rounded_left_arrow/rounded_left_arrow_eProsimaLightBlue.svg + resources/images/icons/rounded_left_arrow/rounded_left_arrow_grey.svg + resources/images/icons/rounded_left_arrow/rounded_left_arrow_white.svg + resources/images/icons/rounded_right_arrow/rounded_right_arrow_black.svg + resources/images/icons/rounded_right_arrow/rounded_right_arrow_eProsimaLightBlue.svg + resources/images/icons/rounded_right_arrow/rounded_right_arrow_grey.svg + resources/images/icons/rounded_right_arrow/rounded_right_arrow_white.svg diff --git a/qml/ChangeAliasDialog.qml b/qml/ChangeAliasDialog.qml index 3c0507c0..fc16d65e 100644 --- a/qml/ChangeAliasDialog.qml +++ b/qml/ChangeAliasDialog.qml @@ -32,6 +32,7 @@ Dialog { standardButtons: Dialog.Ok | Dialog.Cancel anchors.centerIn: Overlay.overlay + property var domainEntityId: "" property var entityId: "" property var currentAlias: "" property var entityKind: "" @@ -79,6 +80,7 @@ Dialog { } else { controller.set_alias(entityId, newSeriesNameTextField.text, entityKind) } + refreshDomainGraphView(domainEntityId, entityId) } } } diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 5aadb1fa..9ff3ff44 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -33,6 +33,8 @@ Item // Public signals signal update_tab_name(string new_name) // Update tab name based on selected domain id + signal openEntitiesMenu(string domainEntityId, string entityId, string currentAlias, string entityKind) + signal openTopicMenu(string domainEntityId, string domainId, string entityId, string currentAlias, string entityKind) // Private properties property var topic_locations_: {} // topic information needed for connection representation @@ -41,7 +43,8 @@ Item property var endpoint_painted_: [] // already painted endpoint connection references property var pending_endpoints_: [] // pending endpoints references that have not been resized yet property var pending_connections_: [] // pending connections references that have not been generated yet - property int entity_box_width_: 0 // entities box width management + property var filtered_topics_: [] // flitered topic entity id in the graph + property int entity_box_width_: 0 // entity box width management // Private (resize) signals The signal resize_elements_ will trigger all entities resize methods in // HOST TOPIC ─┐ the order displayed in the left figure. All entities width value are @@ -229,9 +232,14 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.topic_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openTopicMenu(entity_id, domain_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.topic_click(modelData["id"]) + } } } } @@ -536,8 +544,8 @@ Item } IconSVG { visible: modelData["status"] != "OK" - name: "issues" - color: "white" + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } Rectangle { @@ -558,9 +566,14 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.host_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.host_click(modelData["id"]) + } } } } @@ -673,8 +686,8 @@ Item } IconSVG { visible: modelData["status"] != "OK" - name: "issues" - color: "white" + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } Rectangle { @@ -695,9 +708,14 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.user_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.user_click(modelData["id"]) + } } } } @@ -809,8 +827,9 @@ Item } IconSVG { visible: modelData["status"] != "OK" - name: "issues" - color: "white" + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 } Rectangle { @@ -831,9 +850,14 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.process_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.process_click(modelData["id"]) + } } } } @@ -945,7 +969,8 @@ Item } IconSVG { visible: modelData["status"] != "OK" - name: "issues" + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } Rectangle { @@ -953,7 +978,7 @@ Item width: first_indentation_ /2 } IconSVG { - name: modelData["kind"] + name: "participant" size: icon_size_ } Label { @@ -964,9 +989,15 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.participant_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.participant_click(modelData["id"]) + } + } } } @@ -1083,8 +1114,8 @@ Item var globalCoordinates = endpointComponent.mapToItem(mainSpace, 0, 0) var src_x = globalCoordinates.x + entity_box_width_-(8*elements_spacing_) var src_y = modelData["accum_y"] + (endpointComponent.height / 2) - var left_direction = modelData["kind"] == "datareader" - var right_direction = modelData["kind"] == "datawriter" + var left_direction = modelData["kind"] == "DataReader" + var right_direction = modelData["kind"] == "DataWriter" endpoint_topic_connections_[modelData["id"]] = { "id": modelData["id"], "left_direction": left_direction, @@ -1104,7 +1135,7 @@ Item id: endpoint_background width: parent.width height: endpoint_height_ - color: modelData["kind"] == "datareader" ? reader_color_ : writer_color_ + color: modelData["kind"] == "DataReader" ? reader_color_ : writer_color_ radius: radius_ } @@ -1133,7 +1164,8 @@ Item } IconSVG { visible: modelData["status"] != "OK" - name: "issues" + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } Rectangle { @@ -1141,7 +1173,8 @@ Item width: first_indentation_ /2 } IconSVG { - name: modelData["kind"] + name: modelData["kind"] == "DataReader" + ? "datareader" : "datawriter" size: icon_size_ } Label { @@ -1152,9 +1185,14 @@ Item MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - controller.endpoint_click(modelData["id"]) + if(mouse.button & Qt.RightButton) { + openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + } else { + controller.endpoint_click(modelData["id"]) + } } } } @@ -1230,16 +1268,6 @@ Item } } - // footer section to cut entities layout - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - height: elements_spacing_ - width: entity_box_width_ + 2*elements_spacing_ - color: "white" - z: 14 - } - // Empty screen message Rectangle { anchors.fill: parent @@ -1272,6 +1300,19 @@ Item // Obtain given domain id graph JSON model function load_model() { + filter_model_by_topic ("") + } + + // Filter model by topic + function filter_model_by_topic (topic_id) + { + // topic id management + var topic_names = [] + if (topic_id != "" && !filtered_topics_.includes(topic_id)) + { + filtered_topics_[filtered_topics_.length] = topic_id; + } + // clear internal models clear_graph() @@ -1299,16 +1340,36 @@ Item var metatraffic_ = new_model["topics"][topic]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { - new_topics[new_topics.length] = { - "id":topic, - "kind":new_model["topics"][topic]["kind"], - "alias":new_model["topics"][topic]["alias"] + if (filtered_topics_.length > 0) + { + for (var i = 0; i < filtered_topics_.length; i++) + { + if (filtered_topics_[i] == topic) + { + topic_names[i] = new_model["topics"][topic]["alias"] + new_topics[new_topics.length] = { + "id":topic, + "kind":"Topic", + "alias":new_model["topics"][topic]["alias"] + } + } + } + } + else + { + new_topics[new_topics.length] = { + "id":topic, + "kind":"Topic", + "alias":new_model["topics"][topic]["alias"] + } } } } var accum_y = 0 + var temp_y = 0 for (var host in new_model["hosts"]) { + var discard_host = true var metatraffic_ = new_model["hosts"][host]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { @@ -1340,13 +1401,24 @@ Item var metatraffic_ = new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { - new_endpoints[new_endpoints.length] = { - "id":endpoint, - "kind":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["kind"], - "alias":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["alias"], - "status":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["status"], - "topic":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["topic"], - "accum_y":accum_y + if ((!filtered_topics_.length) || (filtered_topics_.length > 0 + && filtered_topics_.includes(new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["topic"]))) + { + discard_host = false + var kind = "DataWriter" + if (new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["kind"] == "datareader") + { + kind = "DataReader" + } + new_endpoints[new_endpoints.length] = { + "id":endpoint, + "kind":kind, + "alias":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["alias"], + "status":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["status"], + "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 @@ -1354,7 +1426,7 @@ Item } new_participants[new_participants.length] = { "id":participant, - "kind":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["kind"], + "kind": "DomainParticipant", "alias":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["alias"], "status":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["status"], "app_id":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["app_id"], @@ -1366,7 +1438,7 @@ Item } new_processes[new_processes.length] = { "id":process, - "kind":new_model["hosts"][host]["users"][user]["processes"][process]["kind"], + "kind":"Process", "alias":new_model["hosts"][host]["users"][user]["processes"][process]["alias"], "pid": new_model["hosts"][host]["users"][user]["processes"][process]["pid"], "status":new_model["hosts"][host]["users"][user]["processes"][process]["status"], @@ -1377,7 +1449,7 @@ Item } new_users[new_users.length] = { "id":user, - "kind":new_model["hosts"][host]["users"][user]["kind"], + "kind": "User", "alias":new_model["hosts"][host]["users"][user]["alias"], "status":new_model["hosts"][host]["users"][user]["status"], "processes":new_processes @@ -1385,15 +1457,23 @@ Item accum_y += elements_spacing_ } } - new_hosts[new_hosts.length] = { - "id":host, - "kind":new_model["hosts"][host]["kind"], - "alias":new_model["hosts"][host]["alias"], - "status":new_model["hosts"][host]["status"], - "users":new_users + if (!discard_host) + { + new_hosts[new_hosts.length] = { + "id":host, + "kind":"Host", + "alias":new_model["hosts"][host]["alias"], + "status":new_model["hosts"][host]["status"], + "users":new_users + } + accum_y += elements_spacing_ + temp_y = accum_y + } + else { + accum_y = temp_y } - accum_y += elements_spacing_ } + } model = { "kind": new_model["kind"], @@ -1428,7 +1508,31 @@ Item } // Update tab name with selected domain id - domainGraphLayout.update_tab_name("Domain " + domain_id + " View") + if (filtered_topics_.length > 0) + { + if (filtered_topics_.length == 1) + { + domainGraphLayout.update_tab_name(topic_names[0] + " Topic View") + } + else + { + var print_topic_names = topic_names[0] + for (var i = 1; i < topic_names.length -1; i++) + { + print_topic_names += ", " + topic_names[i] + } + if (print_topic_names.length-1 > 0) + { + print_topic_names += " and " + topic_names[topic_names.length-1] + } + + domainGraphLayout.update_tab_name(print_topic_names + " Topics View") + } + } + else + { + domainGraphLayout.update_tab_name("Domain " + domain_id + " View") + } } // remove drawn connections @@ -1458,4 +1562,87 @@ Item } } } + + // check if model contains entity + function contains_entity(domainEntityId, entityId) + { + // check if domainEntityId has content + if (domainEntityId != "") + { + // belongs to the current domain + if (entity_id.toString() != domainEntityId) + { + return false + } + } + // check all entities by entityId + + // check domain + if(entity_id.toString() == entityId) + { + return true + } + + // check topics + for (var topic in model["topics"]) + { + if (model["topics"][topic]["id"] == entityId) + { + return true + } + } + + // check entities + for (var host in model["hosts"]) + { + if (model["hosts"][host]["id"] == entityId) + { + return true + } + else + { + for (var user in model["hosts"][host]["users"]) + { + if (model["hosts"][host]["users"][user]["id"] == entityId) + { + return true + } + else + { + for (var process in model["hosts"][host]["users"][user]["processes"]) + { + if (model["hosts"][host]["users"][user]["processes"][process]["id"] == entityId) + { + return true + } + else + { + for (var participant in model["hosts"][host]["users"][user]["processes"][process]["participants"]) + { + if (model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["id"] == entityId) + { + return true + } + else + { + for (var endpoint in model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"]) + { + if (model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["id"] == entityId) + { + return true + } + } + } + } + } + } + } + } + } + } + + + // not found yet + return false + } } diff --git a/qml/EntitiesMenu.qml b/qml/EntitiesMenu.qml index 48b084f6..d43fcf69 100644 --- a/qml/EntitiesMenu.qml +++ b/qml/EntitiesMenu.qml @@ -7,12 +7,17 @@ import Theme 1.0 */ Menu { id: entitiesMenu + property string domainEntityId: "" property string entityId: "" property string currentAlias: "" property string entityKind: "" MenuItem { text: "Change alias" - onTriggered: changeAlias(menu.entityId, menu.currentAlias, menu.entityKind) + onTriggered: changeAlias(menu.domainEntityId, menu.entityId, menu.currentAlias, menu.entityKind) + } + MenuItem { + text: "View Problems" + onTriggered: filterProblemLog(menu.entityId) } } diff --git a/qml/EntityList.qml b/qml/EntityList.qml index 0746d97b..61c534d2 100644 --- a/qml/EntityList.qml +++ b/qml/EntityList.qml @@ -90,7 +90,7 @@ Rectangle { } onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.participant_click(id) } @@ -173,7 +173,7 @@ Rectangle { } onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.endpoint_click(id) } @@ -245,7 +245,7 @@ Rectangle { onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.locator_click(id) } diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index 5464d3fc..e6a2c211 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -20,17 +20,16 @@ Item { anchors.topMargin: arrow_margin_; anchors.bottomMargin: arrow_margin_ anchors.left: parent.left; anchors.right: parent.right anchors.leftMargin: left_margin; anchors.rightMargin: left_margin; - color: background_color + color: "white" } Rectangle { id: left_background - opacity: 0.70 anchors.top: parent.top; anchors.bottom: parent.bottom - anchors.topMargin: -2; anchors.bottomMargin: -2 + anchors.topMargin: arrow_margin_; anchors.bottomMargin: arrow_margin_ anchors.left: parent.left; anchors.right: parent.right anchors.leftMargin: parent.height /2; anchors.rightMargin: 5; - color: background_color + color: "white" } @@ -39,34 +38,26 @@ Item { Item { id: left_arrow_background visible: left_direction - height: arrow_size_ + 8 - width: arrow_size_ + 2 - opacity: 0.7 + height: arrow_size_ + 20 + width: arrow_size_ + clip: true anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - - Canvas { - id: left_canvas_background - - anchors.centerIn: parent - - height: parent.height / 2 - width: parent.width - - antialiasing:true; smooth:true - - onPaint: { - var ctx = left_canvas_background.getContext('2d') + anchors.left: parent.left; anchors.leftMargin: -4 + + IconSVG { + anchors.left: parent.left + anchors.top: parent.top + name: "left_arrow" + color: "white" + size: arrow_size_ + 10 + } - ctx.strokeStyle = "white" - ctx.lineWidth = left_canvas_background.width * 0.1 - ctx.beginPath() - ctx.moveTo(left_canvas_background.width, left_canvas_background.height * 0.001) - ctx.lineTo(12, left_canvas_background.height / 2 - 6) - ctx.lineTo(12, left_canvas_background.height / 2 + 6) - ctx.lineTo(left_canvas_background.width, left_canvas_background.height * 0.999) - ctx.stroke() - } + IconSVG { + anchors.left: parent.left + anchors.bottom: parent.bottom + name: "left_arrow" + color: "white" + size: arrow_size_ + 10 } } @@ -77,29 +68,12 @@ Item { height: arrow_size_ width: arrow_size_ anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - - Canvas { - id: left_canvas - - anchors.centerIn: parent + anchors.left: parent.left; anchors.leftMargin: -5 - height: parent.height / 2 - width: parent.width - - antialiasing:true; smooth:true - - onPaint: { - var ctx = left_canvas.getContext('2d') - - ctx.strokeStyle = arrow_color - ctx.lineWidth = left_canvas.width * 0.1 - ctx.beginPath() - ctx.moveTo(left_canvas.width, left_canvas.height * 0.05) - ctx.lineTo(0, left_canvas.height / 2) - ctx.lineTo(left_canvas.width, left_canvas.height * 0.95) - ctx.stroke() - } + IconSVG { + name: "left_arrow" + color: "grey" + size: arrow_size_ } } @@ -108,8 +82,8 @@ Item { id: base_arrow anchors.top: parent.top; anchors.bottom: parent.bottom anchors.left: parent.left; anchors.right: parent.right - anchors.leftMargin: left_direction ? 8 : 0 - anchors.rightMargin: right_direction ? 8 : 0 + anchors.leftMargin: left_direction ? 10 : 0 + anchors.rightMargin: right_direction ? 15 : 0 color: arrow_color } @@ -117,32 +91,15 @@ Item { Item { id: right_arrow visible: right_direction - height: arrow_size_ - width: arrow_size_ + height: arrow_size_ -4 + width: arrow_size_ -4 anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right; anchors.rightMargin: parent.height /2 + 2 - Canvas { - id: right_canvas - - anchors.centerIn: parent - - height: parent.height / 2 - width: parent.width - - antialiasing:true; smooth:true - - onPaint: { - var ctx = right_canvas.getContext('2d') - - ctx.strokeStyle = arrow_color - ctx.lineWidth = right_canvas.width * 0.1 - ctx.beginPath() - ctx.moveTo(0, right_canvas.height * 0.05) - ctx.lineTo(right_canvas.width, right_canvas.height / 2 -1) - ctx.lineTo(0, right_canvas.height * 0.95) - ctx.stroke() - } + IconSVG { + name: "right_arrow" + color: "grey" + size: arrow_size_-5 } } } diff --git a/qml/LeftPanel.qml b/qml/LeftPanel.qml index 4f3fe822..5247a047 100644 --- a/qml/LeftPanel.qml +++ b/qml/LeftPanel.qml @@ -40,6 +40,9 @@ RowLayout { signal explorerPhysicalChanged(bool status) signal explorerLogicalChanged(bool status) signal explorerEntityInfoChanged(bool status) + signal open_topic_view(string domainEntityId, string domainId, string entityId) + signal refresh_domain_graph_view(string domainEntityId, string entityId) + signal filter_problem_log(string entityId) MonitoringPanel { id: monitoringPanel @@ -65,26 +68,52 @@ RowLayout { id: entitiesMenu } + TopicMenu { + id: topicMenu + } + IssuesPanel { id: issuesPanel Layout.fillHeight: true visible: (visiblePanel === panelItem[LeftPanel.LeftSubPanel.Issues]) ? true : false } - function changeAlias(entityId, currentAlias, entityKind) { + function changeAlias(domainEntityId, entityId, currentAlias, entityKind) { + aliasDialog.domainEntityId = domainEntityId aliasDialog.entityId = entityId aliasDialog.currentAlias = currentAlias aliasDialog.entityKind = entityKind aliasDialog.open() } - function openEntitiesMenu(entityId, currentAlias, entityKind) { + function openEntitiesMenu(domainEntityId, entityId, currentAlias, entityKind) { + entitiesMenu.domainEntityId = domainEntityId entitiesMenu.entityId = entityId entitiesMenu.currentAlias = currentAlias entitiesMenu.entityKind = entityKind entitiesMenu.popup() } + function openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) { + topicMenu.domainEntityId = domainEntityId + topicMenu.domainId = domainId + topicMenu.entityId = entityId + topicMenu.currentAlias = currentAlias + topicMenu.entityKind = entityKind + topicMenu.popup() + } + + function openTopicView(domainEntityId, domainId, entityId) { + leftPanel.open_topic_view(domainEntityId, domainId, entityId) + } + + function refreshDomainGraphView(domainEntityId, entityId) { + leftPanel.refresh_domain_graph_view(domainEntityId, entityId) + } + function filterProblemLog(entityId){ + leftPanel.filter_problem_log(entityId) + } + function expandAll(view, model) { for(var i=0; i < model.rowCount(); i++) { var index = model.index(i, 0) diff --git a/qml/LogicalView.qml b/qml/LogicalView.qml index cbbfa464..999950e4 100644 --- a/qml/LogicalView.qml +++ b/qml/LogicalView.qml @@ -63,6 +63,7 @@ Rectangle { height: domainListColumn.childrenRect.height property var domainId: id + property var domainName: name property int domainIdx: index property var topicList: topicList @@ -96,7 +97,7 @@ Rectangle { } onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu(domainId, id, name, kind) } else { controller.domain_click(id) } @@ -166,7 +167,7 @@ Rectangle { onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openTopicMenu(domainId, domainName, id, name, kind) } else { controller.topic_click(id) } diff --git a/qml/Panels.qml b/qml/Panels.qml index 84df2717..bd2a1a53 100644 --- a/qml/Panels.qml +++ b/qml/Panels.qml @@ -30,6 +30,9 @@ RowLayout { // If is set to true, the left sidebar was opened, and false if it was closed. property bool prevFullScreenLeftSidebarState: true + // private properties + property int status_layout_height: status_layout_min_height_ + signal openCloseLeftSideBar signal changeChartboxLayout(int chartsPerRow) signal explorerDDSEntitiesChanged(bool status) @@ -37,6 +40,10 @@ RowLayout { signal explorerLogicalChanged(bool status) signal explorerEntityInfoChanged(bool status) + // Read only design properties + readonly property int status_layout_min_height_: 24 + + onOpenCloseLeftSideBar: { if (panels.showLeftSidebar) { iconsVBar.iconClicked(iconsVBar.selected) @@ -90,24 +97,66 @@ RowLayout { onExplorerPhysicalChanged: panels.explorerPhysicalChanged(status) onExplorerLogicalChanged: panels.explorerLogicalChanged(status) onExplorerEntityInfoChanged: panels.explorerEntityInfoChanged(status) + onOpen_topic_view: tabs.open_topic_view(domainEntityId, domainId, entityId) + onRefresh_domain_graph_view: tabs.refresh_domain_graph_view(domainEntityId, entityId) + onFilter_problem_log: statusLayout.filter_problem_log(entityId) } - TabLayout { - id: tabs + Rectangle { SplitView.fillWidth: true - clip: true - onFullScreenChanged: { - if (fullScreen) { - if (showLeftSidebar) { - openCloseLeftSideBar() - prevFullScreenLeftSidebarState = true - } else { - prevFullScreenLeftSidebarState = false + SplitView { + id: tabsSplitView + anchors.fill: parent + orientation: Qt.Vertical + + TabLayout { + id: tabs + SplitView.fillWidth: true + SplitView.fillHeight: true + SplitView.preferredHeight: parent.height - parent.height / 5 + clip: true + + onFullScreenChanged: { + if (fullScreen) { + if (showLeftSidebar) { + openCloseLeftSideBar() + prevFullScreenLeftSidebarState = true + } else { + prevFullScreenLeftSidebarState = false + } + } else { + if (!showLeftSidebar && prevFullScreenLeftSidebarState) { + openCloseLeftSideBar() + } + } } - } else { - if (!showLeftSidebar && prevFullScreenLeftSidebarState) { - openCloseLeftSideBar() + onOpenEntitiesMenu: { + panels.openEntitiesMenu(domainEntityId, entityId, currentAlias, entityKind) + } + onOpenTopicMenu: { + panels.openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) + } + } + StatusLayout { + id: statusLayout + SplitView.preferredHeight: status_layout_height + SplitView.minimumHeight: status_layout_min_height_ + clip: true + current_status: StatusLayout.Status.Collapsed + footer_height: status_layout_min_height_ + + onClose_status_layout: { + status_layout_height = status_layout_min_height_ + statusLayout.current_status = StatusLayout.Status.Closed + } + onCollapse_status_layout: { + status_layout_height = tabsSplitView.height / 5 + statusLayout.current_status = StatusLayout.Status.Collapsed + } + onExpand_status_layout: { + status_layout_height = tabsSplitView.height + statusLayout.current_status = StatusLayout.Status.Expanded } } } @@ -145,4 +194,12 @@ RowLayout { function changeExplorerEntityInfo(status) { leftPanel.changeExplorerEntityInfo(status) } + + function openEntitiesMenu(domainEntityId, entityId, currentAlias, entityKind) { + leftPanel.openEntitiesMenu(domainEntityId, entityId, currentAlias, entityKind) + } + + function openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) { + leftPanel.openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) + } } diff --git a/qml/PhysicalView.qml b/qml/PhysicalView.qml index 0fa8cb55..e698b445 100644 --- a/qml/PhysicalView.qml +++ b/qml/PhysicalView.qml @@ -90,7 +90,7 @@ Rectangle { } onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.host_click(id) } @@ -174,7 +174,7 @@ Rectangle { } onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.user_click(id) } @@ -246,7 +246,7 @@ Rectangle { onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(id, name, kind) + openEntitiesMenu("", id, name, kind) } else { controller.process_click(id) } diff --git a/qml/ProblemTreeView.qml b/qml/ProblemTreeView.qml new file mode 100644 index 00000000..581c75b7 --- /dev/null +++ b/qml/ProblemTreeView.qml @@ -0,0 +1,175 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + + +import QtQuick 2.15 +import QtQuick.Window 2.15 +import QtQuick.Controls 2.15 +import QtQml 2.15 + +Flickable { + id: root + + implicitWidth: 400 + implicitHeight: 400 + clip: true + + property var model + readonly property alias currentIndex: tree.selectedIndex + readonly property alias currentItem: tree.currentItem + property var currentData + + property alias handle: tree.handle + property alias contentItem: tree.contentItem + property Component highlight: Rectangle { + color: root.selectedColor + } + + property alias selectionEnabled: tree.selectionEnabled + property alias hoverEnabled: tree.hoverEnabled + + property alias color: tree.color + property alias handleColor: tree.handleColor + property alias hoverColor: tree.hoverColor + property alias selectedColor: tree.selectedColor + property alias selectedItemColor: tree.selectedItemColor + + property alias rowHeight: tree.rowHeight + property alias rowPadding: tree.rowPadding + property alias rowSpacing: tree.rowSpacing + + property alias fontMetrics: tree.fontMetrics + property alias font: tree.font + + enum Handle { + Triangle, + TriangleSmall, + TriangleOutline, + TriangleSmallOutline, + Chevron, + Arrow + } + + signal problem_focused() + signal clean_filter() + + property int handleStyle: ProblemTreeView.Handle.TriangleSmallOutline + + contentHeight: tree.height + contentWidth: width + boundsBehavior: Flickable.StopAtBounds + ScrollBar.vertical: ScrollBar {} + + Connections { function onCurrentIndexChanged() { if(currentIndex) currentData = model.data(currentIndex) } } + + ProblemTreeViewItem { + id: tree + + model: root.model + parentIndex: model.rootIndex() + childCount: model.rowCount(parentIndex) + + itemLeftPadding: 0 + color: root.color + handleColor: root.handleColor + hoverColor: root.hoverColor + selectedColor: root.selectedColor + selectedItemColor: root.selectedItemColor + 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 + } + + + } + } + + Loader { + id: highlightLoader + sourceComponent: highlight + + width: root.width + height: root.rowHeight + z: 0 + visible: root.selectionEnabled && tree.currentItem !== null + + Binding { + target: highlightLoader.item + property: "y" + value: tree.currentItem ? tree.currentItem.mapToItem(tree, 0, 0).y + tree.anchors.topMargin : 0 + when: highlightLoader.status === Loader.Ready + } + } + + function indicatorToString(handle){ + switch (handle){ + case ProblemTreeView.Handle.Triangle: return "▶"; + case ProblemTreeView.Handle.TriangleSmall: return "►"; + case ProblemTreeView.Handle.TriangleOutline: return "▷"; + case ProblemTreeView.Handle.TriangleSmallOutline: return "⊳"; + case ProblemTreeView.Handle.Chevron: return "❱"; + case ProblemTreeView.Handle.Arrow: return "➤"; + default: return "▶"; + } + } + + 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() + } + } +} diff --git a/qml/ProblemTreeViewItem.qml b/qml/ProblemTreeViewItem.qml new file mode 100644 index 00000000..beea7514 --- /dev/null +++ b/qml/ProblemTreeViewItem.qml @@ -0,0 +1,406 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Theme 1.0 + +Item { + id: root + + // model properties + + property var model + property var parentIndex + property var childCount + + property var currentItem: null + property var selectedIndex: null + property var hoveredIndex: null + + // layout properties + + property bool selectionEnabled: false + property bool hoverEnabled: false + + property int itemLeftPadding: 0 + property int rowHeight: 24 + property int rowPadding: 30 + property int rowSpacing: 6 + + property color color: "black" + property color inactive: "#808080" + property color handleColor: color + property color hoverColor: "lightgray" + property color selectedColor: "silver" + property color selectedItemColor: color + + property string defaultIndicator: "▶" + property FontMetrics fontMetrics: FontMetrics { + font.pointSize: Theme.font.pointSize + } + property alias font: root.fontMetrics.font + enum Role { Id=257, Status, Kind, Value, Description, Alive, Name } + + // public signal + signal toggled() + + // private (internal) signals + signal focus_(int entityId) + + implicitWidth: parent.width + implicitHeight: childrenRect.height + + // Components + + property Component handle: Rectangle { + id: handle + + implicitWidth: 20 + implicitHeight: 20 + Layout.leftMargin: parent.spacing + rotation: currentRow.expanded ? 90 : 0 + opacity: currentRow.hasChildren + color: "transparent" + + Text { + anchors.centerIn: parent + text: defaultIndicator + font: root.font + antialiasing: true + color: currentRow.isSelectedIndex ? root.selectedItemColor : root.handleColor + } + } + + property Component contentItem: Item { + id: contentData + + + IconSVG { + id: status_icon + visible: !(currentRow.currentId === "all" && currentRow.currentKind === "INVALID") + anchors.left: parent.left; anchors.leftMargin: -5 + anchors.verticalCenter: parent.verticalCenter + name: currentRow.currentStatus ? "error" :"issues" + color: currentRow.currentAlive ? currentRow.currentStatus ? "red" :"black" : "grey" + size: 15 + } + + Text { + id: entity_name + anchors.left: status_icon.right; anchors.leftMargin: 5 + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + + color:currentRow.currentAlive ? currentRow.isSelectedIndex ? root.selectedItemColor : root.color : root.inactive + text: currentRow.currentData + font: root.font + } + + Text { + id: id_value + anchors.left: entity_name.right; anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + + color:currentRow.currentAlive ? currentRow.isSelectedIndex ? root.selectedItemColor : root.color : root.inactive + text: currentRow.currentId == undefined || currentRow.currentValue == undefined ? "" : + currentRow.currentId != "all" && currentRow.currentKind === "INVALID" ? + currentRow.currentId === "all" ? "" : "(" + currentRow.currentValue + ")" : currentRow.currentValue + font: root.font + } + + Text { + id: description + anchors.left: id_value.right; anchors.leftMargin: 20 + anchors.right: parent.right; anchors.rightMargin: 10 + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignRight + height: parent.height + elide: Text.ElideRight + + color:currentRow.currentAlive ? currentRow.isSelectedIndex ? root.selectedItemColor : root.color : root.inactive + text: currentRow.currentId != "all" && currentRow.currentKind === "INVALID" ? + currentRow.currentId === "all" ? "" : + "Entity ID: " + currentRow.currentId : currentRow.currentDescription + font.pointSize: Theme.font.pointSize + font.italic: true + onLinkActivated: Qt.openUrlExternally(link) + + MouseArea { + visible: currentRow.currentDescription.includes("href") + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } + } + } + + property Component hoverComponent: Rectangle { + width: parent.width + height: parent.height + color: currentRow.isHoveredIndex && !currentRow.isSelectedIndex ? root.hoverColor : "transparent" + } + + // Body + + ColumnLayout { + width: parent.width + spacing: 0 + + Repeater { + id: repeater + model: childCount + Layout.fillWidth: true + + delegate: ColumnLayout { + id: itemColumn + + Layout.leftMargin: itemLeftPadding + spacing: 0 + + QtObject { + id: _prop + + property var currentIndex: root.model.index(index, 0, parentIndex) + property var currentData: root.model.data(currentIndex) + property var currentId: root.model.data(currentIndex, ProblemTreeViewItem.Role.Id) + property var currentStatus: root.model.data(currentIndex, ProblemTreeViewItem.Role.Status) + property var currentKind: root.model.data(currentIndex, ProblemTreeViewItem.Role.Kind) + property var currentValue: root.model.data(currentIndex, ProblemTreeViewItem.Role.Value) + 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 selected: false + property int itemChildCount: root.model.rowCount(currentIndex) + readonly property int depth: root.model.depth(currentIndex) + readonly property bool hasChildren: itemChildCount > 0 + readonly property bool isSelectedIndex: root.selectionEnabled && currentIndex === root.selectedIndex + readonly property bool isHoveredIndex: root.hoverEnabled && currentIndex === root.hoveredIndex + readonly property bool isSelectedAndHoveredIndex: hoverEnabled && selectionEnabled && isHoveredIndex && isSelectedIndex + + function toggle(){ + if(_prop.hasChildren) + { + _prop.expanded = !_prop.expanded + } + root.toggled() + } + } + + Connections { + target: root.model + ignoreUnknownSignals: true + function onLayoutChanged() { + const parent = root.model.index(index, 0, parentIndex) + _prop.itemChildCount = root.model.rowCount(parent) + // refresh counter + var new_value = root.model.data(_prop.currentIndex, ProblemTreeViewItem.Role.Value) + if (new_value != undefined) + { + _prop.currentValue = new_value + } + } + } + + Connections { + target: root + function onFocus_(entityId){ + if(parseInt(_prop.currentId) === parseInt(entityId)){ + _prop.expanded = true + } else { + _prop.expanded = false + } + } + } + + Item { + id: column + + Layout.fillWidth: true + + width: row.implicitWidth + height: Math.max(row.implicitHeight, root.rowHeight) + + RowLayout { + id: row + + anchors.fill: parent + Layout.fillHeight: true + + z: 1 + spacing: root.rowSpacing + + // handle + Loader { + id: indicatorLoader + sourceComponent: handle + + Layout.leftMargin: parent.spacing + + property QtObject currentRow: _prop + + TapHandler { onSingleTapped: _prop.toggle() } + } + + // Content + Loader { + id: contentItemLoader + sourceComponent: contentItem + + Layout.fillWidth: true + height: rowHeight + + property QtObject currentRow: _prop + + Connections { + target: root.model + ignoreUnknownSignals: true + function onDataChanged(modelIndex) { + const changedId = modelIndex.internalId + const currentId = _prop.currentIndex.internalId + if(changedId === currentId){ + contentItemLoader.currentRow.currentData = root.model.data(modelIndex); + } + } + } + } + + TapHandler { + onDoubleTapped: _prop.toggle() + onSingleTapped: { + root.currentItem = _prop.currentItem + root.selectedIndex = _prop.currentIndex + } + } + } + + Loader { + id: hoverLoader + sourceComponent: hoverComponent + + width: row.width + (1 + _prop.depth * rowPadding) + height: parent.height + + x: -(_prop.depth * rowPadding) + z: 0 + + clip: false + + property QtObject currentRow: _prop + + HoverHandler { + onHoveredChanged: { + if(root.hoverEnabled){ + if(hovered && root.hoveredIndex !== _prop.currentIndex) + root.hoveredIndex = _prop.currentIndex + if(!hovered && root.hoveredIndex === _prop.currentIndex) + root.hoveredIndex = null + } + } + } + } + + } + + // loader to populate the children row for each node + Loader { + id: loader + + Layout.fillWidth: true + + source: "ProblemTreeViewItem.qml" + visible: _prop.expanded + + onLoaded: { + item.model = root.model + item.parentIndex = _prop.currentIndex + item.childCount = _prop.itemChildCount + } + + Connections { + target: root.model + ignoreUnknownSignals: true + function onLayoutChanged() { + const parent = root.model.index(index, 0, parentIndex) + loader.item.childCount = root.model.rowCount(parent) + } + + function onToggled() { + root.toggled() + } + } + + Binding { target: loader.item; property: "model"; value: root.model; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "handle"; value: root.handle; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "contentItem"; value: root.contentItem; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "currentItem"; value: root.currentItem; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedIndex"; value: root.selectedIndex; when: loader.status == Loader.Ready } + Binding { target: root; property: "currentItem"; value: loader.item.currentItem; when: loader.status == Loader.Ready } + Binding { target: root; property: "selectedIndex"; value: loader.item.selectedIndex; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "color"; value: root.color; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "handleColor"; value: root.handleColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "hoverEnabled"; value: root.hoverEnabled; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "hoverColor"; value: root.hoverColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectionEnabled"; value: root.selectionEnabled; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedColor"; value: root.selectedColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedItemColor"; value: root.selectedItemColor; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "itemLeftPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowHeight"; value: root.rowHeight; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowSpacing"; value: root.rowSpacing; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "fontMetrics"; value: root.selectedItemColor; when: loader.status == Loader.Ready } + } + } + } + } + + function focus (entityId) { + root.focus_(entityId) + } +} diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml new file mode 100644 index 00000000..4f7a6817 --- /dev/null +++ b/qml/StatusLayout.qml @@ -0,0 +1,305 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.15 + +import Theme 1.0 + +Item +{ + id: statusLayout + + // Public properties + enum Status {Closed, Expanded, Collapsed} + property int current_status: StatusLayout.Status.Closed + required property int footer_height + + // Public signals + signal close_status_layout() + signal expand_status_layout() + signal collapse_status_layout() + + // Private properties + property bool filter_visible_: false + + // Private signals + signal focus_entity_(int entityId) + signal clean_filter_() + + // Read only design properties (sizes and colors) + readonly property int tabs_height_: 30 + readonly property int tabs_width_: 100 + readonly property int elements_spacing_: 8 + readonly property int separator_line_: 2 + readonly property string grey_background_: "#eaeaea" + + property int spacingIconLabel: 8 + property int iconSize: 18 + property int firstIndentation: 5 + property int secondIndentation: firstIndentation + iconSize + spacingIconLabel + + + TabView { + id: tab_view + anchors.top: parent.top + anchors.bottom: separator_line.top + width: parent.width + + Tab { + title: "Problems" + Rectangle { + + color: "white" + + ProblemTreeView { + id: status_tree_view + anchors.fill: parent + anchors.margins: 1 + + model: problemModel + + onProblem_focused:{ + collapse_status_layout() + } + + onClean_filter: { + statusLayout.clean_filter_() + } + + Connections { + target: statusLayout + + function onFocus_entity_(entityId) { + status_tree_view.focus_entity(entityId) + } + } + } + } + } + style: TabViewStyle { + frameOverlap: 1 + tab: Rectangle { + color: styleData.selected ? "white" : Theme.lightGrey + implicitWidth: Math.max(text.width + 10, tabs_width_) + implicitHeight: tabs_height_ + radius: 4 + + Rectangle { + width: parent.width + height: parent.height/2 + anchors.bottom: parent.bottom + anchors.left: parent.left + color: parent.color + } + Text { + id: text + anchors.centerIn: parent + text: styleData.title + } + } + tabBar: Rectangle { + anchors.top: parent.top + width: parent.width + height: tabs_height_ + color: grey_background_ + + IconSVG { + id: close_icon + anchors.right: parent.right + anchors.rightMargin: elements_spacing_ *2 + anchors.verticalCenter: parent.verticalCenter + name: "cross" + size: parent.height - elements_spacing_ *3/2 + + MouseArea { + anchors.centerIn: parent + width: parent.width + 2*elements_spacing_ + height: parent.height + 2*elements_spacing_ + + onClicked: { + close_status_layout() + } + } + } + + Rectangle { + id: rect + anchors.right: close_icon.left + anchors.rightMargin: elements_spacing_ *2 + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: elements_spacing_/2 + width: parent.height - elements_spacing_ + height: parent.height - elements_spacing_ + color: "transparent" + + IconSVG { + id: expand_icon + + name: "expand" + size: parent.width + } + + MouseArea { + anchors.centerIn: parent + width: parent.width + 2*elements_spacing_ + height: parent.height + 2*elements_spacing_ + + onClicked: { + if (statusLayout.current_status === StatusLayout.Status.Expanded) + { + collapse_status_layout() + expand_icon.name = "expand" + + } + else if (statusLayout.current_status === StatusLayout.Status.Collapsed) + { + expand_status_layout() + expand_icon.name = "collapse" + } + } + } + } + + IconSVG { + id: filter_empty_icon + visible: !statusLayout.filter_visible_ + anchors.right: rect.left + anchors.rightMargin: elements_spacing_ *2 + anchors.verticalCenter: parent.verticalCenter + name: "filter_empty" + size: parent.height - elements_spacing_ + } + + 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_ + } + Connections { + target: statusLayout + + function onFocus_entity_(entityId) { + statusLayout.filter_visible_ = true + } + + function onClean_filter_() { + statusLayout.filter_visible_ = false + } + } + } + } + } + + Rectangle { + id: separator_line + anchors.bottom: icon_section.top + width: parent.width + height: separator_line_ + + color: Theme.grey + } + + Rectangle { + id: icon_section + anchors.bottom: parent.bottom + height: footer_height + width: parent.width + color: grey_background_ + + Component.onCompleted: { close_status_layout() } + + IconSVG { + id: error_icon + anchors.left: parent.left + anchors.leftMargin: elements_spacing_ + anchors.verticalCenter: parent.verticalCenter + name: "error" + size: parent.height - elements_spacing_ + } + Label { + id: error_value + anchors.left: error_icon.right + anchors.leftMargin: elements_spacing_/2 + anchors.verticalCenter: parent.verticalCenter + text: "0" + } + IconSVG { + id: warning_icon + anchors.left: error_icon.right + anchors.leftMargin: elements_spacing_ * 4 + anchors.verticalCenter: parent.verticalCenter + name: "issues" + size: parent.height - elements_spacing_ + } + Label { + id: warning_value + anchors.left: warning_icon.right + anchors.leftMargin: elements_spacing_/2 + anchors.verticalCenter: parent.verticalCenter + text: "0" + } + + Connections + { + target: controller + function onUpdate_status_counters(errors, warnings) { + error_value.text = errors + warning_value.text = warnings + } + } + /*IconSVG { + id: info_icon + anchors.left: warning_value.right + anchors.leftMargin: elements_spacing_ + name: "info" + size: parent.height - elements_spacing_ -1 + anchors.verticalCenter: parent.verticalCenter + } + Label { + id: info_value + anchors.left: info_icon.right + anchors.leftMargin: elements_spacing_/2 + anchors.verticalCenter: parent.verticalCenter + text: "19" + }*/ + MouseArea { + anchors.fill: parent + onClicked: { + if (current_status === StatusLayout.Status.Collapsed) + { + close_status_layout() + } + else + { + collapse_status_layout() + } + } + } + } + + function filter_problem_log(entityId) { + statusLayout.focus_entity_(entityId) + } +} diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index 8de5cfaf..baa78f31 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -19,12 +19,18 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 +import Theme 1.0 + Item { id: tabLayout // Public properties property bool fullScreen: false // ChartsLayout inherited var + // Public signals + signal openEntitiesMenu(string domainEntityId, string entityId, string currentAlias, string entityKind) + signal openTopicMenu(string domainEntityId, string domainId, string entityId, string currentAlias, string entityKind) + // Private properties property int current_: 0 // current tab displayed property int last_index_: 1 // force unique idx on QML components @@ -34,6 +40,7 @@ Item { // private signals signal open_domain_view_(int stack_id, int entity_id, int domain_id) signal initialize_domain_view_(int stack_id, int entity_id, int domain_id) + signal filter_domain_view_by_topic_(int stack_id, int domain_entity_id, string topic_id) // Read only design properties readonly property int max_tabs_: 15 @@ -95,10 +102,36 @@ Item { width: childrenRect.width spacing: 60 Button { + id: chart_button width: 400; height: 400 + background: Rectangle { + color: Theme.whiteSmoke + border.width: 3 + border.color: chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + radius: 40 + + Image { + anchors.centerIn: parent + anchors.verticalCenterOffset: -50 + smooth: true + source: "/resources/images/graphs.svg/" + property int size: 25 + sourceSize.width: size * 16 + sourceSize.height: size * 9 + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom; anchors.bottomMargin: 50 + width: parent.width + text: "Chart View" + horizontalAlignment: Text.AlignHCenter + font.pointSize: 20 + color: chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + } + } anchors.verticalCenter: parent.verticalCenter enabled: !disable_chart_selection_ - text: "Chart View" onClicked: { if (!disable_chart_selection_) { @@ -114,9 +147,35 @@ Item { } } Button { + id: domain_view_button width: 400; height: 400 + background: Rectangle { + color: Theme.whiteSmoke + border.width: 3 + border.color: domain_view_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + radius: 40 + + Image { + anchors.centerIn: parent + anchors.verticalCenterOffset: -50 + smooth: true + source: "/resources/images/domain_graph.svg/" + property int size: 30 + sourceSize.width: size * 16 + sourceSize.height: size * 9 + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom; anchors.bottomMargin: 50 + width: parent.width + text: "Domain View" + horizontalAlignment: Text.AlignHCenter + font.pointSize: 20 + color: domain_view_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + } + } anchors.verticalCenter: parent.verticalCenter - text: "Domain View" onClicked: { if (mainApplicationView.monitors == 0) { @@ -166,6 +225,13 @@ Item { } } + onOpenEntitiesMenu: { + tabLayout.openEntitiesMenu(domainEntityId, entityId, currentAlias, entityKind) + } + onOpenTopicMenu: { + tabLayout.openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) + } + Connections { target: tabLayout @@ -177,6 +243,14 @@ Item { domainGraphLayout.load_model() } } + + function onFilter_domain_view_by_topic_(stack_id, domain_entity_id, topic_id) { + if (domainGraphLayout.component_id == stack_id && + domainGraphLayout.entity_id == domain_entity_id) + { + domainGraphLayout.filter_model_by_topic(topic_id) + } + } } } @@ -185,7 +259,7 @@ Item { Connections { target: tabLayout - function onOpen_domain_view_(stack_id, entity_id, domain_id) { + function onOpen_domain_view_(stack_id, entity_id, domain_id, topic_id) { if (stack.stack_id == stack_id) { if (stack.deep > 1) @@ -423,7 +497,8 @@ Item { { for (var i=0; i 0) { controller.domain_click(stack_layout.children[i].currentItem.entity_id) break; @@ -540,4 +615,23 @@ Item { function chartsLayout_saveAllCSV() { chartsLayout.saveAllCSV() } + + function open_topic_view(domainEntityId, domainId, entityId) { + create_new_tab() + open_domain_view_(tabLayout.tab_model_[current_]["stack_id"], domainEntityId, domainId) + filter_domain_view_by_topic_(tabLayout.tab_model_[current_]["stack_id"], domainEntityId, entityId) + } + + function refresh_domain_graph_view(domainEntityId, entityId) { + for (var i=0; i. + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import Theme 1.0 + +/* + Menu containing the possible actions that can be performed on any DDS, physical and logical entity. + */ +Menu { + id: topicMenu + property string domainEntityId: "" + property string domainId: "" + property string entityId: "" + property string currentAlias: "" + property string entityKind: "" + + MenuItem { + text: "Change alias" + onTriggered: changeAlias(menu.domainEntityId, menu.entityId, menu.currentAlias, menu.entityKind) + } + MenuItem { + text: "View problems" + onTriggered: filterProblemLog(menu.entityId) + } + MenuItem { + text: "Filter graph view" + onTriggered: openTopicView(menu.domainEntityId, menu.domainId, menu.entityId) + } +} diff --git a/resources/images/domain_graph.svg b/resources/images/domain_graph.svg new file mode 100644 index 00000000..45bc9b26 --- /dev/null +++ b/resources/images/domain_graph.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/collapse/collapse_black.svg b/resources/images/icons/collapse/collapse_black.svg new file mode 100644 index 00000000..9d2bb38b --- /dev/null +++ b/resources/images/icons/collapse/collapse_black.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/collapse/collapse_eProsimaLightBlue.svg b/resources/images/icons/collapse/collapse_eProsimaLightBlue.svg new file mode 100644 index 00000000..32e7586b --- /dev/null +++ b/resources/images/icons/collapse/collapse_eProsimaLightBlue.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/collapse/collapse_grey.svg b/resources/images/icons/collapse/collapse_grey.svg new file mode 100644 index 00000000..1f9eaba8 --- /dev/null +++ b/resources/images/icons/collapse/collapse_grey.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/collapse/collapse_white.svg b/resources/images/icons/collapse/collapse_white.svg new file mode 100644 index 00000000..1be200e0 --- /dev/null +++ b/resources/images/icons/collapse/collapse_white.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/cross/cross_red.svg b/resources/images/icons/cross/cross_red.svg new file mode 100644 index 00000000..ea6821b4 --- /dev/null +++ b/resources/images/icons/cross/cross_red.svg @@ -0,0 +1,5 @@ + + +Layer 1 + + \ No newline at end of file diff --git a/resources/images/icons/error/error_black.svg b/resources/images/icons/error/error_black.svg new file mode 100644 index 00000000..f5c62a0d --- /dev/null +++ b/resources/images/icons/error/error_black.svg @@ -0,0 +1,10 @@ + + +Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/error/error_eProsimaLightBlue.svg b/resources/images/icons/error/error_eProsimaLightBlue.svg new file mode 100644 index 00000000..277fd56f --- /dev/null +++ b/resources/images/icons/error/error_eProsimaLightBlue.svg @@ -0,0 +1,10 @@ + + +Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/error/error_grey.svg b/resources/images/icons/error/error_grey.svg new file mode 100644 index 00000000..43e12705 --- /dev/null +++ b/resources/images/icons/error/error_grey.svg @@ -0,0 +1,10 @@ + + +Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/error/error_red.svg b/resources/images/icons/error/error_red.svg new file mode 100644 index 00000000..33c5370a --- /dev/null +++ b/resources/images/icons/error/error_red.svg @@ -0,0 +1,10 @@ + + +Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/error/error_white.svg b/resources/images/icons/error/error_white.svg new file mode 100644 index 00000000..6ecb6905 --- /dev/null +++ b/resources/images/icons/error/error_white.svg @@ -0,0 +1,10 @@ + + +Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/expand/expand_black.svg b/resources/images/icons/expand/expand_black.svg new file mode 100644 index 00000000..650b4682 --- /dev/null +++ b/resources/images/icons/expand/expand_black.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/expand/expand_eProsimaLightBlue.svg b/resources/images/icons/expand/expand_eProsimaLightBlue.svg new file mode 100644 index 00000000..1d1eab90 --- /dev/null +++ b/resources/images/icons/expand/expand_eProsimaLightBlue.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/expand/expand_grey.svg b/resources/images/icons/expand/expand_grey.svg new file mode 100644 index 00000000..d268e18b --- /dev/null +++ b/resources/images/icons/expand/expand_grey.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/expand/expand_white.svg b/resources/images/icons/expand/expand_white.svg new file mode 100644 index 00000000..09cc7c34 --- /dev/null +++ b/resources/images/icons/expand/expand_white.svg @@ -0,0 +1 @@ +Layer 1 diff --git a/resources/images/icons/filter_empty/filter_empty_black.svg b/resources/images/icons/filter_empty/filter_empty_black.svg new file mode 100644 index 00000000..9a0211e5 --- /dev/null +++ b/resources/images/icons/filter_empty/filter_empty_black.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_empty/filter_empty_eProsimaLightBlue.svg b/resources/images/icons/filter_empty/filter_empty_eProsimaLightBlue.svg new file mode 100644 index 00000000..9003c643 --- /dev/null +++ b/resources/images/icons/filter_empty/filter_empty_eProsimaLightBlue.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_empty/filter_empty_grey.svg b/resources/images/icons/filter_empty/filter_empty_grey.svg new file mode 100644 index 00000000..36c8ba78 --- /dev/null +++ b/resources/images/icons/filter_empty/filter_empty_grey.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_empty/filter_empty_white.svg b/resources/images/icons/filter_empty/filter_empty_white.svg new file mode 100644 index 00000000..f57f44bc --- /dev/null +++ b/resources/images/icons/filter_empty/filter_empty_white.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_full/filter_full_black.svg b/resources/images/icons/filter_full/filter_full_black.svg new file mode 100644 index 00000000..27967f66 --- /dev/null +++ b/resources/images/icons/filter_full/filter_full_black.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_full/filter_full_eProsimaLightBlue.svg b/resources/images/icons/filter_full/filter_full_eProsimaLightBlue.svg new file mode 100644 index 00000000..f5e231a6 --- /dev/null +++ b/resources/images/icons/filter_full/filter_full_eProsimaLightBlue.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_full/filter_full_grey.svg b/resources/images/icons/filter_full/filter_full_grey.svg new file mode 100644 index 00000000..b5652197 --- /dev/null +++ b/resources/images/icons/filter_full/filter_full_grey.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/filter_full/filter_full_white.svg b/resources/images/icons/filter_full/filter_full_white.svg new file mode 100644 index 00000000..21bbf614 --- /dev/null +++ b/resources/images/icons/filter_full/filter_full_white.svg @@ -0,0 +1,3 @@ + + +Layer 1 \ No newline at end of file diff --git a/resources/images/icons/left_arrow/left_arrow_black.svg b/resources/images/icons/left_arrow/left_arrow_black.svg new file mode 100644 index 00000000..c914089c --- /dev/null +++ b/resources/images/icons/left_arrow/left_arrow_black.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/left_arrow/left_arrow_eProsimaLightBlue.svg b/resources/images/icons/left_arrow/left_arrow_eProsimaLightBlue.svg new file mode 100644 index 00000000..624805e0 --- /dev/null +++ b/resources/images/icons/left_arrow/left_arrow_eProsimaLightBlue.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/left_arrow/left_arrow_grey.svg b/resources/images/icons/left_arrow/left_arrow_grey.svg new file mode 100644 index 00000000..f2b5779e --- /dev/null +++ b/resources/images/icons/left_arrow/left_arrow_grey.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/left_arrow/left_arrow_white.svg b/resources/images/icons/left_arrow/left_arrow_white.svg new file mode 100644 index 00000000..6b9c5105 --- /dev/null +++ b/resources/images/icons/left_arrow/left_arrow_white.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/right_arrow/right_arrow_black.svg b/resources/images/icons/right_arrow/right_arrow_black.svg new file mode 100644 index 00000000..00768271 --- /dev/null +++ b/resources/images/icons/right_arrow/right_arrow_black.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/right_arrow/right_arrow_eProsimaLightBlue.svg b/resources/images/icons/right_arrow/right_arrow_eProsimaLightBlue.svg new file mode 100644 index 00000000..ee6300c1 --- /dev/null +++ b/resources/images/icons/right_arrow/right_arrow_eProsimaLightBlue.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/right_arrow/right_arrow_grey.svg b/resources/images/icons/right_arrow/right_arrow_grey.svg new file mode 100644 index 00000000..135d1b59 --- /dev/null +++ b/resources/images/icons/right_arrow/right_arrow_grey.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/right_arrow/right_arrow_white.svg b/resources/images/icons/right_arrow/right_arrow_white.svg new file mode 100644 index 00000000..7bf3f71a --- /dev/null +++ b/resources/images/icons/right_arrow/right_arrow_white.svg @@ -0,0 +1,7 @@ + + + + Layer 1 + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_left_arrow/rounded_left_arrow_black.svg b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_black.svg new file mode 100644 index 00000000..69b4af63 --- /dev/null +++ b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_black.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_left_arrow/rounded_left_arrow_eProsimaLightBlue.svg b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_eProsimaLightBlue.svg new file mode 100644 index 00000000..e77aebf4 --- /dev/null +++ b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_eProsimaLightBlue.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_left_arrow/rounded_left_arrow_grey.svg b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_grey.svg new file mode 100644 index 00000000..8e1c8a0c --- /dev/null +++ b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_grey.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_left_arrow/rounded_left_arrow_white.svg b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_white.svg new file mode 100644 index 00000000..031e91bb --- /dev/null +++ b/resources/images/icons/rounded_left_arrow/rounded_left_arrow_white.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_right_arrow/rounded_right_arrow_black.svg b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_black.svg new file mode 100644 index 00000000..ace9468d --- /dev/null +++ b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_black.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_right_arrow/rounded_right_arrow_eProsimaLightBlue.svg b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_eProsimaLightBlue.svg new file mode 100644 index 00000000..613e3233 --- /dev/null +++ b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_eProsimaLightBlue.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_right_arrow/rounded_right_arrow_grey.svg b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_grey.svg new file mode 100644 index 00000000..3ef61017 --- /dev/null +++ b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_grey.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/icons/rounded_right_arrow/rounded_right_arrow_white.svg b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_white.svg new file mode 100644 index 00000000..33cb74e1 --- /dev/null +++ b/resources/images/icons/rounded_right_arrow/rounded_right_arrow_white.svg @@ -0,0 +1,12 @@ + + triangle-filled + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/resources/images/topic_graph.svg b/resources/images/topic_graph.svg new file mode 100644 index 00000000..a1c47775 --- /dev/null +++ b/resources/images/topic_graph.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Layer 1 \ No newline at end of file diff --git a/src/Engine.cpp b/src/Engine.cpp index 873d9461..42f74da3 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -87,6 +87,10 @@ QObject* Engine::enable() generate_new_status_info_(); fill_status_(); + // Creates a default json structure for problems and fills the tree model with it + problem_model_ = new models::ProblemTreeModel(); + update_problem(backend::ID_ALL, backend::StatusKind::INVALID); + 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()); @@ -109,6 +113,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("entityModelFirst", source_entity_id_model_); rootContext()->setContextProperty("entityModelSecond", destination_entity_id_model_); @@ -118,6 +123,7 @@ QObject* Engine::enable() rootContext()->setContextProperty("controller", controller_); addImportPath(":/imports"); + addImportPath(":/imports/TreeView"); load(QUrl(QLatin1String("qrc:/qml/main.qml"))); // Connect Callback Listener to this object @@ -127,6 +133,12 @@ QObject* Engine::enable() this, &Engine::new_callback_slot); + QObject::connect( + this, + &Engine::new_problem_callback_signal, + this, + &Engine::new_problem_callback_slot); + // Set enable as True enabled_ = true; @@ -186,6 +198,11 @@ Engine::~Engine() delete status_model_; } + if (problem_model_) + { + //delete problem_model_; + } + // Auxiliar models if (source_entity_id_model_) { @@ -833,12 +850,27 @@ void Engine::process_callback_queue() } } +void Engine::process_problem_callback_queue() +{ + // It iterates while run_ is activate and the queue has elements + while (!problem_callback_queue_.empty()) + { + process_problem_callback_(); + } +} + bool Engine::are_callbacks_to_process_() { std::lock_guard ml(callback_queue_mutex_); return callback_queue_.empty(); } +bool Engine::are_problem_callbacks_to_process_() +{ + std::lock_guard ml(problem_callback_queue_mutex_); + return problem_callback_queue_.empty(); +} + bool Engine::add_callback( backend::Callback callback) { @@ -851,11 +883,28 @@ bool Engine::add_callback( return true; } +bool Engine::add_callback( + backend::ProblemCallback problem_callback) +{ + std::lock_guard ml(problem_callback_queue_mutex_); + problem_callback_queue_.append(problem_callback); + + // Emit signal to specify there are new data + emit new_problem_callback_signal(); + + return true; +} + void Engine::new_callback_slot() { process_callback_queue(); } +void Engine::new_problem_callback_slot() +{ + process_problem_callback_queue(); +} + bool Engine::process_callback_() { backend::Callback first_callback; @@ -871,6 +920,21 @@ bool Engine::process_callback_() return read_callback_(first_callback); } +bool Engine::process_problem_callback_() +{ + backend::ProblemCallback first_problem_callback; + + { + std::lock_guard ml(problem_callback_queue_mutex_); + first_problem_callback = problem_callback_queue_.front(); + problem_callback_queue_.pop_front(); + } + + qDebug() << "Processing problem callback: " << backend::backend_id_to_models_id(first_problem_callback.entity_id); + + return read_callback_(first_problem_callback); +} + bool Engine::read_callback_( backend::Callback callback) { @@ -897,6 +961,283 @@ bool Engine::read_callback_( callback.entity_id, callback.entity_kind, callback.is_update); } +bool Engine::read_callback_( + backend::ProblemCallback problem_callback) +{ + // It should not read callbacks while a domain is being initialized + std::lock_guard lock(initializing_monitor_); + + // update model + return update_problem(problem_callback.entity_id, problem_callback.status_kind); +} + +bool Engine::update_problem( + const backend::EntityId& id, + backend::StatusKind kind) +{ + int counter = 0; + auto empty_item = new models::ProblemTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string("")); + if (id == backend::ID_ALL) + { + problem_model_->addTopLevelItem(empty_item); + } + else + { + backend::EntityStatus new_status = backend::EntityStatus::OK; + std::string description = backend::problem_description(kind); + + switch (kind) + { + case backend::StatusKind::DEADLINE_MISSED: + { + backend::DeadlineMissedSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::EntityStatus::OK) + { + auto entity_item = problem_model_->getTopLevelItem( + id, backend_connection_.get_name(id), + sample.status == backend::EntityStatus::ERROR, description); + 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); + auto total_count_item = new models::ProblemTreeItem(id, kind, std::string("Total count:"), + sample.status == backend::EntityStatus::ERROR, + std::to_string(sample.deadline_missed_status.total_count()), description); + for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) + { + handle_string = handle_string + std::to_string(handler); + } + auto last_instance_handle_item = new models::ProblemTreeItem(id, kind, + std::string("Last instance handle:"), + sample.status == backend::EntityStatus::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); + counter = entity_item->recalculate_entity_counter(); + } + break; + } + case backend::StatusKind::INCOMPATIBLE_QOS: + { + backend::IncompatibleQosSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::EntityStatus::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); + 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); + 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, + std::to_string(policy.count()), + std::string("Check for compatible rules ") + + std::string("here")); + problem_model_->addItem(incompatible_qos_item, policy_item); + } + } + problem_model_->addItem(entity_item, incompatible_qos_item); + counter = entity_item->recalculate_entity_counter(); + } + break; + } + case backend::StatusKind::INCONSISTENT_TOPIC: + { + backend::InconsistentTopicSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::EntityStatus::OK) + { + auto entity_item = problem_model_->getTopLevelItem( + id, backend_connection_.get_name(id), + sample.status == backend::EntityStatus::ERROR, description); + new_status = sample.status; + auto inconsistent_topic_item = new models::ProblemTreeItem(id, kind, std::string("Inconsistent topics:"), + sample.status == backend::EntityStatus::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(); + } + break; + } + case backend::StatusKind::LIVELINESS_LOST: + { + backend::LivelinessLostSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::EntityStatus::OK) + { + auto entity_item = problem_model_->getTopLevelItem( + id, backend_connection_.get_name(id), + sample.status == backend::EntityStatus::ERROR, description); + new_status = sample.status; + auto liveliness_lost_item = new models::ProblemTreeItem(id, kind, std::string("Liveliness lost:"), + sample.status == backend::EntityStatus::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(); + } + break; + } + case backend::StatusKind::SAMPLE_LOST: + { + backend::SampleLostSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::EntityStatus::OK) + { + auto entity_item = problem_model_->getTopLevelItem( + id, backend_connection_.get_name(id), + sample.status == backend::EntityStatus::ERROR, description); + new_status = sample.status; + auto samples_lost_item = new models::ProblemTreeItem(id, kind, std::string("Samples lost:"), + sample.status == backend::EntityStatus::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(); + } + break; + } + + case backend::StatusKind::CONNECTION_LIST: + case backend::StatusKind::LIVELINESS_CHANGED: + case backend::StatusKind::PROXY: + //case backend::StatusKind::STATUSES_SIZE: + default: + { + // No problem status updates, as always returns OK + break; + } + } + if (new_status != backend::EntityStatus::OK) + { + std::map::iterator it; + uint32_t total_counter = 0; + bool found = false; + if (new_status == backend::EntityStatus::ERROR) + { + for (it = controller_->status_counters.errors.begin(); it != controller_->status_counters.errors.end(); it++) + { + if (it->first == id) + { + //element found; + found = true; + it->second = counter; + } + total_counter += it->second; + } + if (!found) + { + controller_->status_counters.errors.insert(std::pair(id, counter)); + } + controller_->status_counters.total_errors = total_counter; + } + else if (new_status == backend::EntityStatus::WARNING) + { + for (it = controller_->status_counters.warnings.begin(); it != controller_->status_counters.warnings.end(); it++) + { + if (it->first == id) + { + //element found; + found = true; + it->second = counter; + } + total_counter += it->second; + } + if (!found) + { + controller_->status_counters.warnings.insert(std::pair(id, counter)); + } + controller_->status_counters.total_warnings = total_counter; + } + // notify problem model layout changed to refresh layout view + emit problem_model_->layoutAboutToBeChanged(); + + emit controller_->update_status_counters( + QString::number(controller_->status_counters.total_errors), + QString::number(controller_->status_counters.total_warnings)); + + // remove empty message if exists + if (problem_model_->is_empty()) + { + problem_model_->removeEmptyItem(); + } + // notify problem model layout changed to refresh layout view + emit problem_model_->layoutChanged(); + } + } + return true; +} + +bool Engine::update_problem_entities( + const backend::EntityId& id) +{ + // check if there are entities in the problem model + if (!problem_model_->is_empty()) + { + // get info from id + EntityInfo entity_info = backend_connection_.get_info(id); + + // update problem model if not alive + if (!entity_info["alive"]) + { + // remove item from tree + problem_model_->removeItem(problem_model_->getTopLevelItem(id, "", false, "")); + + // add empty item if removed last item + if (problem_model_->rowCount(problem_model_->rootIndex()) == 0) + { + problem_model_->addTopLevelItem(new models::ProblemTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string(""))); + } + + + uint32_t error_checker = 0 - 100; + // update error counter + std::map::iterator err_it = controller_->status_counters.errors.find(id); + if(err_it != controller_->status_counters.errors.end()) + { + //element found; + controller_->status_counters.total_errors -= err_it->second; + if (controller_->status_counters.total_errors > error_checker) + { + controller_->status_counters.total_errors = 0; + } + } + controller_->status_counters.errors.erase(id); + + // update warning counter + std::map::iterator warn_it = controller_->status_counters.warnings.find(id); + if(warn_it != controller_->status_counters.warnings.end()) + { + //element found; + controller_->status_counters.total_warnings -= warn_it->second; + if (controller_->status_counters.total_warnings > error_checker) + { + controller_->status_counters.total_warnings = 0; + } + } + controller_->status_counters.warnings.erase(id); + + // refresh layout + emit problem_model_->layoutAboutToBeChanged(); + + emit controller_->update_status_counters( + QString::number(controller_->status_counters.total_errors), + QString::number(controller_->status_counters.total_warnings)); + } + return true; + } + return false; +} + bool Engine::update_entity_generic( backend::EntityId entity_id, backend::EntityKind entity_kind, @@ -926,14 +1267,17 @@ bool Engine::update_entity_generic( entity_id, &Engine::update_topic, !is_update, is_last_clicked); case backend::EntityKind::PARTICIPANT: + update_problem_entities(entity_id); return update_entity( entity_id, &Engine::update_participant, !is_update, is_last_clicked); case backend::EntityKind::DATAWRITER: + update_problem_entities(entity_id); return update_entity( entity_id, &Engine::update_datawriter, !is_update, is_last_clicked); case backend::EntityKind::DATAREADER: + update_problem_entities(entity_id); return update_entity( entity_id, &Engine::update_datareader, !is_update, is_last_clicked); diff --git a/src/backend/Listener.cpp b/src/backend/Listener.cpp index a00375ed..e224b3ae 100644 --- a/src/backend/Listener.cpp +++ b/src/backend/Listener.cpp @@ -169,4 +169,14 @@ void Listener::on_topic_discovery( } } +void Listener::on_problem_reported( + EntityId domain_id, + EntityId entity_id, + StatusKind status_kind) +{ + //qDebug() << "PROBLEM REPORTED OF " << backend::backend_id_to_models_id(entity_id) + // << " IN DOMAIN " << backend::backend_id_to_models_id(domain_id); + engine_->add_callback(ProblemCallback(domain_id, entity_id, status_kind)); +} + } //namespace backend diff --git a/src/backend/SyncBackendConnection.cpp b/src/backend/SyncBackendConnection.cpp index 87e2f2eb..4353e5f8 100644 --- a/src/backend/SyncBackendConnection.cpp +++ b/src/backend/SyncBackendConnection.cpp @@ -718,6 +718,63 @@ bool SyncBackendConnection::data_available( return !data.empty(); } +void SyncBackendConnection::get_status_data( + EntityId id, + ConnectionListSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + DeadlineMissedSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + IncompatibleQosSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + InconsistentTopicSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + LivelinessChangedSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + LivelinessLostSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + ProxySample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + +void SyncBackendConnection::get_status_data( + EntityId id, + SampleLostSample& sample) +{ + StatisticsBackend::get_status_data(id, sample); +} + + bool SyncBackendConnection::build_source_target_entities_vectors( DataKind data_kind, EntityId source_entity_id, diff --git a/src/backend/backend_utils.cpp b/src/backend/backend_utils.cpp index 034a66e1..063e02da 100644 --- a/src/backend/backend_utils.cpp +++ b/src/backend/backend_utils.cpp @@ -123,6 +123,35 @@ std::string statistic_kind_to_string( } } +std::string status_kind_to_string( + const StatusKind& status_kind) +{ + switch (status_kind) + { + case StatusKind::CONNECTION_LIST: + return "CONNECTION_LIST"; + case StatusKind::DEADLINE_MISSED: + return "DEADLINE_MISSED"; + case StatusKind::INCOMPATIBLE_QOS: + return "INCOMPATIBLE_QOS"; + case StatusKind::INCONSISTENT_TOPIC: + return "INCONSISTENT_TOPIC"; + case StatusKind::LIVELINESS_CHANGED: + return "LIVELINESS_CHANGED"; + case StatusKind::LIVELINESS_LOST: + return "LIVELINESS_LOST"; + case StatusKind::PROXY: + return "PROXY"; + case StatusKind::SAMPLE_LOST: + return "SAMPLE_LOST"; + case StatusKind::STATUSES_SIZE: + return "STATUSES_SIZE"; + case StatusKind::INVALID: + default: + return "INVALID"; + } +} + std::string data_kind_to_string( const DataKind& data_kind) { @@ -378,4 +407,144 @@ std::string timestamp_to_string( return ss.str(); } +std::string policy_id_to_string( + const uint32_t& id) +{ + switch (id) + { + case 0: // INVALID_QOS_POLICY_ID + default: + return "INVALID"; + case 1: // USERDATA_QOS_POLICY_ID + return "UserData"; + case 2: // DURABILITY_QOS_POLICY_ID + return "Durability"; + case 3: // PRESENTATION_QOS_POLICY_ID + return "Presentation"; + case 4: // DEADLINE_QOS_POLICY_ID + return "Deadline"; + case 5: // LATENCYBUDGET_QOS_POLICY_ID + return "Latency budget"; + case 6: // OWNERSHIP_QOS_POLICY_ID + return "Ownership"; + case 7: // OWNERSHIPSTRENGTH_QOS_POLICY_ID + return "Ownership strength"; + case 8: // LIVELINESS_QOS_POLICY_ID + return "Liveliness"; + case 9: // TIMEBASEDFILTER_QOS_POLICY_ID + return "Time-based filter"; + case 10: // PARTITION_QOS_POLICY_ID + return "Partition"; + case 11: // RELIABILITY_QOS_POLICY_ID + return "Reliability"; + case 12: // DESTINATIONORDER_QOS_POLICY_ID + return "Destination order"; + case 13: // HISTORY_QOS_POLICY_ID + return "History"; + case 14: // RESOURCELIMITS_QOS_POLICY_ID + return "Resource limits"; + case 15: // ENTITYFACTORY_QOS_POLICY_ID + return "Entity factory"; + case 16: // WRITERDATALIFECYCLE_QOS_POLICY_ID + return "Writer data lifecycle"; + case 17: // READERDATALIFECYCLE_QOS_POLICY_ID + return "Reader data lifecycle"; + case 18: // TOPICDATA_QOS_POLICY_ID + return "Topic data"; + case 19: // GROUPDATA_QOS_POLICY_ID + return "Group data"; + case 20: // TRANSPORTPRIORITY_QOS_POLICY_ID + return "Transport priority"; + case 21: // LIFESPAN_QOS_POLICY_ID + return "Lifespan"; + case 22: // DURABILITYSERVICE_QOS_POLICY_ID + return "Durability service"; + case 23: // DATAREPRESENTATION_QOS_POLICY_ID + return "Data representation"; + case 24: // TYPECONSISTENCYENFORCEMENT_QOS_POLICY_ID + return "Type consistency enforcement"; + case 25: // DISABLEPOSITIVEACKS_QOS_POLICY_ID + return "Disable positive acks"; + case 26: // PARTICIPANTRESOURCELIMITS_QOS_POLICY_ID + return "Participant resource limits"; + case 27: // PROPERTYPOLICY_QOS_POLICY_ID + return "Property policy"; + case 28: // PUBLISHMODE_QOS_POLICY_ID + return "Publish mode"; + case 29: // READERRESOURCELIMITS_QOS_POLICY_ID + return "Reader resource limits"; + case 30: // RTPSENDPOINT_QOS_POLICY_ID + return "RTPS endpoint"; + case 31: // RTPSRELIABLEREADER_QOS_POLICY_ID + return "RTPS reliable reader"; + case 32: // RTPSRELIABLEWRITER_QOS_POLICY_ID + return "RTPS reliable writer"; + case 33: // TRANSPORTCONFIG_QOS_POLICY_ID + return "Transport config"; + case 34: // TYPECONSISTENCY_QOS_POLICY_ID + return "Type consistency"; + case 35: // WIREPROTOCOLCONFIG_QOS_POLICY_ID + return "Wire protocol config"; + case 36: // WRITERRESOURCELIMITS_QOS_POLICY_ID + return "Writer resource limits"; + } +} + +std::string problem_description( + const backend::StatusKind kind) +{ + switch (kind) { + case backend::StatusKind::CONNECTION_LIST: + return "List of connections that the entity is using"; + case backend::StatusKind::DEADLINE_MISSED: + return "Number of deadlines missed that were registered in the entity"; + case backend::StatusKind::INCOMPATIBLE_QOS: + return "Tracks the number of incompatible QoS detected in the entity"; + case backend::StatusKind::INCONSISTENT_TOPIC: + return "Status of Inconsistent topics of the topic of the entity"; + case backend::StatusKind::LIVELINESS_CHANGED: + return "Tracks the number of times that liveliness status changed (reader side)"; + case backend::StatusKind::LIVELINESS_LOST: + return "Tracks the number of times that liveliness was lost (writer side)"; + case backend::StatusKind::PROXY: + return "Collection of Parameters describing the Proxy Data of the entity"; + case backend::StatusKind::SAMPLE_LOST: + return "Tracks the number of times that the entity lost samples"; + //case backend::StatusKind::STATUSES_SIZE: + // return ""; + default: + case backend::StatusKind::INVALID: + return ""; + } +} + +std::string policy_documentation_description( + const uint32_t& id) +{ + switch (id) + { + case 2: // DURABILITY_QOS_POLICY_ID + return "#durability-compatibilityrule"; + case 3: // PRESENTATION_QOS_POLICY_ID + return "#presentation-compatibilityrule"; + case 4: // DEADLINE_QOS_POLICY_ID + return "#compatibility-rule"; + case 5: // LATENCYBUDGET_QOS_POLICY_ID + return "#latencybudget-compatibilityrule"; + case 6: // OWNERSHIP_QOS_POLICY_ID + return "#ownership-compatibilityrule"; + case 8: // LIVELINESS_QOS_POLICY_ID + return "#liveliness-compatibilityrule"; + case 11: // RELIABILITY_QOS_POLICY_ID + return "#reliability-compatibilityrule"; + case 12: // DESTINATIONORDER_QOS_POLICY_ID + return "#destinationorder-compatibilityrule"; + case 14: // RESOURCELIMITS_QOS_POLICY_ID + return "#consistency-rule"; + default: + return ""; + } +} + + } // namespace backend diff --git a/src/model/tree/ProblemTreeItem.cpp b/src/model/tree/ProblemTreeItem.cpp new file mode 100644 index 00000000..af09e651 --- /dev/null +++ b/src/model/tree/ProblemTreeItem.cpp @@ -0,0 +1,318 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +#include + +#include +#include +#include +#include + +namespace models { + +ProblemTreeItem::ProblemTreeItem() + : parent_item_(nullptr) + , id_(backend::ID_ALL) + , kind_(backend::StatusKind::INVALID) + , name_() + , is_status_error_(false) + , value_() + , description_() + , is_active_(true) + , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) + , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) + , name_variant_(QVariant()) + , is_status_error_variant_(QVariant(false)) + , value_variant_(QVariant()) + , description_variant_(QVariant()) + , is_active_variant_(QVariant(true)) +{ +} + +ProblemTreeItem::ProblemTreeItem( + const QVariant& data) + : parent_item_(nullptr) + , id_(backend::ID_ALL) + , kind_(backend::StatusKind::INVALID) + , name_(data.toString().toStdString()) + , is_status_error_(false) + , value_() + , description_() + , is_active_(true) + , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) + , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) + , name_variant_(QVariant(QString::fromStdString(name_))) + , is_status_error_variant_(QVariant(false)) + , value_variant_(QVariant()) + , description_variant_(QVariant()) + , is_active_variant_(QVariant(true)) +{ +} + +ProblemTreeItem::ProblemTreeItem( + const backend::EntityId& id, + const std::string& name, + const bool& is_error, + const std::string& description) + : parent_item_(nullptr) + , id_(id) + , kind_(backend::StatusKind::INVALID) + , name_(name) + , is_status_error_(is_error) + , value_() + , description_(description) + , is_active_(true) + , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) + , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) + , name_variant_(QVariant(QString::fromStdString(name))) + , is_status_error_variant_(QVariant(is_error)) + , value_variant_(QVariant()) + , description_variant_(QVariant(QString::fromStdString(description))) + , is_active_variant_(QVariant(true)) +{ +} + +ProblemTreeItem::ProblemTreeItem( + const backend::EntityId& id, + const backend::StatusKind& kind, + const std::string& name, + const bool& is_error, + const std::string& value, + const std::string& description) + : parent_item_(nullptr) + , id_(id) + , kind_(kind) + , name_(name) + , is_status_error_(is_error) + , value_(value) + , description_(description) + , is_active_(true) + , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) + , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) + , name_variant_(QVariant(QString::fromStdString(name_))) + , is_status_error_variant_(QVariant(is_error)) + , value_variant_(QVariant(QString::fromStdString(value))) + , description_variant_(QVariant(QString::fromStdString(description))) + , is_active_variant_(QVariant(true)) +{ +} + +ProblemTreeItem::~ProblemTreeItem() +{ + qDeleteAll(child_items_); +} + +ProblemTreeItem* ProblemTreeItem::parentItem() +{ + return parent_item_; +} + +void ProblemTreeItem::setParentItem( + ProblemTreeItem* parentItem) +{ + parent_item_ = parentItem; +} + +void ProblemTreeItem::appendChild( + ProblemTreeItem* item) +{ + if (item && !child_items_.contains(item)) + { + child_items_.append(item); + } +} + +void ProblemTreeItem::removeChild( + ProblemTreeItem* item) +{ + if (item) + { + child_items_.removeAll(item); + } +} + +ProblemTreeItem* ProblemTreeItem::child( + int row) +{ + return child_items_.value(row); +} + +int ProblemTreeItem::childCount() const +{ + return child_items_.count(); +} + +const QVariant& ProblemTreeItem::data() const +{ + return this->data(models::ProblemTreeModel::ModelItemRoles::nameRole); +} + +const QVariant& ProblemTreeItem::data( + int role) const +{ + switch (role) + { + case models::ProblemTreeModel::ModelItemRoles::idRole: + return this->entity_id(); + case models::ProblemTreeModel::ModelItemRoles::statusRole: + return this->status(); + case models::ProblemTreeModel::ModelItemRoles::kindRole: + return this->status_kind(); + case models::ProblemTreeModel::ModelItemRoles::valueRole: + return this->value(); + case models::ProblemTreeModel::ModelItemRoles::descriptionRole: + return this->description(); + case models::ProblemTreeModel::ModelItemRoles::aliveRole: + return this->alive(); + case models::ProblemTreeModel::ModelItemRoles::nameRole: + default: + return this->name(); + } +} + +const QVariant& ProblemTreeItem::entity_id() const +{ + return id_variant_; +} + +const QVariant& ProblemTreeItem::status_kind() const +{ + return kind_variant_; +} + +const QVariant& ProblemTreeItem::name() const +{ + return name_variant_; +} + +const QVariant& ProblemTreeItem::status() const +{ + return is_status_error_variant_; +} + +const QVariant& ProblemTreeItem::value() const +{ + return value_variant_; +} + +const QVariant& ProblemTreeItem::description() const +{ + return description_variant_; +} + +const QVariant& ProblemTreeItem::alive() const +{ + return is_active_variant_; +} + +void ProblemTreeItem::setData( + const QVariant& data) +{ + name_variant_ = data; +} + +bool ProblemTreeItem::isLeaf() const +{ + return child_items_.isEmpty(); +} + +int ProblemTreeItem::depth() const +{ + int depth = 0; + ProblemTreeItem* anchestor = parent_item_; + while (anchestor) + { + ++depth; + anchestor = anchestor->parentItem(); + } + + return depth; +} + +int ProblemTreeItem::row() const +{ + if (parent_item_) + { + return parent_item_->child_items_.indexOf(const_cast(this)); + } + + return 0; +} + +backend::EntityId ProblemTreeItem::id() +{ + return id_; +} + +backend::StatusKind ProblemTreeItem::kind() +{ + return kind_; +} + + +int ProblemTreeItem::recalculate_entity_counter() +{ + int count = 0; + // check if top level item / entity item + if (id_ != backend::ID_ALL && kind_ == backend::StatusKind::INVALID) + { + for (int i = 0; i < child_items_.count(); i++) + { + try + { + if (child_items_.value(i)->childCount() > 0) + { + for (int j = 0; j < child_items_.value(i)->childCount(); j++) + { + count += child_items_.value(i)->child(j)->value().toInt(); + } + } + count += child_items_.value(i)->value().toInt(); + } + catch (...) {} + } + value_ = std::to_string(count); + value_variant_ = QVariant(QString::fromStdString(value_)); + } + return count; +} + +} // namespace models diff --git a/src/model/tree/ProblemTreeModel.cpp b/src/model/tree/ProblemTreeModel.cpp new file mode 100644 index 00000000..2576775f --- /dev/null +++ b/src/model/tree/ProblemTreeModel.cpp @@ -0,0 +1,375 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Maurizio Ingrassia + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// This file is part of eProsima Fast DDS Monitor. +// +// eProsima Fast DDS Monitor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// eProsima Fast DDS Monitor is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with eProsima Fast DDS Monitor. If not, see . + +#include + +#include +#include + +#include + +namespace models { + +ProblemTreeModel::ProblemTreeModel( + QObject* parent) + : QAbstractItemModel(parent) + , root_item_{ new ProblemTreeItem() } + , is_empty_(false) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +ProblemTreeModel::~ProblemTreeModel() +{ + delete root_item_; +} + +int ProblemTreeModel::rowCount( + const QModelIndex& parent) const +{ + if (!parent.isValid()) + { + return root_item_->childCount(); + } + + return internalPointer(parent)->childCount(); +} + +int ProblemTreeModel::columnCount( + const QModelIndex& /*parent*/) const +{ + // This is basically flatten as a list model + return 1; +} + +QModelIndex ProblemTreeModel::index( + const int row, + const int column, + const QModelIndex& parent) const +{ + if (!hasIndex(row, column, parent)) + { + return {}; + } + + ProblemTreeItem* item = root_item_; + if (parent.isValid()) + { + item = internalPointer(parent); + } + + if (auto child = item->child(row)) + { + return createIndex(row, column, child); + } + + return {}; +} + +QModelIndex ProblemTreeModel::parent( + const QModelIndex& index) const +{ + if (!index.isValid()) + { + return {}; + } + + ProblemTreeItem* childItem = internalPointer(index); + ProblemTreeItem* parentItem = childItem->parentItem(); + + if (!parentItem) + { + return {}; + } + + if (parentItem == root_item_) + { + return {}; + } + + return createIndex(parentItem->row(), 0, parentItem); +} + +QVariant ProblemTreeModel::data( + const QModelIndex& index, + const int role) const +{ + if (!index.isValid()/* || role != Qt::DisplayRole*/) + { + return QVariant(); + } + + return internalPointer(index)->data(role); +} + +bool ProblemTreeModel::setData( + const QModelIndex& index, + const QVariant& value, + int /*role*/) +{ + if (!index.isValid()) + { + return false; + } + + if (auto item = internalPointer(index)) + { + item->setData(value); + emit dataChanged(index, index, {Qt::EditRole}); + } + + return false; +} + +void ProblemTreeModel::addTopLevelItem( + ProblemTreeItem* child) +{ + if (child) + { + addItem(root_item_, child); + if (child->id() == backend::ID_ALL &&root_item_->childCount() == 1) + { + is_empty_ = true; + } + } +} + +void ProblemTreeModel::addItem( + ProblemTreeItem* parent, + ProblemTreeItem* child) +{ + if (!child || !parent) + { + return; + } + + + // if parent is topLevelItem (entity item) + if (parent->id() != backend::ID_ALL && parent->kind() == backend::StatusKind::INVALID) + { + // For each problem in the entity item + for (int i=0; ichildCount(); i++) + { + // if overriding problem, remove previous problem + if (parent->child(i)->id() == child->id() && parent->child(i)->kind() == child->kind()) + { + emit layoutAboutToBeChanged(); + beginRemoveRows(QModelIndex(), qMax(parent->childCount() - 1, 0), qMax(parent->childCount(), 0)); + parent->removeChild(parent->child(i)); + endRemoveRows(); + emit layoutChanged(); + } + } + } + + emit layoutAboutToBeChanged(); + + // remove possible parent from new child + if (child->parentItem()) + { + beginRemoveRows(QModelIndex(), qMax(parent->childCount() - 1, 0), qMax(parent->childCount(), 0)); + child->parentItem()->removeChild(child); + endRemoveRows(); + } + + beginInsertRows(QModelIndex(), qMax(parent->childCount() - 1, 0), qMax(parent->childCount() - 1, 0)); + // set new parent in the child + child->setParentItem(parent); + // append child in parent's child list + parent->appendChild(child); + endInsertRows(); + + emit layoutChanged(); +} + +void ProblemTreeModel::removeItem( + ProblemTreeItem* item) +{ + if (!item) + { + return; + } + + emit layoutAboutToBeChanged(); + + if (item->parentItem()) + { + beginRemoveRows(QModelIndex(), qMax(item->childCount() - 1, 0), qMax(item->childCount(), 0)); + item->parentItem()->removeChild(item); + endRemoveRows(); + } + + emit layoutChanged(); +} + +ProblemTreeItem* ProblemTreeModel::rootItem() const +{ + return root_item_; +} + +QModelIndex ProblemTreeModel::rootIndex() +{ + return {}; +} + +int ProblemTreeModel::depth( + const QModelIndex& index) const +{ + int count = 0; + auto anchestor = index; + if (!index.isValid()) + { + return 0; + } + while (anchestor.parent().isValid()) + { + anchestor = anchestor.parent(); + ++count; + } + + return count; +} + +void ProblemTreeModel::clear() +{ + emit layoutAboutToBeChanged(); + beginResetModel(); + delete root_item_; + root_item_ = new ProblemTreeItem(); + endResetModel(); + emit layoutChanged(); +} + +ProblemTreeItem* ProblemTreeModel::internalPointer( + const QModelIndex& index) const +{ + return static_cast(index.internalPointer()); +} + +bool ProblemTreeModel::containsTopLevelItem( + ProblemTreeItem* child) +{ + if (child) + { + return contains(root_item_, child); + } + return false; +} + +bool ProblemTreeModel::contains( + ProblemTreeItem* parent, + ProblemTreeItem* child) +{ + if (!parent || !child) + { + return false; + } + + for (int i = 0; i < parent->childCount(); i++) + { + if (parent->child(i)->id() == child->id()) + { + return true; + } + } + return false; +} + +bool ProblemTreeModel::is_empty() +{ + return is_empty_; +} + +void ProblemTreeModel::removeEmptyItem() +{ + emit layoutAboutToBeChanged(); + for (int i=0; ichildCount(); i++) + { + if (root_item_->child(i)->id() == backend::ID_ALL) + { + root_item_->removeChild(root_item_->child(i)); + is_empty_ = false; + break; + } + } + emit layoutChanged(); +} + +ProblemTreeItem* ProblemTreeModel::getTopLevelItem( + const backend::EntityId& id, + const std::string& data, + const bool& is_error, + const std::string& description) +{ + // For each entity item in the three (root) + for (int i=0; ichildCount(); i++) + { + // if exists + if (root_item_->child(i)->id() == id) + { + return root_item_->child(i); + } + } + + // if not existing, create new topLevelItem + ProblemTreeItem* new_entity_item = new ProblemTreeItem(id, data, is_error, description); + addTopLevelItem(new_entity_item); + return new_entity_item; +} + + +QHash ProblemTreeModel::roleNames() const +{ + // TODO Jesus this roles are not currently used in the QML, find out why + QHash roles; + + roles[idRole] = "id"; + roles[statusRole] = "status"; + roles[kindRole] = "kind"; + roles[valueRole] = "value"; + roles[descriptionRole] = "description"; + roles[aliveRole] = "alive"; + roles[nameRole] = "name"; + + return roles; +} + +} // namespace models From 423411f99788098263d1aef1655f6c7212c75c98 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 25 Oct 2023 16:00:25 +0200 Subject: [PATCH 02/43] Refs #19533: Improve disable view of chart layout button Signed-off-by: JesusPoderoso --- qml/TabLayout.qml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index baa78f31..a95f64a7 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -105,9 +105,10 @@ Item { id: chart_button width: 400; height: 400 background: Rectangle { - color: Theme.whiteSmoke + color: disable_chart_selection_ ? Theme.lightGrey : Theme.whiteSmoke border.width: 3 - border.color: chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + border.color: disable_chart_selection_ ? Theme.grey : + chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue radius: 40 Image { @@ -127,7 +128,8 @@ Item { text: "Chart View" horizontalAlignment: Text.AlignHCenter font.pointSize: 20 - color: chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue + color: disable_chart_selection_ ? Theme.grey : + chart_button.hovered ? Theme.eProsimaLightBlue : Theme.eProsimaDarkBlue } } anchors.verticalCenter: parent.verticalCenter From df89f1f4a3474519982103809815c4186bae962a Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 30 Oct 2023 08:35:03 +0100 Subject: [PATCH 03/43] Fix mock build issue Signed-off-by: JesusPoderoso --- include/fastdds_monitor/Engine.h | 1 - mock/complex_mock/database/Database.cpp | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index 4cdc0bd1..8ea5e361 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/mock/complex_mock/database/Database.cpp b/mock/complex_mock/database/Database.cpp index d0afb7f6..6ed54462 100644 --- a/mock/complex_mock/database/Database.cpp +++ b/mock/complex_mock/database/Database.cpp @@ -360,8 +360,12 @@ void Database::callback_listener_thread_() default: break; } + + // add status callback + listener_->on_problem_reported(std::get<2>(entity), std::get<0>(entity), StatusKind::PROXY); } } + } std::cout << "DATABASE Callback Listener Thread stopping" << std::endl; From c162098a630f65bcec118f96ff971f66ff7b1cd4 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 30 Oct 2023 15:33:37 +0100 Subject: [PATCH 04/43] Fix visual details Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 120 +++++++++++++++++++++----------------- qml/GraphConnection.qml | 23 ++++---- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 9ff3ff44..93b6b0ba 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -57,14 +57,15 @@ Item // Read only design properties (sizes and colors) readonly property int radius_: 10 - readonly property int connection_thickness_: 5 - readonly property int elements_spacing_: 12 + readonly property int connection_thickness_: 6 + readonly property int elements_spacing_: 5 readonly property int containers_spacing_: 100 - readonly property int endpoint_height_: 40 + readonly property int endpoint_height_: 30 readonly property int first_indentation_: 5 readonly property int icon_size_: 18 - readonly property int label_height_: 35 + readonly property int label_height_: 25 readonly property int spacing_icon_label_: 8 + readonly property int spacing_icon_: 4 readonly property int scrollbar_min_size_: 8 readonly property int scrollbar_max_size_: 12 readonly property int topic_thickness_: 10 @@ -539,18 +540,20 @@ Item Rectangle { color: "transparent" - width: modelData["status"] != "OK" - ? first_indentation_ : 0 - } - IconSVG { - visible: modelData["status"] != "OK" - name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" - size: modelData["status"] != "OK"? icon_size_ : 0 + width: first_indentation_ } Rectangle { - color: "transparent" - width: first_indentation_ /2 + visible: modelData["status"] != "OK" + color: "white" + width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + IconSVG { + anchors.centerIn: parent + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 + } } IconSVG { name: "host" @@ -681,18 +684,20 @@ Item Rectangle { color: "transparent" - width: modelData["status"] != "OK" - ? first_indentation_ : 0 - } - IconSVG { - visible: modelData["status"] != "OK" - name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" - size: modelData["status"] != "OK"? icon_size_ : 0 + width: first_indentation_ } Rectangle { - color: "transparent" - width: first_indentation_ /2 + visible: modelData["status"] != "OK" + color: "white" + width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + IconSVG { + anchors.centerIn: parent + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 + } } IconSVG { name: "user" @@ -822,19 +827,20 @@ Item Rectangle { color: "transparent" - width: modelData["status"] != "OK" - ? first_indentation_ : 0 - } - IconSVG { - visible: modelData["status"] != "OK" - name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" - - size: modelData["status"] != "OK"? icon_size_ : 0 + width: first_indentation_ } Rectangle { - color: "transparent" - width: first_indentation_ /2 + visible: modelData["status"] != "OK" + color: "white" + width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + IconSVG { + anchors.centerIn: parent + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 + } } IconSVG { name: "process" @@ -964,18 +970,20 @@ Item Rectangle { color: "transparent" - width: modelData["status"] != "OK" - ? first_indentation_ : 0 - } - IconSVG { - visible: modelData["status"] != "OK" - name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" - size: modelData["status"] != "OK"? icon_size_ : 0 + width: first_indentation_ } Rectangle { - color: "transparent" - width: first_indentation_ /2 + visible: modelData["status"] != "OK" + color: "white" + width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + IconSVG { + anchors.centerIn: parent + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 + } } IconSVG { name: "participant" @@ -1159,18 +1167,20 @@ Item Rectangle { color: "transparent" - width: modelData["status"] != "OK" - ? first_indentation_ : 0 - } - IconSVG { - visible: modelData["status"] != "OK" - name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" - size: modelData["status"] != "OK"? icon_size_ : 0 + width: first_indentation_ } Rectangle { - color: "transparent" - width: first_indentation_ /2 + visible: modelData["status"] != "OK" + color: "white" + width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 + IconSVG { + anchors.centerIn: parent + name: modelData["status"] == "WARNING" ? "issues" : "error" + color: modelData["status"] == "WARNING" ? "white" : "red" + size: modelData["status"] != "OK"? icon_size_ : 0 + } } IconSVG { name: modelData["kind"] == "DataReader" diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index e6a2c211..b670b1af 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -9,8 +9,8 @@ Item { property string background_color: "white" // background color // readonly private design properties - readonly property int arrow_margin_: -4 // margins for background - readonly property int arrow_size_: 30 // arrow size + readonly property int arrow_margin_: -3 // margins for background + readonly property int arrow_size_: 18 // arrow size // background to make connection overlap nicely with previous topics (looks like connection goes OVER the topic) Rectangle { @@ -19,7 +19,7 @@ Item { anchors.top: parent.top; anchors.bottom: parent.bottom anchors.topMargin: arrow_margin_; anchors.bottomMargin: arrow_margin_ anchors.left: parent.left; anchors.right: parent.right - anchors.leftMargin: left_margin; anchors.rightMargin: left_margin; + anchors.leftMargin: left_margin; anchors.rightMargin: left_margin color: "white" } @@ -28,7 +28,8 @@ Item { anchors.top: parent.top; anchors.bottom: parent.bottom anchors.topMargin: arrow_margin_; anchors.bottomMargin: arrow_margin_ anchors.left: parent.left; anchors.right: parent.right - anchors.leftMargin: parent.height /2; anchors.rightMargin: 5; + anchors.leftMargin: parent.height /2 + anchors.rightMargin: left_direction ? left_margin: left_margin != 0 ? parent.height : parent.height/2 color: "white" } @@ -38,7 +39,7 @@ Item { Item { id: left_arrow_background visible: left_direction - height: arrow_size_ + 20 + height: arrow_size_ + 15 width: arrow_size_ clip: true anchors.verticalCenter: parent.verticalCenter @@ -49,7 +50,7 @@ Item { anchors.top: parent.top name: "left_arrow" color: "white" - size: arrow_size_ + 10 + size: arrow_size_ + 8 } IconSVG { @@ -57,7 +58,7 @@ Item { anchors.bottom: parent.bottom name: "left_arrow" color: "white" - size: arrow_size_ + 10 + size: arrow_size_ + 8 } } @@ -91,15 +92,15 @@ Item { Item { id: right_arrow visible: right_direction - height: arrow_size_ -4 - width: arrow_size_ -4 + height: arrow_size_ -2 + width: arrow_size_ -2 anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right; anchors.rightMargin: parent.height /2 + 2 + anchors.right: parent.right; anchors.rightMargin: parent.height /2 IconSVG { name: "right_arrow" color: "grey" - size: arrow_size_-5 + size: arrow_size_-2 } } } From 56d54df263884210af183c2c6a9ebeea5e978106 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 31 Oct 2023 07:52:33 +0100 Subject: [PATCH 05/43] Display entity information when clicked in status layout Signed-off-by: JesusPoderoso --- qml/ProblemTreeViewItem.qml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/qml/ProblemTreeViewItem.qml b/qml/ProblemTreeViewItem.qml index beea7514..057266da 100644 --- a/qml/ProblemTreeViewItem.qml +++ b/qml/ProblemTreeViewItem.qml @@ -226,8 +226,15 @@ Item { { _prop.expanded = !_prop.expanded } + + _prop.focus() root.toggled() } + + function focus(){ + controller.endpoint_click(_prop.currentId) + controller.participant_click(_prop.currentId) + } } Connections { @@ -311,6 +318,7 @@ Item { TapHandler { onDoubleTapped: _prop.toggle() onSingleTapped: { + _prop.focus() root.currentItem = _prop.currentItem root.selectedIndex = _prop.currentIndex } From 022ed1ec63bed8c86ffd79bfec9bb508347dd21b Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 2 Nov 2023 08:19:43 +0100 Subject: [PATCH 06/43] Refs #19533: Fix warning visual issue Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 93b6b0ba..cb9bfc9c 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -544,14 +544,14 @@ Item } Rectangle { visible: modelData["status"] != "OK" - color: "white" + color: modelData["status"] == "WARNING" ? "transparent" : "white" width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" + color: modelData["status"] == "WARNING" ? "black" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -688,14 +688,14 @@ Item } Rectangle { visible: modelData["status"] != "OK" - color: "white" + color: modelData["status"] == "WARNING" ? "transparent" : "white" width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" + color: modelData["status"] == "WARNING" ? "black" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -831,14 +831,14 @@ Item } Rectangle { visible: modelData["status"] != "OK" - color: "white" + color: modelData["status"] == "WARNING" ? "transparent" : "white" width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" + color: modelData["status"] == "WARNING" ? "black" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -974,14 +974,14 @@ Item } Rectangle { visible: modelData["status"] != "OK" - color: "white" + color: modelData["status"] == "WARNING" ? "transparent" : "white" width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" + color: modelData["status"] == "WARNING" ? "black" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -1171,14 +1171,14 @@ Item } Rectangle { visible: modelData["status"] != "OK" - color: "white" + color: modelData["status"] == "WARNING" ? "transparent" : "white" width: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 height: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 radius: modelData["status"] != "OK"? icon_size_ + spacing_icon_: 0 IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "white" : "red" + color: modelData["status"] == "WARNING" ? "black" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } From 00f073a90ffd997900f2c423349dcefc9ed5829d Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 2 Nov 2023 10:51:12 +0100 Subject: [PATCH 07/43] 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 cb9bfc9c..faf88a93 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -1428,7 +1428,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_; From 7a5fc14c64cc9f1582b1f984af14f5c91f0cae8e Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 3 Nov 2023 10:31:41 +0100 Subject: [PATCH 08/43] Refs #19743: Fix topic filtering visual bugs Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 101 +++++++++++++++++++++++++------------- qml/TabLayout.qml | 29 ++++++----- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index faf88a93..fa17e966 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -32,7 +32,7 @@ Item required property string component_id // mandatory to be included when object created // Public signals - signal update_tab_name(string new_name) // Update tab name based on selected domain id + signal update_tab_name(string new_name, string stack_id) // Update tab name based on selected domain id signal openEntitiesMenu(string domainEntityId, string entityId, string currentAlias, string entityKind) signal openTopicMenu(string domainEntityId, string domainId, string entityId, string currentAlias, string entityKind) @@ -1376,7 +1376,7 @@ Item } } var accum_y = 0 - var temp_y = 0 + var host_temp_y = 0 for (var host in new_model["hosts"]) { var discard_host = true @@ -1385,22 +1385,28 @@ Item { accum_y += label_height_ + elements_spacing_ var new_users = [] + var user_temp_y = accum_y for (var user in new_model["hosts"][host]["users"]) { + var discard_user = true var metatraffic_ = new_model["hosts"][host]["users"][user]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { accum_y += label_height_ + elements_spacing_ var new_processes = [] + var process_temp_y = accum_y for (var process in new_model["hosts"][host]["users"][user]["processes"]) { + var discard_process = true var metatraffic_ = new_model["hosts"][host]["users"][user]["processes"][process]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { accum_y += label_height_ + elements_spacing_ var new_participants = [] + var participant_temp_y = accum_y for (var participant in new_model["hosts"][host]["users"][user]["processes"][process]["participants"]) { + var discard_participant = true var metatraffic_ = new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["metatraffic"] if (metatraffic_ != true || is_metatraffic_visible_) { @@ -1414,7 +1420,7 @@ Item if ((!filtered_topics_.length) || (filtered_topics_.length > 0 && filtered_topics_.includes(new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["topic"]))) { - discard_host = false + discard_participant = false; discard_process = false; discard_user = false; discard_host = false var kind = "DataWriter" if (new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["kind"] == "datareader") { @@ -1428,42 +1434,66 @@ 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_ + pending_endpoints_[pending_endpoints_.length] = endpoint } - accum_y += endpoint_height_ + elements_spacing_ - pending_endpoints_[pending_endpoints_.length] = endpoint } } - new_participants[new_participants.length] = { - "id":participant, - "kind": "DomainParticipant", - "alias":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["alias"], - "status":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["status"], - "app_id":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["app_id"], - "app_metadata":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["app_metadata"], - "endpoints":new_endpoints + if (!discard_participant) + { + new_participants[new_participants.length] = { + "id":participant, + "kind": "DomainParticipant", + "alias":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["alias"], + "status":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["status"], + "app_id":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["app_id"], + "app_metadata":new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["app_metadata"], + "endpoints":new_endpoints + } + accum_y += elements_spacing_ + participant_temp_y = accum_y + } + else + { + accum_y = participant_temp_y } - accum_y += elements_spacing_ } } - new_processes[new_processes.length] = { - "id":process, - "kind":"Process", - "alias":new_model["hosts"][host]["users"][user]["processes"][process]["alias"], - "pid": new_model["hosts"][host]["users"][user]["processes"][process]["pid"], - "status":new_model["hosts"][host]["users"][user]["processes"][process]["status"], - "participants":new_participants + if (!discard_process) + { + new_processes[new_processes.length] = { + "id":process, + "kind":"Process", + "alias":new_model["hosts"][host]["users"][user]["processes"][process]["alias"], + "pid": new_model["hosts"][host]["users"][user]["processes"][process]["pid"], + "status":new_model["hosts"][host]["users"][user]["processes"][process]["status"], + "participants":new_participants + } + accum_y += elements_spacing_ + process_temp_y = accum_y + } + else + { + accum_y = process_temp_y } - accum_y += elements_spacing_ } } - new_users[new_users.length] = { - "id":user, - "kind": "User", - "alias":new_model["hosts"][host]["users"][user]["alias"], - "status":new_model["hosts"][host]["users"][user]["status"], - "processes":new_processes + if (!discard_user) + { + new_users[new_users.length] = { + "id":user, + "kind": "User", + "alias":new_model["hosts"][host]["users"][user]["alias"], + "status":new_model["hosts"][host]["users"][user]["status"], + "processes":new_processes + } + accum_y += elements_spacing_ + user_temp_y = accum_y + } + else + { + accum_y = user_temp_y } - accum_y += elements_spacing_ } } if (!discard_host) @@ -1476,10 +1506,11 @@ Item "users":new_users } accum_y += elements_spacing_ - temp_y = accum_y + host_temp_y = accum_y } - else { - accum_y = temp_y + else + { + accum_y = host_temp_y } } @@ -1521,7 +1552,7 @@ Item { if (filtered_topics_.length == 1) { - domainGraphLayout.update_tab_name(topic_names[0] + " Topic View") + domainGraphLayout.update_tab_name(topic_names[0] + " Topic View", component_id) } else { @@ -1535,12 +1566,12 @@ Item print_topic_names += " and " + topic_names[topic_names.length-1] } - domainGraphLayout.update_tab_name(print_topic_names + " Topics View") + domainGraphLayout.update_tab_name(print_topic_names + " Topics View", component_id) } } else { - domainGraphLayout.update_tab_name("Domain " + domain_id + " View") + domainGraphLayout.update_tab_name("Domain " + domain_id + " View", component_id) } } diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index a95f64a7..942715bf 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -210,19 +210,26 @@ Item { component_id: stack.stack_id onUpdate_tab_name: { - tabLayout.tab_model_[current_]["title"] = new_name - - // update model to set the visual change - tab_list.model = tabLayout.tab_model_ - - // update left panel information - for (var i=0; i 0) + if (tabLayout.tab_model_[i]["stack_id"] == stack_id) { - controller.domain_click(stack_layout.children[i].currentItem.entity_id) - break; + tabLayout.tab_model_[i]["title"] = new_name + + // update model to set the visual change + tab_list.model = tabLayout.tab_model_ + + // update left panel information + for (var j=0; j 0) + { + controller.domain_click(stack_layout.children[j].currentItem.entity_id) + break; + } + } + break // exit loop } } } From 18e4069aa3918fc9b0d276827b8c8426c949d1c3 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 7 Nov 2023 10:32:53 +0100 Subject: [PATCH 09/43] Refs #19743: Add load model check for empty filter Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index fa17e966..748ce3f8 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -1310,7 +1310,14 @@ Item // Obtain given domain id graph JSON model function load_model() { - filter_model_by_topic ("") + if (filtered_topics_.length > 0) + { + filter_model_by_topic (filtered_topics_[filtered_topics_.length-1]) + } + else + { + filter_model_by_topic ("") + } } // Filter model by topic From 15e9ae9236ee03b509ea1adf81f443dc34bc78cb Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 12:30:18 +0100 Subject: [PATCH 10/43] Refs #19743: [ARS] Set Backend status references Signed-off-by: JesusPoderoso --- include/fastdds_monitor/backend/backend_types.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/fastdds_monitor/backend/backend_types.h b/include/fastdds_monitor/backend/backend_types.h index 6e2b5db8..474b2fc7 100644 --- a/include/fastdds_monitor/backend/backend_types.h +++ b/include/fastdds_monitor/backend/backend_types.h @@ -26,6 +26,7 @@ #include #include +#include namespace backend { @@ -55,9 +56,9 @@ extern const EntityId ID_ALL; extern const EntityId ID_NONE; //! Reference for problem status (ok, error or warning) -static constexpr const char* PROBLEM_STATUS_ERROR = "error"; -static constexpr const char* PROBLEM_STATUS_OK = "ok"; -static constexpr const char* PROBLEM_STATUS_WARNING = "warning"; +static const char* PROBLEM_STATUS_ERROR = eprosima::statistics_backend::ERROR_STATUS; +static const char* PROBLEM_STATUS_OK = eprosima::statistics_backend::OK_STATUS; +static const char* PROBLEM_STATUS_WARNING = eprosima::statistics_backend::WARNING_STATUS; } //namespace backend From a50a7d57e40083c21c496bf46aa3e2f92e3013e5 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 12:35:30 +0100 Subject: [PATCH 11/43] Refs #19743: [ARS] Delete debug comment Signed-off-by: JesusPoderoso --- src/backend/Listener.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/backend/Listener.cpp b/src/backend/Listener.cpp index ee5ab2ad..64f309b9 100644 --- a/src/backend/Listener.cpp +++ b/src/backend/Listener.cpp @@ -174,8 +174,6 @@ void Listener::on_status_reported( EntityId entity_id, StatusKind status_kind) { - //qDebug() << "PROBLEM REPORTED OF " << backend::backend_id_to_models_id(entity_id) - // << " IN DOMAIN " << backend::backend_id_to_models_id(domain_id); engine_->add_callback(ProblemCallback(domain_id, entity_id, status_kind)); } From 6b2f4e42ff7cb4ad519c71b4fad331fd3f4a8997 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 13:31:03 +0100 Subject: [PATCH 12/43] Refs #19743: [ARS] Rename all problems to statuses Signed-off-by: JesusPoderoso --- CMakeLists.txt | 8 +- fastdds_monitor.pro | 8 +- include/fastdds_monitor/Engine.h | 52 +++--- include/fastdds_monitor/backend/Listener.h | 2 +- .../{ProblemCallback.h => StatusCallback.h} | 18 +- .../fastdds_monitor/backend/backend_types.h | 7 +- .../fastdds_monitor/backend/backend_utils.h | 2 +- .../{ProblemTreeItem.h => StatusTreeItem.h} | 42 ++--- .../{ProblemTreeModel.h => StatusTreeModel.h} | 48 +++--- qml.qrc | 4 +- qml/EntitiesMenu.qml | 2 +- qml/LeftPanel.qml | 6 +- qml/Panels.qml | 2 +- qml/StatusLayout.qml | 8 +- ...ProblemTreeView.qml => StatusTreeView.qml} | 20 +-- ...reeViewItem.qml => StatusTreeViewItem.qml} | 16 +- qml/TopicMenu.qml | 2 +- src/Engine.cpp | 160 +++++++++--------- src/backend/Listener.cpp | 2 +- src/backend/backend_utils.cpp | 2 +- ...ProblemTreeItem.cpp => StatusTreeItem.cpp} | 94 +++++----- ...oblemTreeModel.cpp => StatusTreeModel.cpp} | 96 +++++------ 22 files changed, 298 insertions(+), 303 deletions(-) rename include/fastdds_monitor/backend/{ProblemCallback.h => StatusCallback.h} (81%) rename include/fastdds_monitor/model/tree/{ProblemTreeItem.h => StatusTreeItem.h} (82%) rename include/fastdds_monitor/model/tree/{ProblemTreeModel.h => StatusTreeModel.h} (84%) rename qml/{ProblemTreeView.qml => StatusTreeView.qml} (90%) rename qml/{ProblemTreeViewItem.qml => StatusTreeViewItem.qml} (97%) rename src/model/tree/{ProblemTreeItem.cpp => StatusTreeItem.cpp} (76%) rename src/model/tree/{ProblemTreeModel.cpp => StatusTreeModel.cpp} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 910d7578..8fb0735d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,8 +233,8 @@ set(PROJECT_HEADERS ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/statistics/EntityItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/SubListedListItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/SubListedListModel.h - ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/ProblemTreeItem.h - ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/ProblemTreeModel.h + ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/StatusTreeItem.h + ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/StatusTreeModel.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/TreeItem.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/model/tree/TreeModel.h ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}/statistics/DataChartBox.h @@ -263,8 +263,8 @@ set(PROJECT_SOURCES_NO_MAIN ${PROJECT_SOURCE_DIR}/src/model/physical/ProcessModelItem.cpp ${PROJECT_SOURCE_DIR}/src/model/statistics/EntityItem.cpp ${PROJECT_SOURCE_DIR}/src/model/SubListedListModel.cpp - ${PROJECT_SOURCE_DIR}/src/model/tree/ProblemTreeItem.cpp - ${PROJECT_SOURCE_DIR}/src/model/tree/ProblemTreeModel.cpp + ${PROJECT_SOURCE_DIR}/src/model/tree/StatusTreeItem.cpp + ${PROJECT_SOURCE_DIR}/src/model/tree/StatusTreeModel.cpp ${PROJECT_SOURCE_DIR}/src/model/tree/TreeItem.cpp ${PROJECT_SOURCE_DIR}/src/model/tree/TreeModel.cpp ${PROJECT_SOURCE_DIR}/src/statistics/DataChartBox.cpp diff --git a/fastdds_monitor.pro b/fastdds_monitor.pro index d3771b80..869a54d4 100644 --- a/fastdds_monitor.pro +++ b/fastdds_monitor.pro @@ -24,8 +24,8 @@ SOURCES += \ src/model/physical/ProcessModelItem.cpp \ src/model/statistics/EntityItem.cpp \ src/model/SubListedListModel.cpp \ - src/model/tree/ProblemTreeItem.cpp \ - src/model/tree/ProblemTreeModel.cpp \ + src/model/tree/StatusTreeItem.cpp \ + src/model/tree/StatusTreeModel.cpp \ src/model/tree/TreeItem.cpp \ src/model/tree/TreeModel.cpp \ src/statistics/DataChartBox.cpp \ @@ -77,8 +77,8 @@ HEADERS += \ include/fastdds_monitor/model/statistics/EntityItem.h \ include/fastdds_monitor/model/SubListedListItem.h \ include/fastdds_monitor/model/SubListedListModel.h \ - include/fastdds_monitor/model/tree/ProblemTreeModel.h \ - include/fastdds_monitor/model/tree/ProblemTreeItem.h \ + include/fastdds_monitor/model/tree/StatusTreeModel.h \ + include/fastdds_monitor/model/tree/StatusTreeItem.h \ include/fastdds_monitor/model/tree/TreeItem.h \ include/fastdds_monitor/model/tree/TreeModel.h \ include/fastdds_monitor/statistics/DataChartBox.h \ diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index d688a43c..91674f05 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include @@ -40,7 +40,7 @@ #include #include #include -#include +#include struct EntityClicked { @@ -268,11 +268,11 @@ class Engine : public QQmlApplicationEngine bool new_entity = true, bool last_clicked = false); - bool update_problem( + bool update_entity_status( const backend::EntityId& id, backend::StatusKind kind); - bool update_problem_entities( + bool update_entity_status_entities( const backend::EntityId& id); /** @@ -367,7 +367,7 @@ class Engine : public QQmlApplicationEngine * @return true */ bool add_callback( - backend::ProblemCallback callback); + backend::StatusCallback callback); /** * @brief Refresh the view @@ -412,12 +412,12 @@ class Engine : public QQmlApplicationEngine void process_callback_queue(); /** - * @brief Pop problem callbacks from the callback queues while non empty and update the models + * @brief Pop status callbacks from the callback queues while non empty and update the models * * @warning This method must be executed from the main Thread (or at least a QThread) so the models are * updated in the view when modified. */ - void process_problem_callback_queue(); + void process_status_callback_queue(); //! Refresh summary panel void refresh_summary(); @@ -540,7 +540,7 @@ class Engine : public QQmlApplicationEngine * Internal signal that communicate that there are callbacks to process by the main Thread. * Arise from \c add_callback */ - void new_problem_callback_signal(); + void new_status_callback_signal(); public slots: @@ -551,10 +551,10 @@ public slots: void new_callback_slot(); /** - * Receive the internal signal \c new_problem_callback_signal and start the process of problem - * callback queue by \c process_problem_callback_queue + * Receive the internal signal \c new_status_callback_signal and start the process of status + * callback queue by \c process_status_callback_queue */ - void new_problem_callback_slot(); + void new_status_callback_slot(); protected: @@ -674,22 +674,22 @@ public slots: //! True if there are callbacks in the callback queue bool are_callbacks_to_process_(); - //! True if there are problem callbacks in the callback queue - bool are_problem_callbacks_to_process_(); + //! True if there are status callbacks in the callback queue + bool are_status_callbacks_to_process_(); //! Pop a callback from callback queues and call \c read_callback for that callback bool process_callback_(); - //! Pop a problem callback from callback queues and call \c read_callback for that problem callback - bool process_problem_callback_(); + //! Pop a status callback from callback queues and call \c read_callback for that status callback + bool process_status_callback_(); //! Update the model concerned by the entity in the callback bool read_callback_( backend::Callback callback); - //! Update the model concerned by the entity in the problem callback + //! Update the model concerned by the entity in the status callback bool read_callback_( - backend::ProblemCallback callback); + backend::StatusCallback callback); //! Common method to demultiplex to update functions depending on the entity kind bool update_entity_generic( @@ -746,11 +746,11 @@ public slots: //! Data that is represented in the Status Model when this model is refreshed backend::Info status_info_; - //! Data Model for Fast DDS Monitor problem view. Collects all entities problems detected by the monitor service - models::ProblemTreeModel* problem_model_; + //! Data Model for Fast DDS Monitor status view. Collects all entities statuses detected by the monitor service + models::StatusTreeModel* entity_status_model_; - //! Display and allow to filter Model for Fast DDS Monitor problem view. - models::ProblemTreeModel* problem_proxy_model_; + //! Display and allow to filter Model for Fast DDS Monitor status view. + models::StatusTreeModel* entity_status_proxy_model_; //! TODO models::ListModel* source_entity_id_model_; @@ -779,14 +779,14 @@ public slots: //! Mutex to protect \c callback_queue_ std::recursive_mutex callback_queue_mutex_; - //! Mutex to protect \c problem_callback_queue_ - std::recursive_mutex problem_callback_queue_mutex_; + //! Mutex to protect \c status_callback_queue_ + std::recursive_mutex status_callback_queue_mutex_; //! Queue of Callbacks that have arrived by the \c Listener and have not been processed QQueue callback_queue_; - //! Queue of Problem Callbacks that have arrived by the \c Listener and have not been processed - QQueue problem_callback_queue_; + //! Queue of status Callbacks that have arrived by the \c Listener and have not been processed + QQueue status_callback_queue_; //! Object that manage all the communications with the QML view Controller* controller_; @@ -811,7 +811,7 @@ public slots: std::recursive_mutex initializing_monitor_; //! All status log - backend::Info problem_status_log_; + backend::Info status_status_log_; }; #endif // _EPROSIMA_FASTDDS_MONITOR_ENGINE_H diff --git a/include/fastdds_monitor/backend/Listener.h b/include/fastdds_monitor/backend/Listener.h index bc743928..be61fdd5 100644 --- a/include/fastdds_monitor/backend/Listener.h +++ b/include/fastdds_monitor/backend/Listener.h @@ -91,7 +91,7 @@ class Listener : public PhysicalListener EntityId datawriter_id, const Status& status) override; - //! Callback when a status problem is reported + //! Callback when a status is reported void on_status_reported( EntityId domain_id, EntityId entity_id, diff --git a/include/fastdds_monitor/backend/ProblemCallback.h b/include/fastdds_monitor/backend/StatusCallback.h similarity index 81% rename from include/fastdds_monitor/backend/ProblemCallback.h rename to include/fastdds_monitor/backend/StatusCallback.h index d4ca47d6..cffdc273 100644 --- a/include/fastdds_monitor/backend/ProblemCallback.h +++ b/include/fastdds_monitor/backend/StatusCallback.h @@ -16,29 +16,29 @@ // along with eProsima Fast DDS Monitor. If not, see . /** - * @file ProblemCallback.h + * @file StatusCallback.h */ -#ifndef _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H -#define _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H +#ifndef _EPROSIMA_FASTDDS_MONITOR_BACKEND_STATUS_CALLBACK_H +#define _EPROSIMA_FASTDDS_MONITOR_BACKEND_STATUS_CALLBACK_H #include namespace backend { /* - * Struct that store the problem callback information required by the GUI. - * It encapsulates the domain id, entity id and the kind of the new problem reported. + * Struct that store the status callback information required by the GUI. + * It encapsulates the domain id, entity id and the kind of the new status reported. */ -struct ProblemCallback +struct StatusCallback { //! Void constructor to use copy constructor afterwards - ProblemCallback() + StatusCallback() { } //! Standard constructor with the two fields required - ProblemCallback( + StatusCallback( backend::EntityId domain_entity_id, backend::EntityId entity_id, backend::StatusKind status_kind) @@ -57,4 +57,4 @@ struct ProblemCallback } // namespace backend -#endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_PROBLEM_CALLBACK_H +#endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_STATUS_CALLBACK_H diff --git a/include/fastdds_monitor/backend/backend_types.h b/include/fastdds_monitor/backend/backend_types.h index 474b2fc7..b21f5b0b 100644 --- a/include/fastdds_monitor/backend/backend_types.h +++ b/include/fastdds_monitor/backend/backend_types.h @@ -39,7 +39,7 @@ using StatisticKind = eprosima::statistics_backend::StatisticKind; using EntityInfo = eprosima::statistics_backend::Info; using Timestamp = eprosima::statistics_backend::Timestamp; -// Problem status types from backend +// Status types from backend using ConnectionListSample = eprosima::statistics_backend::ConnectionListSample; using DeadlineMissedSample = eprosima::statistics_backend::DeadlineMissedSample; using IncompatibleQosSample = eprosima::statistics_backend::IncompatibleQosSample; @@ -55,11 +55,6 @@ extern const EntityId ID_ALL; //! Reference the ID_NONE in the project extern const EntityId ID_NONE; -//! Reference for problem status (ok, error or warning) -static const char* PROBLEM_STATUS_ERROR = eprosima::statistics_backend::ERROR_STATUS; -static const char* PROBLEM_STATUS_OK = eprosima::statistics_backend::OK_STATUS; -static const char* PROBLEM_STATUS_WARNING = eprosima::statistics_backend::WARNING_STATUS; - } //namespace backend #endif // _EPROSIMA_FASTDDS_MONITOR_BACKEND_BACKENDTYPES_H diff --git a/include/fastdds_monitor/backend/backend_utils.h b/include/fastdds_monitor/backend/backend_utils.h index 25af9e1c..e6dc56da 100644 --- a/include/fastdds_monitor/backend/backend_utils.h +++ b/include/fastdds_monitor/backend/backend_utils.h @@ -114,7 +114,7 @@ std::string timestamp_to_string( std::string policy_id_to_string( const uint32_t& id); -std::string problem_description( +std::string entity_status_description( const backend::StatusKind kind); std::string policy_documentation_description( diff --git a/include/fastdds_monitor/model/tree/ProblemTreeItem.h b/include/fastdds_monitor/model/tree/StatusTreeItem.h similarity index 82% rename from include/fastdds_monitor/model/tree/ProblemTreeItem.h rename to include/fastdds_monitor/model/tree/StatusTreeItem.h index 1b3eaae2..42fe0799 100644 --- a/include/fastdds_monitor/model/tree/ProblemTreeItem.h +++ b/include/fastdds_monitor/model/tree/StatusTreeItem.h @@ -39,8 +39,8 @@ // You should have received a copy of the GNU General Public License // along with eProsima Fast DDS Monitor. If not, see . -#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H -#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H +#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeItem_H +#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeItem_H #include #include @@ -48,34 +48,34 @@ namespace models { /*! - * This class represents a node of the ProblemTreeModel. - * The items are meant to be managed from the ProblemTreeModel, thus is only allowed + * This class represents a node of the StatusTreeModel. + * The items are meant to be managed from the StatusTreeModel, thus is only allowed * to modify the stored data. - * Parenting and deletion are dealt from the ProblemTreeModel. Deleting a ProblemTreeItem + * Parenting and deletion are dealt from the StatusTreeModel. Deleting a StatusTreeItem * will call the delete for each child node. */ -class ProblemTreeItem +class StatusTreeItem { - friend class ProblemTreeModel; + friend class StatusTreeModel; public: //! Create an empty item. - ProblemTreeItem(); + StatusTreeItem(); //! Create an item with the given data. - explicit ProblemTreeItem( + explicit StatusTreeItem( const QVariant& data); //! Create an Entity item / top level item - explicit ProblemTreeItem( + explicit StatusTreeItem( const backend::EntityId& id, const std::string& name, const bool& is_error, const std::string& description); - //! Create an item with the problem parameters - explicit ProblemTreeItem( + //! Create an item with the status parameters + explicit StatusTreeItem( const backend::EntityId& id, const backend::StatusKind& kind, const std::string& name, @@ -84,7 +84,7 @@ class ProblemTreeItem const std::string& description); //! Destroy the item. It will destroy every child. - ~ProblemTreeItem(); + ~StatusTreeItem(); //! Return the stored data of the node. const QVariant& data() const; @@ -122,7 +122,7 @@ class ProblemTreeItem //! Return the depth of this node inside the tree. int depth() const; - ProblemTreeItem* child( + StatusTreeItem* child( int row); backend::EntityId id(); @@ -144,20 +144,20 @@ class ProblemTreeItem int recalculate_entity_counter(); private: - ProblemTreeItem* parentItem(); + StatusTreeItem* parentItem(); void setParentItem( - ProblemTreeItem* parentItem); + StatusTreeItem* parentItem); void appendChild( - ProblemTreeItem* item); + StatusTreeItem* item); void removeChild( - ProblemTreeItem* item); + StatusTreeItem* item); private: - ProblemTreeItem* parent_item_; - QVector child_items_; + StatusTreeItem* parent_item_; + QVector child_items_; backend::EntityId id_; backend::StatusKind kind_; std::string name_; @@ -176,4 +176,4 @@ class ProblemTreeItem } // namespace models -#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEITEM_H +#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeItem_H diff --git a/include/fastdds_monitor/model/tree/ProblemTreeModel.h b/include/fastdds_monitor/model/tree/StatusTreeModel.h similarity index 84% rename from include/fastdds_monitor/model/tree/ProblemTreeModel.h rename to include/fastdds_monitor/model/tree/StatusTreeModel.h index cd149063..1611209b 100644 --- a/include/fastdds_monitor/model/tree/ProblemTreeModel.h +++ b/include/fastdds_monitor/model/tree/StatusTreeModel.h @@ -39,10 +39,10 @@ // You should have received a copy of the GNU General Public License // along with eProsima Fast DDS Monitor. If not, see . -#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H -#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H +#ifndef _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeModel_H +#define _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeModel_H -#include +#include #include @@ -52,16 +52,16 @@ namespace models { * The Tree Model works as List Model, using one column and using the row information * referred to the parent node. */ -class ProblemTreeModel : public QAbstractItemModel +class StatusTreeModel : public QAbstractItemModel { Q_OBJECT - //Q_ENUMS(models::ProblemTreeItem::ModelItemRoles) + //Q_ENUMS(models::StatusTreeItem::ModelItemRoles) public: - explicit ProblemTreeModel( + explicit StatusTreeModel( QObject* parent = nullptr); - ~ProblemTreeModel() override; + ~StatusTreeModel() override; // Overriden method from QAbstractItemModel @@ -112,19 +112,19 @@ class ProblemTreeModel : public QAbstractItemModel public: //! Add an item to the top level. void addTopLevelItem( - ProblemTreeItem* child); + StatusTreeItem* child); //! Add a child to the parent item. void addItem( - ProblemTreeItem* parent, - ProblemTreeItem* child); + StatusTreeItem* parent, + StatusTreeItem* child); //! Remove the item from the model. void removeItem( - ProblemTreeItem* item); + StatusTreeItem* item); //! Return the root item of the model. - ProblemTreeItem* rootItem() const; + StatusTreeItem* rootItem() const; //! Return the depth for the given index Q_INVOKABLE int depth( @@ -141,15 +141,15 @@ class ProblemTreeModel : public QAbstractItemModel // Check if top level item is defined bool containsTopLevelItem( - ProblemTreeItem* child); + StatusTreeItem* child); // Check if item is defined in the parent item bool contains( - ProblemTreeItem* parent, - ProblemTreeItem* child); + StatusTreeItem* parent, + StatusTreeItem* child); // Returns the child in the given position - ProblemTreeItem* child( + StatusTreeItem* child( int row); // Check if default empty value is the only element @@ -158,14 +158,14 @@ class ProblemTreeModel : public QAbstractItemModel void removeEmptyItem(); //! Looks for a TopLevelItem that matches that id. If not existing, creates new one and returns it - ProblemTreeItem* getTopLevelItem( + StatusTreeItem* getTopLevelItem( const backend::EntityId& id, const std::string& data, const bool& is_error, const std::string& description); void set_source_model( - ProblemTreeModel* source_model); + StatusTreeModel* source_model); /*! * Filters the model if it is defined as proxy @@ -174,19 +174,19 @@ class ProblemTreeModel : public QAbstractItemModel const QVariant& entity_id); private: - ProblemTreeItem* internalPointer( + StatusTreeItem* internalPointer( const QModelIndex& index) const; - ProblemTreeItem* copy( - ProblemTreeItem* source, + StatusTreeItem* copy( + StatusTreeItem* source, const backend::EntityId entity_id); void filter( const backend::EntityId entity_id); private: - ProblemTreeModel* source_model_; - ProblemTreeItem* root_item_; + StatusTreeModel* source_model_; + StatusTreeItem* root_item_; bool is_empty_; backend::EntityId current_filter_; @@ -194,4 +194,4 @@ class ProblemTreeModel : public QAbstractItemModel } // namespace models -#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_PROBLEMTREEMODEL_H +#endif // _EPROSIMA_FASTDDS_MONITOR_MODEL_TREE_StatusTreeModel_H diff --git a/qml.qrc b/qml.qrc index 28a42166..8eb72d0b 100644 --- a/qml.qrc +++ b/qml.qrc @@ -53,8 +53,8 @@ qml/MonitorToolBarButton.qml qml/Panels.qml qml/PhysicalView.qml - qml/ProblemTreeView.qml - qml/ProblemTreeViewItem.qml + qml/StatusTreeView.qml + qml/StatusTreeViewItem.qml qml/QosView.qml qml/ScheduleClearDialog.qml qml/SeriesSetMaxPointsDialog.qml diff --git a/qml/EntitiesMenu.qml b/qml/EntitiesMenu.qml index d43fcf69..160b699b 100644 --- a/qml/EntitiesMenu.qml +++ b/qml/EntitiesMenu.qml @@ -18,6 +18,6 @@ Menu { } MenuItem { text: "View Problems" - onTriggered: filterProblemLog(menu.entityId) + onTriggered: filterEntityStatusLog(menu.entityId) } } diff --git a/qml/LeftPanel.qml b/qml/LeftPanel.qml index 5247a047..35a7435c 100644 --- a/qml/LeftPanel.qml +++ b/qml/LeftPanel.qml @@ -42,7 +42,7 @@ RowLayout { signal explorerEntityInfoChanged(bool status) signal open_topic_view(string domainEntityId, string domainId, string entityId) signal refresh_domain_graph_view(string domainEntityId, string entityId) - signal filter_problem_log(string entityId) + signal filter_entity_status_log(string entityId) MonitoringPanel { id: monitoringPanel @@ -110,8 +110,8 @@ RowLayout { function refreshDomainGraphView(domainEntityId, entityId) { leftPanel.refresh_domain_graph_view(domainEntityId, entityId) } - function filterProblemLog(entityId){ - leftPanel.filter_problem_log(entityId) + function filterEntityStatusLog(entityId){ + leftPanel.filter_entity_status_log(entityId) } function expandAll(view, model) { diff --git a/qml/Panels.qml b/qml/Panels.qml index bd2a1a53..5e80df17 100644 --- a/qml/Panels.qml +++ b/qml/Panels.qml @@ -99,7 +99,7 @@ RowLayout { onExplorerEntityInfoChanged: panels.explorerEntityInfoChanged(status) onOpen_topic_view: tabs.open_topic_view(domainEntityId, domainId, entityId) onRefresh_domain_graph_view: tabs.refresh_domain_graph_view(domainEntityId, entityId) - onFilter_problem_log: statusLayout.filter_problem_log(entityId) + onFilter_entity_status_log: statusLayout.filter_entity_status_log(entityId) } Rectangle { diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index b240d35f..9c39a6c5 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -69,14 +69,14 @@ Item color: "white" - ProblemTreeView { + StatusTreeView { id: status_tree_view anchors.fill: parent anchors.margins: 1 - model: problemModel + model: entityStatusModel - onProblem_filtered:{ + onEntity_status_filtered:{ collapse_status_layout() } @@ -312,7 +312,7 @@ Item } } - function filter_problem_log(entityId) { + function filter_entity_status_log(entityId) { statusLayout.focus_entity_(entityId) } function clean_filter() diff --git a/qml/ProblemTreeView.qml b/qml/StatusTreeView.qml similarity index 90% rename from qml/ProblemTreeView.qml rename to qml/StatusTreeView.qml index 7644e6ec..5dabb9b7 100644 --- a/qml/ProblemTreeView.qml +++ b/qml/StatusTreeView.qml @@ -89,9 +89,9 @@ Flickable { } property int current_filter_: -2 // backend::ID_ALL - signal problem_filtered() + signal entity_status_filtered() - property int handleStyle: ProblemTreeView.Handle.TriangleSmallOutline + property int handleStyle: StatusTreeView.Handle.TriangleSmallOutline contentHeight: tree.height contentWidth: width @@ -112,7 +112,7 @@ Flickable { Connections { function onCurrentIndexChanged() { if(currentIndex) currentData = model.data(currentIndex) } } - ProblemTreeViewItem { + StatusTreeViewItem { id: tree model: root.model @@ -156,12 +156,12 @@ Flickable { function indicatorToString(handle){ switch (handle){ - case ProblemTreeView.Handle.Triangle: return "▶"; - case ProblemTreeView.Handle.TriangleSmall: return "►"; - case ProblemTreeView.Handle.TriangleOutline: return "▷"; - case ProblemTreeView.Handle.TriangleSmallOutline: return "⊳"; - case ProblemTreeView.Handle.Chevron: return "❱"; - case ProblemTreeView.Handle.Arrow: return "➤"; + case StatusTreeView.Handle.Triangle: return "▶"; + case StatusTreeView.Handle.TriangleSmall: return "►"; + case StatusTreeView.Handle.TriangleOutline: return "▷"; + case StatusTreeView.Handle.TriangleSmallOutline: return "⊳"; + case StatusTreeView.Handle.Chevron: return "❱"; + case StatusTreeView.Handle.Arrow: return "➤"; default: return "▶"; } } @@ -188,7 +188,7 @@ Flickable { function filter_model_by_id(entityId) { model.filter_proxy(entityId) - root.problem_filtered() + root.entity_status_filtered() tree.filter(entityId) } } diff --git a/qml/ProblemTreeViewItem.qml b/qml/StatusTreeViewItem.qml similarity index 97% rename from qml/ProblemTreeViewItem.qml rename to qml/StatusTreeViewItem.qml index 9ff53c30..b500de37 100644 --- a/qml/ProblemTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -205,12 +205,12 @@ Item { property var currentIndex: root.model.index(index, 0, parentIndex) property var currentData: root.model.data(currentIndex) - property var currentId: root.model.data(currentIndex, ProblemTreeViewItem.Role.Id) - property var currentStatus: root.model.data(currentIndex, ProblemTreeViewItem.Role.Status) - property var currentKind: root.model.data(currentIndex, ProblemTreeViewItem.Role.Kind) - property var currentValue: root.model.data(currentIndex, ProblemTreeViewItem.Role.Value) - property var currentDescription: root.model.data(currentIndex, ProblemTreeViewItem.Role.Description) - property var currentAlive: root.model.data(currentIndex, ProblemTreeViewItem.Role.Alive) + property var currentId: root.model.data(currentIndex, StatusTreeViewItem.Role.Id) + property var currentStatus: root.model.data(currentIndex, StatusTreeViewItem.Role.Status) + property var currentKind: root.model.data(currentIndex, StatusTreeViewItem.Role.Kind) + property var currentValue: root.model.data(currentIndex, StatusTreeViewItem.Role.Value) + property var currentDescription: root.model.data(currentIndex, StatusTreeViewItem.Role.Description) + property var currentAlive: root.model.data(currentIndex, StatusTreeViewItem.Role.Alive) property Item currentItem: repeater.itemAt(index) property bool expanded: true property bool selected: false @@ -244,7 +244,7 @@ Item { const parent = root.model.index(index, 0, parentIndex) _prop.itemChildCount = root.model.rowCount(parent) // refresh counter - var new_value = root.model.data(_prop.currentIndex, ProblemTreeViewItem.Role.Value) + var new_value = root.model.data(_prop.currentIndex, StatusTreeViewItem.Role.Value) if (new_value != undefined) { _prop.currentValue = new_value @@ -362,7 +362,7 @@ Item { Layout.fillWidth: true - source: "ProblemTreeViewItem.qml" + source: "StatusTreeViewItem.qml" visible: _prop.expanded onLoaded: { diff --git a/qml/TopicMenu.qml b/qml/TopicMenu.qml index 85ba0be4..08a14eed 100644 --- a/qml/TopicMenu.qml +++ b/qml/TopicMenu.qml @@ -36,7 +36,7 @@ Menu { } MenuItem { text: "View problems" - onTriggered: filterProblemLog(menu.entityId) + onTriggered: filterEntityStatusLog(menu.entityId) } MenuItem { text: "Filter graph view" diff --git a/src/Engine.cpp b/src/Engine.cpp index 070953cd..108a4671 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -87,13 +87,13 @@ QObject* Engine::enable() generate_new_status_info_(); fill_status_(); - // Creates a default json structure for problems and fills the tree model with it - problem_model_ = new models::ProblemTreeModel(); - update_problem(backend::ID_ALL, backend::StatusKind::INVALID); + // Creates a default json structure for statuses and fills the tree model with it + entity_status_model_ = new models::StatusTreeModel(); + update_entity_status(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_); + entity_status_proxy_model_ = new models::StatusTreeModel(); + entity_status_proxy_model_->set_source_model(entity_status_model_); source_entity_id_model_ = new models::ListModel(new models::EntityItem()); @@ -118,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_proxy_model_); + rootContext()->setContextProperty("entityStatusModel", entity_status_proxy_model_); rootContext()->setContextProperty("entityModelFirst", source_entity_id_model_); rootContext()->setContextProperty("entityModelSecond", destination_entity_id_model_); @@ -140,9 +140,9 @@ QObject* Engine::enable() QObject::connect( this, - &Engine::new_problem_callback_signal, + &Engine::new_status_callback_signal, this, - &Engine::new_problem_callback_slot); + &Engine::new_status_callback_slot); // Set enable as True enabled_ = true; @@ -203,14 +203,14 @@ Engine::~Engine() delete status_model_; } - if (problem_model_) + if (entity_status_model_) { - delete problem_model_; + delete entity_status_model_; } - if (problem_proxy_model_) + if (entity_status_proxy_model_) { - //delete problem_proxy_model_; + //delete entity_status_proxy_model_; } // Auxiliar models @@ -860,12 +860,12 @@ void Engine::process_callback_queue() } } -void Engine::process_problem_callback_queue() +void Engine::process_status_callback_queue() { // It iterates while run_ is activate and the queue has elements - while (!problem_callback_queue_.empty()) + while (!status_callback_queue_.empty()) { - process_problem_callback_(); + process_status_callback_(); } } @@ -875,10 +875,10 @@ bool Engine::are_callbacks_to_process_() return callback_queue_.empty(); } -bool Engine::are_problem_callbacks_to_process_() +bool Engine::are_status_callbacks_to_process_() { - std::lock_guard ml(problem_callback_queue_mutex_); - return problem_callback_queue_.empty(); + std::lock_guard ml(status_callback_queue_mutex_); + return status_callback_queue_.empty(); } bool Engine::add_callback( @@ -894,13 +894,13 @@ bool Engine::add_callback( } bool Engine::add_callback( - backend::ProblemCallback problem_callback) + backend::StatusCallback status_callback) { - std::lock_guard ml(problem_callback_queue_mutex_); - problem_callback_queue_.append(problem_callback); + std::lock_guard ml(status_callback_queue_mutex_); + status_callback_queue_.append(status_callback); // Emit signal to specify there are new data - emit new_problem_callback_signal(); + emit new_status_callback_signal(); return true; } @@ -910,9 +910,9 @@ void Engine::new_callback_slot() process_callback_queue(); } -void Engine::new_problem_callback_slot() +void Engine::new_status_callback_slot() { - process_problem_callback_queue(); + process_status_callback_queue(); } bool Engine::process_callback_() @@ -930,19 +930,19 @@ bool Engine::process_callback_() return read_callback_(first_callback); } -bool Engine::process_problem_callback_() +bool Engine::process_status_callback_() { - backend::ProblemCallback first_problem_callback; + backend::StatusCallback first_status_callback; { - std::lock_guard ml(problem_callback_queue_mutex_); - first_problem_callback = problem_callback_queue_.front(); - problem_callback_queue_.pop_front(); + std::lock_guard ml(status_callback_queue_mutex_); + first_status_callback = status_callback_queue_.front(); + status_callback_queue_.pop_front(); } - qDebug() << "Processing problem callback: " << backend::backend_id_to_models_id(first_problem_callback.entity_id); + qDebug() << "Processing status callback: " << backend::backend_id_to_models_id(first_status_callback.entity_id); - return read_callback_(first_problem_callback); + return read_callback_(first_status_callback); } bool Engine::read_callback_( @@ -972,29 +972,29 @@ bool Engine::read_callback_( } bool Engine::read_callback_( - backend::ProblemCallback problem_callback) + backend::StatusCallback status_callback) { // It should not read callbacks while a domain is being initialized std::lock_guard lock(initializing_monitor_); // update model - return update_problem(problem_callback.entity_id, problem_callback.status_kind); + return update_entity_status(status_callback.entity_id, status_callback.status_kind); } -bool Engine::update_problem( +bool Engine::update_entity_status( const backend::EntityId& id, backend::StatusKind kind) { int counter = 0; - auto empty_item = new models::ProblemTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string("")); + auto empty_item = new models::StatusTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string("")); if (id == backend::ID_ALL) { - problem_model_->addTopLevelItem(empty_item); + entity_status_model_->addTopLevelItem(empty_item); } else { backend::StatusLevel new_status = backend::StatusLevel::OK; - std::string description = backend::problem_description(kind); + std::string description = backend::entity_status_description(kind); switch (kind) { @@ -1004,7 +1004,7 @@ bool Engine::update_problem( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { - auto entity_item = problem_model_->getTopLevelItem( + auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), sample.status == backend::StatusLevel::ERROR, description); backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1018,21 +1018,21 @@ bool Engine::update_problem( } new_status = sample.status; std::string handle_string; - auto deadline_missed_item = new models::ProblemTreeItem(id, kind, std::string("Deadline missed"), + auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), sample.status == backend::StatusLevel::ERROR, std::string(""), description); - auto total_count_item = new models::ProblemTreeItem(id, kind, std::string("Total count:"), + auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), 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()) { handle_string = handle_string + std::to_string(handler); } - auto last_instance_handle_item = new models::ProblemTreeItem(id, kind, + auto last_instance_handle_item = new models::StatusTreeItem(id, kind, std::string("Last instance handle:"), 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); + entity_status_model_->addItem(deadline_missed_item, total_count_item); + entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); + entity_status_model_->addItem(entity_item, deadline_missed_item); counter = entity_item->recalculate_entity_counter(); } break; @@ -1044,7 +1044,7 @@ bool Engine::update_problem( if (sample.status != backend::StatusLevel::OK) { std::string fastdds_version = "v2.12.0"; - auto entity_item = problem_model_->getTopLevelItem( + auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), sample.status == backend::StatusLevel::ERROR, description); backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1057,13 +1057,13 @@ bool Engine::update_problem( entity_item->is_error(false); } new_status = sample.status; - auto incompatible_qos_item = new models::ProblemTreeItem(id, kind, std::string("Incompatible QoS"), + auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), 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, + auto policy_item = new models::StatusTreeItem(id, kind, std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), sample.status == backend::StatusLevel::ERROR, std::to_string(policy.count()), @@ -1072,10 +1072,10 @@ bool Engine::update_problem( std::string("/fastdds/dds_layer/core/policy/standardQosPolicies.html") + backend::policy_documentation_description(policy.policy_id()) + std::string("\">here")); - problem_model_->addItem(incompatible_qos_item, policy_item); + entity_status_model_->addItem(incompatible_qos_item, policy_item); } } - problem_model_->addItem(entity_item, incompatible_qos_item); + entity_status_model_->addItem(entity_item, incompatible_qos_item); counter = entity_item->recalculate_entity_counter(); } break; @@ -1086,7 +1086,7 @@ bool Engine::update_problem( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { - auto entity_item = problem_model_->getTopLevelItem( + auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), sample.status == backend::StatusLevel::ERROR, description); backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1099,10 +1099,10 @@ bool Engine::update_problem( entity_item->is_error(false); } new_status = sample.status; - auto inconsistent_topic_item = new models::ProblemTreeItem(id, kind, std::string("Inconsistent topics:"), + auto inconsistent_topic_item = new models::StatusTreeItem(id, kind, std::string("Inconsistent topics:"), sample.status == backend::StatusLevel::ERROR, std::to_string(sample.inconsistent_topic_status.total_count()), description); - problem_model_->addItem(entity_item, inconsistent_topic_item); + entity_status_model_->addItem(entity_item, inconsistent_topic_item); counter = entity_item->recalculate_entity_counter(); } break; @@ -1113,7 +1113,7 @@ bool Engine::update_problem( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { - auto entity_item = problem_model_->getTopLevelItem( + auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), sample.status == backend::StatusLevel::ERROR, description); backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1126,10 +1126,10 @@ bool Engine::update_problem( entity_item->is_error(false); } new_status = sample.status; - auto liveliness_lost_item = new models::ProblemTreeItem(id, kind, std::string("Liveliness lost:"), + auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), sample.status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_lost_status.total_count()), description); - problem_model_->addItem(entity_item, liveliness_lost_item); + entity_status_model_->addItem(entity_item, liveliness_lost_item); counter = entity_item->recalculate_entity_counter(); } break; @@ -1140,7 +1140,7 @@ bool Engine::update_problem( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { - auto entity_item = problem_model_->getTopLevelItem( + auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), sample.status == backend::StatusLevel::ERROR, description); backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1153,10 +1153,10 @@ bool Engine::update_problem( entity_item->is_error(false); } new_status = sample.status; - auto samples_lost_item = new models::ProblemTreeItem(id, kind, std::string("Samples lost:"), + auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), sample.status == backend::StatusLevel::ERROR, std::to_string(sample.sample_lost_status.total_count()), description); - problem_model_->addItem(entity_item, samples_lost_item); + entity_status_model_->addItem(entity_item, samples_lost_item); counter = entity_item->recalculate_entity_counter(); } break; @@ -1168,7 +1168,7 @@ bool Engine::update_problem( //case backend::StatusKind::STATUSES_SIZE: default: { - // No problem status updates, as always returns OK + // No entity status updates, as always returns OK break; } } @@ -1213,48 +1213,48 @@ bool Engine::update_problem( } controller_->status_counters.total_warnings = total_counter; } - // notify problem model layout changed to refresh layout view - emit problem_proxy_model_->layoutAboutToBeChanged(); + // notify status model layout changed to refresh layout view + emit entity_status_proxy_model_->layoutAboutToBeChanged(); emit controller_->update_status_counters( QString::number(controller_->status_counters.total_errors), QString::number(controller_->status_counters.total_warnings)); // remove empty message if exists - if (problem_model_->is_empty()) + if (entity_status_model_->is_empty()) { - problem_model_->removeEmptyItem(); + entity_status_model_->removeEmptyItem(); } // update view - problem_proxy_model_->set_source_model(problem_model_); + entity_status_proxy_model_->set_source_model(entity_status_model_); - // notify problem model layout changed to refresh layout view - emit problem_proxy_model_->layoutChanged(); + // notify status model layout changed to refresh layout view + emit entity_status_proxy_model_->layoutChanged(); } } return true; } -bool Engine::update_problem_entities( +bool Engine::update_entity_status_entities( const backend::EntityId& id) { - // check if there are entities in the problem model - if (!problem_model_->is_empty()) + // check if there are entities in the status model + if (!entity_status_model_->is_empty()) { // get info from id EntityInfo entity_info = backend_connection_.get_info(id); - // update problem model if not alive + // update status model if not alive if (!entity_info["alive"]) { // remove item from tree - problem_model_->removeItem(problem_model_->getTopLevelItem(id, "", false, "")); + entity_status_model_->removeItem(entity_status_model_->getTopLevelItem(id, "", false, "")); // add empty item if removed last item - if (problem_model_->rowCount(problem_model_->rootIndex()) == 0) + if (entity_status_model_->rowCount(entity_status_model_->rootIndex()) == 0) { - problem_model_->addTopLevelItem(new models::ProblemTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string(""))); + entity_status_model_->addTopLevelItem(new models::StatusTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string(""))); } @@ -1286,17 +1286,17 @@ bool Engine::update_problem_entities( controller_->status_counters.warnings.erase(id); // refresh layout - emit problem_proxy_model_->layoutAboutToBeChanged(); + emit entity_status_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_); + entity_status_proxy_model_->set_source_model(entity_status_model_); - // notify problem model layout changed to refresh layout view - emit problem_proxy_model_->layoutChanged(); + // notify status model layout changed to refresh layout view + emit entity_status_proxy_model_->layoutChanged(); } return true; } @@ -1332,17 +1332,17 @@ bool Engine::update_entity_generic( entity_id, &Engine::update_topic, !is_update, is_last_clicked); case backend::EntityKind::PARTICIPANT: - update_problem_entities(entity_id); + update_entity_status_entities(entity_id); return update_entity( entity_id, &Engine::update_participant, !is_update, is_last_clicked); case backend::EntityKind::DATAWRITER: - update_problem_entities(entity_id); + update_entity_status_entities(entity_id); return update_entity( entity_id, &Engine::update_datawriter, !is_update, is_last_clicked); case backend::EntityKind::DATAREADER: - update_problem_entities(entity_id); + update_entity_status_entities(entity_id); return update_entity( entity_id, &Engine::update_datareader, !is_update, is_last_clicked); diff --git a/src/backend/Listener.cpp b/src/backend/Listener.cpp index 64f309b9..26b57379 100644 --- a/src/backend/Listener.cpp +++ b/src/backend/Listener.cpp @@ -174,7 +174,7 @@ void Listener::on_status_reported( EntityId entity_id, StatusKind status_kind) { - engine_->add_callback(ProblemCallback(domain_id, entity_id, status_kind)); + engine_->add_callback(StatusCallback(domain_id, entity_id, status_kind)); } } //namespace backend diff --git a/src/backend/backend_utils.cpp b/src/backend/backend_utils.cpp index 063e02da..27c1982c 100644 --- a/src/backend/backend_utils.cpp +++ b/src/backend/backend_utils.cpp @@ -490,7 +490,7 @@ std::string policy_id_to_string( } } -std::string problem_description( +std::string entity_status_description( const backend::StatusKind kind) { switch (kind) { diff --git a/src/model/tree/ProblemTreeItem.cpp b/src/model/tree/StatusTreeItem.cpp similarity index 76% rename from src/model/tree/ProblemTreeItem.cpp rename to src/model/tree/StatusTreeItem.cpp index d10ae97b..d5964343 100644 --- a/src/model/tree/ProblemTreeItem.cpp +++ b/src/model/tree/StatusTreeItem.cpp @@ -43,12 +43,12 @@ #include #include -#include -#include +#include +#include namespace models { -ProblemTreeItem::ProblemTreeItem() +StatusTreeItem::StatusTreeItem() : parent_item_(nullptr) , id_(backend::ID_ALL) , kind_(backend::StatusKind::INVALID) @@ -67,7 +67,7 @@ ProblemTreeItem::ProblemTreeItem() { } -ProblemTreeItem::ProblemTreeItem( +StatusTreeItem::StatusTreeItem( const QVariant& data) : parent_item_(nullptr) , id_(backend::ID_ALL) @@ -87,7 +87,7 @@ ProblemTreeItem::ProblemTreeItem( { } -ProblemTreeItem::ProblemTreeItem( +StatusTreeItem::StatusTreeItem( const backend::EntityId& id, const std::string& name, const bool& is_error, @@ -110,7 +110,7 @@ ProblemTreeItem::ProblemTreeItem( { } -ProblemTreeItem::ProblemTreeItem( +StatusTreeItem::StatusTreeItem( const backend::EntityId& id, const backend::StatusKind& kind, const std::string& name, @@ -135,24 +135,24 @@ ProblemTreeItem::ProblemTreeItem( { } -ProblemTreeItem::~ProblemTreeItem() +StatusTreeItem::~StatusTreeItem() { qDeleteAll(child_items_); } -ProblemTreeItem* ProblemTreeItem::parentItem() +StatusTreeItem* StatusTreeItem::parentItem() { return parent_item_; } -void ProblemTreeItem::setParentItem( - ProblemTreeItem* parentItem) +void StatusTreeItem::setParentItem( + StatusTreeItem* parentItem) { parent_item_ = parentItem; } -void ProblemTreeItem::appendChild( - ProblemTreeItem* item) +void StatusTreeItem::appendChild( + StatusTreeItem* item) { if (item && !child_items_.contains(item)) { @@ -160,8 +160,8 @@ void ProblemTreeItem::appendChild( } } -void ProblemTreeItem::removeChild( - ProblemTreeItem* item) +void StatusTreeItem::removeChild( + StatusTreeItem* item) { if (item) { @@ -169,95 +169,95 @@ void ProblemTreeItem::removeChild( } } -ProblemTreeItem* ProblemTreeItem::child( +StatusTreeItem* StatusTreeItem::child( int row) { return child_items_.value(row); } -int ProblemTreeItem::childCount() const +int StatusTreeItem::childCount() const { return child_items_.count(); } -const QVariant& ProblemTreeItem::data() const +const QVariant& StatusTreeItem::data() const { - return this->data(models::ProblemTreeModel::ModelItemRoles::nameRole); + return this->data(models::StatusTreeModel::ModelItemRoles::nameRole); } -const QVariant& ProblemTreeItem::data( +const QVariant& StatusTreeItem::data( int role) const { switch (role) { - case models::ProblemTreeModel::ModelItemRoles::idRole: + case models::StatusTreeModel::ModelItemRoles::idRole: return this->entity_id(); - case models::ProblemTreeModel::ModelItemRoles::statusRole: + case models::StatusTreeModel::ModelItemRoles::statusRole: return this->status(); - case models::ProblemTreeModel::ModelItemRoles::kindRole: + case models::StatusTreeModel::ModelItemRoles::kindRole: return this->status_kind(); - case models::ProblemTreeModel::ModelItemRoles::valueRole: + case models::StatusTreeModel::ModelItemRoles::valueRole: return this->value(); - case models::ProblemTreeModel::ModelItemRoles::descriptionRole: + case models::StatusTreeModel::ModelItemRoles::descriptionRole: return this->description(); - case models::ProblemTreeModel::ModelItemRoles::aliveRole: + case models::StatusTreeModel::ModelItemRoles::aliveRole: return this->alive(); - case models::ProblemTreeModel::ModelItemRoles::nameRole: + case models::StatusTreeModel::ModelItemRoles::nameRole: default: return this->name(); } } -const QVariant& ProblemTreeItem::entity_id() const +const QVariant& StatusTreeItem::entity_id() const { return id_variant_; } -const QVariant& ProblemTreeItem::status_kind() const +const QVariant& StatusTreeItem::status_kind() const { return kind_variant_; } -const QVariant& ProblemTreeItem::name() const +const QVariant& StatusTreeItem::name() const { return name_variant_; } -const QVariant& ProblemTreeItem::status() const +const QVariant& StatusTreeItem::status() const { return is_status_error_variant_; } -const QVariant& ProblemTreeItem::value() const +const QVariant& StatusTreeItem::value() const { return value_variant_; } -const QVariant& ProblemTreeItem::description() const +const QVariant& StatusTreeItem::description() const { return description_variant_; } -const QVariant& ProblemTreeItem::alive() const +const QVariant& StatusTreeItem::alive() const { return is_active_variant_; } -void ProblemTreeItem::setData( +void StatusTreeItem::setData( const QVariant& data) { name_variant_ = data; } -bool ProblemTreeItem::isLeaf() const +bool StatusTreeItem::isLeaf() const { return child_items_.isEmpty(); } -int ProblemTreeItem::depth() const +int StatusTreeItem::depth() const { int depth = 0; - ProblemTreeItem* anchestor = parent_item_; + StatusTreeItem* anchestor = parent_item_; while (anchestor) { ++depth; @@ -267,54 +267,54 @@ int ProblemTreeItem::depth() const return depth; } -int ProblemTreeItem::row() const +int StatusTreeItem::row() const { if (parent_item_) { - return parent_item_->child_items_.indexOf(const_cast(this)); + return parent_item_->child_items_.indexOf(const_cast(this)); } return 0; } -backend::EntityId ProblemTreeItem::id() +backend::EntityId StatusTreeItem::id() { return id_; } -backend::StatusKind ProblemTreeItem::kind() +backend::StatusKind StatusTreeItem::kind() { return kind_; } -bool ProblemTreeItem::is_error() +bool StatusTreeItem::is_error() { return is_status_error_; } -void ProblemTreeItem::is_error( +void StatusTreeItem::is_error( bool val) { is_status_error_ = val; is_status_error_variant_ = QVariant(val); } -std::string ProblemTreeItem::name_str() +std::string StatusTreeItem::name_str() { return name_; } -std::string ProblemTreeItem::value_str() +std::string StatusTreeItem::value_str() { return value_; } -std::string ProblemTreeItem::description_str() +std::string StatusTreeItem::description_str() { return description_; } -int ProblemTreeItem::recalculate_entity_counter() +int StatusTreeItem::recalculate_entity_counter() { int count = 0; // check if top level item / entity item diff --git a/src/model/tree/ProblemTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp similarity index 82% rename from src/model/tree/ProblemTreeModel.cpp rename to src/model/tree/StatusTreeModel.cpp index 95ca7f85..659469de 100644 --- a/src/model/tree/ProblemTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -39,7 +39,7 @@ // You should have received a copy of the GNU General Public License // along with eProsima Fast DDS Monitor. If not, see . -#include +#include #include #include @@ -48,30 +48,30 @@ namespace models { -ProblemTreeModel::ProblemTreeModel( +StatusTreeModel::StatusTreeModel( QObject* parent) : QAbstractItemModel(parent) , source_model_(nullptr) - , root_item_{ new ProblemTreeItem() } + , root_item_{ new StatusTreeItem() } , is_empty_(false) , current_filter_(backend::ID_ALL) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } -ProblemTreeModel::~ProblemTreeModel() +StatusTreeModel::~StatusTreeModel() { delete root_item_; } -void ProblemTreeModel::set_source_model( - ProblemTreeModel* source_model) +void StatusTreeModel::set_source_model( + StatusTreeModel* source_model) { source_model_ = source_model; filter(current_filter_); } -void ProblemTreeModel::filter_proxy( +void StatusTreeModel::filter_proxy( const QVariant& entity_id) { if (source_model_) @@ -80,7 +80,7 @@ void ProblemTreeModel::filter_proxy( } } -void ProblemTreeModel::filter( +void StatusTreeModel::filter( const backend::EntityId entity_id) { clear(); @@ -97,14 +97,14 @@ void ProblemTreeModel::filter( } } -ProblemTreeItem* ProblemTreeModel::copy( - ProblemTreeItem* source, +StatusTreeItem* StatusTreeModel::copy( + StatusTreeItem* 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( + StatusTreeItem* destiny = new StatusTreeItem( source->id(), source->kind(), source->name_str(), @@ -121,7 +121,7 @@ ProblemTreeItem* ProblemTreeModel::copy( } -int ProblemTreeModel::rowCount( +int StatusTreeModel::rowCount( const QModelIndex& parent) const { if (!parent.isValid()) @@ -132,14 +132,14 @@ int ProblemTreeModel::rowCount( return internalPointer(parent)->childCount(); } -int ProblemTreeModel::columnCount( +int StatusTreeModel::columnCount( const QModelIndex& /*parent*/) const { // This is basically flatten as a list model return 1; } -QModelIndex ProblemTreeModel::index( +QModelIndex StatusTreeModel::index( const int row, const int column, const QModelIndex& parent) const @@ -149,7 +149,7 @@ QModelIndex ProblemTreeModel::index( return {}; } - ProblemTreeItem* item = root_item_; + StatusTreeItem* item = root_item_; if (parent.isValid()) { item = internalPointer(parent); @@ -163,7 +163,7 @@ QModelIndex ProblemTreeModel::index( return {}; } -QModelIndex ProblemTreeModel::parent( +QModelIndex StatusTreeModel::parent( const QModelIndex& index) const { if (!index.isValid()) @@ -171,8 +171,8 @@ QModelIndex ProblemTreeModel::parent( return {}; } - ProblemTreeItem* childItem = internalPointer(index); - ProblemTreeItem* parentItem = childItem->parentItem(); + StatusTreeItem* childItem = internalPointer(index); + StatusTreeItem* parentItem = childItem->parentItem(); if (!parentItem) { @@ -187,7 +187,7 @@ QModelIndex ProblemTreeModel::parent( return createIndex(parentItem->row(), 0, parentItem); } -QVariant ProblemTreeModel::data( +QVariant StatusTreeModel::data( const QModelIndex& index, const int role) const { @@ -199,7 +199,7 @@ QVariant ProblemTreeModel::data( return internalPointer(index)->data(role); } -bool ProblemTreeModel::setData( +bool StatusTreeModel::setData( const QModelIndex& index, const QVariant& value, int /*role*/) @@ -218,7 +218,7 @@ bool ProblemTreeModel::setData( return false; } -bool ProblemTreeModel::removeRow( +bool StatusTreeModel::removeRow( int /*row*/, const QModelIndex& index) { @@ -237,8 +237,8 @@ bool ProblemTreeModel::removeRow( return false; } -void ProblemTreeModel::addTopLevelItem( - ProblemTreeItem* child) +void StatusTreeModel::addTopLevelItem( + StatusTreeItem* child) { if (child) { @@ -250,9 +250,9 @@ void ProblemTreeModel::addTopLevelItem( } } -void ProblemTreeModel::addItem( - ProblemTreeItem* parent, - ProblemTreeItem* child) +void StatusTreeModel::addItem( + StatusTreeItem* parent, + StatusTreeItem* child) { if (!child || !parent) { @@ -263,10 +263,10 @@ void ProblemTreeModel::addItem( // if parent is topLevelItem (entity item) if (parent->id() != backend::ID_ALL && parent->kind() == backend::StatusKind::INVALID) { - // For each problem in the entity item + // For each status in the entity item for (int i=0; ichildCount(); i++) { - // if overriding problem, remove previous problem + // if overriding status, remove previous status if (parent->child(i)->id() == child->id() && parent->child(i)->kind() == child->kind()) { emit layoutAboutToBeChanged(); @@ -298,8 +298,8 @@ void ProblemTreeModel::addItem( emit layoutChanged(); } -void ProblemTreeModel::removeItem( - ProblemTreeItem* item) +void StatusTreeModel::removeItem( + StatusTreeItem* item) { if (!item) { @@ -318,17 +318,17 @@ void ProblemTreeModel::removeItem( emit layoutChanged(); } -ProblemTreeItem* ProblemTreeModel::rootItem() const +StatusTreeItem* StatusTreeModel::rootItem() const { return root_item_; } -QModelIndex ProblemTreeModel::rootIndex() +QModelIndex StatusTreeModel::rootIndex() { return {}; } -int ProblemTreeModel::depth( +int StatusTreeModel::depth( const QModelIndex& index) const { int count = 0; @@ -346,24 +346,24 @@ int ProblemTreeModel::depth( return count; } -void ProblemTreeModel::clear() +void StatusTreeModel::clear() { emit layoutAboutToBeChanged(); beginResetModel(); delete root_item_; - root_item_ = new ProblemTreeItem(); + root_item_ = new StatusTreeItem(); endResetModel(); emit layoutChanged(); } -ProblemTreeItem* ProblemTreeModel::internalPointer( +StatusTreeItem* StatusTreeModel::internalPointer( const QModelIndex& index) const { - return static_cast(index.internalPointer()); + return static_cast(index.internalPointer()); } -bool ProblemTreeModel::containsTopLevelItem( - ProblemTreeItem* child) +bool StatusTreeModel::containsTopLevelItem( + StatusTreeItem* child) { if (child) { @@ -372,9 +372,9 @@ bool ProblemTreeModel::containsTopLevelItem( return false; } -bool ProblemTreeModel::contains( - ProblemTreeItem* parent, - ProblemTreeItem* child) +bool StatusTreeModel::contains( + StatusTreeItem* parent, + StatusTreeItem* child) { if (!parent || !child) { @@ -391,7 +391,7 @@ bool ProblemTreeModel::contains( return false; } -ProblemTreeItem* ProblemTreeModel::child( +StatusTreeItem* StatusTreeModel::child( int row) { if (row >= 0 && row < root_item_->childCount()) @@ -402,12 +402,12 @@ ProblemTreeItem* ProblemTreeModel::child( return nullptr; } -bool ProblemTreeModel::is_empty() +bool StatusTreeModel::is_empty() { return is_empty_; } -void ProblemTreeModel::removeEmptyItem() +void StatusTreeModel::removeEmptyItem() { emit layoutAboutToBeChanged(); for (int i=0; ichildCount(); i++) @@ -422,7 +422,7 @@ void ProblemTreeModel::removeEmptyItem() emit layoutChanged(); } -ProblemTreeItem* ProblemTreeModel::getTopLevelItem( +StatusTreeItem* StatusTreeModel::getTopLevelItem( const backend::EntityId& id, const std::string& data, const bool& is_error, @@ -439,13 +439,13 @@ ProblemTreeItem* ProblemTreeModel::getTopLevelItem( } // if not existing, create new topLevelItem - ProblemTreeItem* new_entity_item = new ProblemTreeItem(id, data, is_error, description); + StatusTreeItem* new_entity_item = new StatusTreeItem(id, data, is_error, description); addTopLevelItem(new_entity_item); return new_entity_item; } -QHash ProblemTreeModel::roleNames() const +QHash StatusTreeModel::roleNames() const { // TODO Jesus this roles are not currently used in the QML, find out why QHash roles; From 15a9ad65290e61b2525fab95e729ab0e9924098c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 13:46:38 +0100 Subject: [PATCH 13/43] Refs #19743: [ARS] Improve comments Signed-off-by: JesusPoderoso --- include/fastdds_monitor/Engine.h | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index 91674f05..59d986b0 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -268,10 +268,23 @@ class Engine : public QQmlApplicationEngine bool new_entity = true, bool last_clicked = false); + /** + * @brief Update the entity status model with the status kind received + * + * @param id entity id + * @param kind StatusKind reported + * @return true if any change in model has been done + */ bool update_entity_status( const backend::EntityId& id, backend::StatusKind kind); + /** + * @brief Update the entity status counters and populate the model with empty message if empty + * + * @param id entity id + * @return false + */ bool update_entity_status_entities( const backend::EntityId& id); @@ -357,13 +370,13 @@ class Engine : public QQmlApplicationEngine backend::Callback callback); /** - * @brief add a callback arrived from the backend to the callback queue + * @brief add a status callback arrived from the backend to the status callback queue * - * Add a callback to the callback queue in order to process it afterwards by the main thread. - * Emit a signal that communicate the main thread that there are info to process in the callback queue. - * Add a callback issue. + * Add a status callback to the status callback queue in order to process it afterwards by the main thread. + * Emit a signal that communicate the main thread that there are info to process in the status callback queue. + * Add a status callback issue. * - * @param callback new callback to add + * @param callback new status callback to add * @return true */ bool add_callback( @@ -412,7 +425,7 @@ class Engine : public QQmlApplicationEngine void process_callback_queue(); /** - * @brief Pop status callbacks from the callback queues while non empty and update the models + * @brief Pop status callbacks from the status callback queues while non empty and update the models * * @warning This method must be executed from the main Thread (or at least a QThread) so the models are * updated in the view when modified. @@ -537,7 +550,7 @@ class Engine : public QQmlApplicationEngine void new_callback_signal(); /** - * Internal signal that communicate that there are callbacks to process by the main Thread. + * Internal signal that communicate that there are status callbacks to process by the main Thread. * Arise from \c add_callback */ void new_status_callback_signal(); From 2c3a635f651248136264912ddb3e379c2a4ea029 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 13:54:38 +0100 Subject: [PATCH 14/43] Refs #19743: [ARS] Minor sugestions Signed-off-by: JesusPoderoso --- src/Engine.cpp | 7 ++++++- src/model/tree/StatusTreeModel.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 108a4671..068b6a37 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -210,7 +210,7 @@ Engine::~Engine() if (entity_status_proxy_model_) { - //delete entity_status_proxy_model_; + delete entity_status_proxy_model_; } // Auxiliar models @@ -977,6 +977,11 @@ bool Engine::read_callback_( // It should not read callbacks while a domain is being initialized std::lock_guard lock(initializing_monitor_); + // Add callback to log model + add_log_callback_("New entity (" + backend_connection_.get_name(status_callback.entity_id) + ") status reported: " + + backend::status_kind_to_string(status_callback.status_kind), + utils::now()); + // update model return update_entity_status(status_callback.entity_id, status_callback.status_kind); } diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 659469de..9bd17384 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -101,10 +101,10 @@ StatusTreeItem* StatusTreeModel::copy( StatusTreeItem* source, const backend::EntityId entity_id) { - // copy source data in destiny data + // copy source data in destination data if (source->id() == entity_id || entity_id == backend::ID_ALL) { - StatusTreeItem* destiny = new StatusTreeItem( + StatusTreeItem* destination = new StatusTreeItem( source->id(), source->kind(), source->name_str(), @@ -113,9 +113,9 @@ StatusTreeItem* StatusTreeModel::copy( source->description_str()); for (int i = 0; i < source->childCount(); i++) { - addItem(destiny, copy(source->child(i), entity_id)); + addItem(destination, copy(source->child(i), entity_id)); } - return destiny; + return destination; } return nullptr; } From 0a21318b575bc499ea8c0b7d128df26601fc3900 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 10 Nov 2023 19:01:31 +0100 Subject: [PATCH 15/43] Refs #19743: [ARS] Improve entity status assignments Signed-off-by: JesusPoderoso --- src/Engine.cpp | 77 +++++++----------------------- src/model/tree/StatusTreeModel.cpp | 1 + 2 files changed, 19 insertions(+), 59 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 068b6a37..6e4318ee 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1009,24 +1009,16 @@ bool Engine::update_entity_status( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { + backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), - 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); - } + entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; std::string handle_string; auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), - sample.status == backend::StatusLevel::ERROR, std::string(""), description); + new_status == backend::StatusLevel::ERROR, std::string(""), description); auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), - sample.status == backend::StatusLevel::ERROR, + new_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()) { @@ -1034,7 +1026,7 @@ bool Engine::update_entity_status( } auto last_instance_handle_item = new models::StatusTreeItem(id, kind, std::string("Last instance handle:"), - sample.status == backend::StatusLevel::ERROR, handle_string, description); + new_status == backend::StatusLevel::ERROR, handle_string, description); entity_status_model_->addItem(deadline_missed_item, total_count_item); entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); entity_status_model_->addItem(entity_item, deadline_missed_item); @@ -1049,29 +1041,20 @@ bool Engine::update_entity_status( if (sample.status != backend::StatusLevel::OK) { std::string fastdds_version = "v2.12.0"; + backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), - 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); - } + entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), - sample.status == backend::StatusLevel::ERROR, std::string(""), description); + new_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::StatusTreeItem(id, kind, std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(policy.count()), + new_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::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); - } + entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto inconsistent_topic_item = new models::StatusTreeItem(id, kind, std::string("Inconsistent topics:"), - sample.status == backend::StatusLevel::ERROR, + new_status == backend::StatusLevel::ERROR, std::to_string(sample.inconsistent_topic_status.total_count()), description); entity_status_model_->addItem(entity_item, inconsistent_topic_item); counter = entity_item->recalculate_entity_counter(); @@ -1118,21 +1093,13 @@ bool Engine::update_entity_status( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { + backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), - 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); - } + entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), - sample.status == backend::StatusLevel::ERROR, + new_status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, liveliness_lost_item); counter = entity_item->recalculate_entity_counter(); @@ -1145,21 +1112,13 @@ bool Engine::update_entity_status( backend_connection_.get_status_data(id, sample); if (sample.status != backend::StatusLevel::OK) { + backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( id, backend_connection_.get_name(id), - 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); - } + entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), - sample.status == backend::StatusLevel::ERROR, + new_status == backend::StatusLevel::ERROR, std::to_string(sample.sample_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, samples_lost_item); counter = entity_item->recalculate_entity_counter(); diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 9bd17384..54e2045e 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -92,6 +92,7 @@ void StatusTreeModel::filter( { for (int i = 0; i < source_model_->rootItem()->childCount(); i++) { + addTopLevelItem(copy(source_model_->rootItem()->child(i), entity_id)); } } From 6c4a09acccf0db9df382d571218f4d51deea6703 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 08:44:06 +0100 Subject: [PATCH 16/43] Refs #19743: [ARS] Add missing problem sample 'Liveliness changed' Signed-off-by: JesusPoderoso --- src/Engine.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 6e4318ee..fd93935c 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1087,6 +1087,42 @@ bool Engine::update_entity_status( } break; } + case backend::StatusKind::LIVELINESS_CHANGED: + { + backend::LivelinessChangedSample sample; + backend_connection_.get_status_data(id, sample); + if (sample.status != backend::StatusLevel::OK) + { + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), + entity_status == backend::StatusLevel::ERROR, description); + new_status = sample.status; + auto liveliness_changed_item = new models::StatusTreeItem(id, kind, std::string("Liveliness changed"), + new_status == backend::StatusLevel::ERROR, std::string(""), description); + std::string handle_string; + auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), + new_status == backend::StatusLevel::ERROR, + std::to_string(sample.liveliness_changed_status.alive_count()), description); + auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), + new_status == backend::StatusLevel::ERROR, + std::to_string(sample.liveliness_changed_status.not_alive_count()), description); + for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) + { + handle_string = handle_string + std::to_string(handler); + } + auto last_publication_handle_item = new models::StatusTreeItem(id, kind, + std::string("Last publication handle:"), + new_status == backend::StatusLevel::ERROR, handle_string, description); + + entity_status_model_->addItem(liveliness_changed_item, alive_count_item); + entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); + entity_status_model_->addItem(liveliness_changed_item, last_publication_handle_item); + entity_status_model_->addItem(entity_item, liveliness_changed_item); + counter = entity_item->recalculate_entity_counter(); + } + break; + } case backend::StatusKind::LIVELINESS_LOST: { backend::LivelinessLostSample sample; @@ -1127,7 +1163,6 @@ bool Engine::update_entity_status( } case backend::StatusKind::CONNECTION_LIST: - case backend::StatusKind::LIVELINESS_CHANGED: case backend::StatusKind::PROXY: //case backend::StatusKind::STATUSES_SIZE: default: From 08ae1ac0584ca31116e2590c7d83d0d92fb61f98 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 09:19:51 +0100 Subject: [PATCH 17/43] Refs #19743: [ARS] Improve error / warning counter update and update left panel info when problem reported Signed-off-by: JesusPoderoso --- include/fastdds_monitor/Controller.h | 4 +-- src/Engine.cpp | 48 +++++++++++----------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/include/fastdds_monitor/Controller.h b/include/fastdds_monitor/Controller.h index b1f5a40b..220b3bb7 100644 --- a/include/fastdds_monitor/Controller.h +++ b/include/fastdds_monitor/Controller.h @@ -66,8 +66,8 @@ class Controller : public QObject { std::map errors; std::map warnings; - uint32_t total_errors = 0; - uint32_t total_warnings = 0; + int32_t total_errors = 0; + int32_t total_warnings = 0; } status_counters; public slots: diff --git a/src/Engine.cpp b/src/Engine.cpp index fd93935c..d4f9866b 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -982,6 +982,9 @@ bool Engine::read_callback_( + backend::status_kind_to_string(status_callback.status_kind), utils::now()); + // update left panel + update_entity_generic(status_callback.entity_id, backend_connection_.get_type(status_callback.entity_id) , true, false); + // update model return update_entity_status(status_callback.entity_id, status_callback.status_kind); } @@ -1173,44 +1176,33 @@ bool Engine::update_entity_status( } if (new_status != backend::StatusLevel::OK) { - std::map::iterator it; - uint32_t total_counter = 0; - bool found = false; if (new_status == backend::StatusLevel::ERROR) { - for (it = controller_->status_counters.errors.begin(); it != controller_->status_counters.errors.end(); it++) + std::map::iterator it = controller_->status_counters.errors.find(id); + if(it != controller_->status_counters.errors.end()) { - if (it->first == id) + controller_->status_counters.total_errors -= controller_->status_counters.errors[id]; + if (controller_->status_counters.total_errors < 0) { - //element found; - found = true; - it->second = counter; + controller_->status_counters.total_errors = 0; } - total_counter += it->second; - } - if (!found) - { - controller_->status_counters.errors.insert(std::pair(id, counter)); } - controller_->status_counters.total_errors = total_counter; + controller_->status_counters.errors[id] = counter; + controller_->status_counters.total_errors += controller_->status_counters.errors[id]; } else if (new_status == backend::StatusLevel::WARNING) { - for (it = controller_->status_counters.warnings.begin(); it != controller_->status_counters.warnings.end(); it++) + std::map::iterator it = controller_->status_counters.warnings.find(id); + if(it != controller_->status_counters.warnings.end()) { - if (it->first == id) + controller_->status_counters.total_warnings -= controller_->status_counters.warnings[id]; + if (controller_->status_counters.total_warnings < 0) { - //element found; - found = true; - it->second = counter; + controller_->status_counters.total_warnings = 0; } - total_counter += it->second; } - if (!found) - { - controller_->status_counters.warnings.insert(std::pair(id, counter)); - } - controller_->status_counters.total_warnings = total_counter; + controller_->status_counters.warnings[id] = counter; + controller_->status_counters.total_warnings += controller_->status_counters.warnings[id]; } // notify status model layout changed to refresh layout view emit entity_status_proxy_model_->layoutAboutToBeChanged(); @@ -1256,15 +1248,13 @@ bool Engine::update_entity_status_entities( entity_status_model_->addTopLevelItem(new models::StatusTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string(""))); } - - uint32_t error_checker = 0 - 100; // update error counter std::map::iterator err_it = controller_->status_counters.errors.find(id); if(err_it != controller_->status_counters.errors.end()) { //element found; controller_->status_counters.total_errors -= err_it->second; - if (controller_->status_counters.total_errors > error_checker) + if (controller_->status_counters.total_errors < 0) { controller_->status_counters.total_errors = 0; } @@ -1277,7 +1267,7 @@ bool Engine::update_entity_status_entities( { //element found; controller_->status_counters.total_warnings -= warn_it->second; - if (controller_->status_counters.total_warnings > error_checker) + if (controller_->status_counters.total_warnings < 0) { controller_->status_counters.total_warnings = 0; } From 9a69d1990c6853b1c2a5395c53b7c9c57569236e Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 09:34:46 +0100 Subject: [PATCH 18/43] Refs #19743: [ARS] Rename method Signed-off-by: JesusPoderoso --- include/fastdds_monitor/Engine.h | 2 +- src/Engine.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fastdds_monitor/Engine.h b/include/fastdds_monitor/Engine.h index 59d986b0..d55cf86e 100644 --- a/include/fastdds_monitor/Engine.h +++ b/include/fastdds_monitor/Engine.h @@ -285,7 +285,7 @@ class Engine : public QQmlApplicationEngine * @param id entity id * @return false */ - bool update_entity_status_entities( + bool remove_inactive_entities_from_status_model( const backend::EntityId& id); /** diff --git a/src/Engine.cpp b/src/Engine.cpp index d4f9866b..c00e2e5e 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1227,7 +1227,7 @@ bool Engine::update_entity_status( return true; } -bool Engine::update_entity_status_entities( +bool Engine::remove_inactive_entities_from_status_model( const backend::EntityId& id) { // check if there are entities in the status model @@ -1321,17 +1321,17 @@ bool Engine::update_entity_generic( entity_id, &Engine::update_topic, !is_update, is_last_clicked); case backend::EntityKind::PARTICIPANT: - update_entity_status_entities(entity_id); + remove_inactive_entities_from_status_model(entity_id); return update_entity( entity_id, &Engine::update_participant, !is_update, is_last_clicked); case backend::EntityKind::DATAWRITER: - update_entity_status_entities(entity_id); + remove_inactive_entities_from_status_model(entity_id); return update_entity( entity_id, &Engine::update_datawriter, !is_update, is_last_clicked); case backend::EntityKind::DATAREADER: - update_entity_status_entities(entity_id); + remove_inactive_entities_from_status_model(entity_id); return update_entity( entity_id, &Engine::update_datareader, !is_update, is_last_clicked); From 67699fbba68ca9de31473243263a24ce398dc9cd Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 09:36:02 +0100 Subject: [PATCH 19/43] Refs #19743: [ARS] QML minor changes Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 1 - qml/TopicMenu.qml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 748ce3f8..47765886 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -1005,7 +1005,6 @@ Item } else { controller.participant_click(modelData["id"]) } - } } } diff --git a/qml/TopicMenu.qml b/qml/TopicMenu.qml index 08a14eed..b1fd64c3 100644 --- a/qml/TopicMenu.qml +++ b/qml/TopicMenu.qml @@ -20,7 +20,7 @@ import QtQuick.Controls 2.15 import Theme 1.0 /* - Menu containing the possible actions that can be performed on any DDS, physical and logical entity. + Menu containing the possible actions that can be performed on topic entities. */ Menu { id: topicMenu From 5b533f96fc549099344306f756df003ab6bcffa1 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 11:03:33 +0100 Subject: [PATCH 20/43] Refs #19743: [ARS] Improve graph connections section Signed-off-by: JesusPoderoso --- qml/GraphConnection.qml | 42 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index b670b1af..ee2f2151 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -2,15 +2,22 @@ import QtQuick 2.0 Item { // public property - property bool left_direction: false // defines if the represented connection must draw a left arrow - property bool right_direction: false // defines if the represented connection must draw a right arrow - property int left_margin: 0 // left margin to be applied - property string arrow_color: Theme.grey // connection color - property string background_color: "white" // background color + property bool left_direction: false // defines if the represented connection must draw a left arrow + property bool right_direction: false // defines if the represented connection must draw a right arrow + property int left_margin: 0 // left margin to be applied + property string arrow_color: Theme.grey // connection color + property string background_color: "white" // background color // readonly private design properties - readonly property int arrow_margin_: -3 // margins for background - readonly property int arrow_size_: 18 // arrow size + readonly property int arrow_margin_: -3 // margins for background + readonly property int arrow_size_: 18 // arrow size + readonly property int main_left_margin_: 10 // left arrow margin size + readonly property int main_right_margin_: 15 // right arrow margin size + readonly property int left_arrow_background_: 15 // left arrow background size + readonly property int left_arrow_background_icon_size_offset_: 8 + readonly property int left_arrow_background_margin_: -4 + readonly property int left_arrow_margin_: -5 // left arrow margin + readonly property int right_arrow_margin_: -2 // right arrow margin // background to make connection overlap nicely with previous topics (looks like connection goes OVER the topic) Rectangle { @@ -23,6 +30,7 @@ Item { color: "white" } + //background to make connection overlap nicely left panel Rectangle { id: left_background anchors.top: parent.top; anchors.bottom: parent.bottom @@ -39,18 +47,18 @@ Item { Item { id: left_arrow_background visible: left_direction - height: arrow_size_ + 15 + height: arrow_size_ + left_arrow_background_ width: arrow_size_ clip: true anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left; anchors.leftMargin: -4 + anchors.left: parent.left; anchors.leftMargin: left_arrow_background_margin_ IconSVG { anchors.left: parent.left anchors.top: parent.top name: "left_arrow" color: "white" - size: arrow_size_ + 8 + size: arrow_size_ + left_arrow_background_icon_size_offset_ } IconSVG { @@ -58,7 +66,7 @@ Item { anchors.bottom: parent.bottom name: "left_arrow" color: "white" - size: arrow_size_ + 8 + size: arrow_size_ + left_arrow_background_icon_size_offset_ } } @@ -69,7 +77,7 @@ Item { height: arrow_size_ width: arrow_size_ anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left; anchors.leftMargin: -5 + anchors.left: parent.left; anchors.leftMargin: left_arrow_margin_ IconSVG { name: "left_arrow" @@ -83,8 +91,8 @@ Item { id: base_arrow anchors.top: parent.top; anchors.bottom: parent.bottom anchors.left: parent.left; anchors.right: parent.right - anchors.leftMargin: left_direction ? 10 : 0 - anchors.rightMargin: right_direction ? 15 : 0 + anchors.leftMargin: left_direction ? main_left_margin_ : 0 + anchors.rightMargin: right_direction ? main_right_margin_ : 0 color: arrow_color } @@ -92,15 +100,15 @@ Item { Item { id: right_arrow visible: right_direction - height: arrow_size_ -2 - width: arrow_size_ -2 + height: arrow_size_ + right_arrow_margin_ + width: arrow_size_ + right_arrow_margin_ anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right; anchors.rightMargin: parent.height /2 IconSVG { name: "right_arrow" color: "grey" - size: arrow_size_-2 + size: arrow_size_ + right_arrow_margin_ } } } From 1a105ea5a6fd135222ed0cb2051b7f42a99c48b7 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 11:11:22 +0100 Subject: [PATCH 21/43] Refs #19743: [ARS] Fix style in the imported qml files Signed-off-by: JesusPoderoso --- qml/StatusTreeView.qml | 9 ++- qml/StatusTreeViewItem.qml | 158 ++++++++++++++++++------------------- 2 files changed, 87 insertions(+), 80 deletions(-) diff --git a/qml/StatusTreeView.qml b/qml/StatusTreeView.qml index 5dabb9b7..6371a37a 100644 --- a/qml/StatusTreeView.qml +++ b/qml/StatusTreeView.qml @@ -110,7 +110,14 @@ Flickable { } } - Connections { function onCurrentIndexChanged() { if(currentIndex) currentData = model.data(currentIndex) } } + Connections { + function onCurrentIndexChanged() { + if(currentIndex) + { + currentData = model.data(currentIndex) + } + } + } StatusTreeViewItem { id: tree diff --git a/qml/StatusTreeViewItem.qml b/qml/StatusTreeViewItem.qml index b500de37..c4d01a8f 100644 --- a/qml/StatusTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -201,40 +201,40 @@ Item { spacing: 0 QtObject { - id: _prop - - property var currentIndex: root.model.index(index, 0, parentIndex) - property var currentData: root.model.data(currentIndex) - property var currentId: root.model.data(currentIndex, StatusTreeViewItem.Role.Id) - property var currentStatus: root.model.data(currentIndex, StatusTreeViewItem.Role.Status) - property var currentKind: root.model.data(currentIndex, StatusTreeViewItem.Role.Kind) - property var currentValue: root.model.data(currentIndex, StatusTreeViewItem.Role.Value) - property var currentDescription: root.model.data(currentIndex, StatusTreeViewItem.Role.Description) - property var currentAlive: root.model.data(currentIndex, StatusTreeViewItem.Role.Alive) - property Item currentItem: repeater.itemAt(index) - property bool expanded: true - property bool selected: false - property int itemChildCount: root.model.rowCount(currentIndex) - readonly property int depth: root.model.depth(currentIndex) - readonly property bool hasChildren: itemChildCount > 0 - readonly property bool isSelectedIndex: root.selectionEnabled && currentIndex === root.selectedIndex - readonly property bool isHoveredIndex: root.hoverEnabled && currentIndex === root.hoveredIndex - readonly property bool isSelectedAndHoveredIndex: hoverEnabled && selectionEnabled && isHoveredIndex && isSelectedIndex - - function toggle(){ - if(_prop.hasChildren) - { - _prop.expanded = !_prop.expanded - } + id: _prop + + property var currentIndex: root.model.index(index, 0, parentIndex) + property var currentData: root.model.data(currentIndex) + property var currentId: root.model.data(currentIndex, StatusTreeViewItem.Role.Id) + property var currentStatus: root.model.data(currentIndex, StatusTreeViewItem.Role.Status) + property var currentKind: root.model.data(currentIndex, StatusTreeViewItem.Role.Kind) + property var currentValue: root.model.data(currentIndex, StatusTreeViewItem.Role.Value) + property var currentDescription: root.model.data(currentIndex, StatusTreeViewItem.Role.Description) + property var currentAlive: root.model.data(currentIndex, StatusTreeViewItem.Role.Alive) + property Item currentItem: repeater.itemAt(index) + property bool expanded: true + property bool selected: false + property int itemChildCount: root.model.rowCount(currentIndex) + readonly property int depth: root.model.depth(currentIndex) + readonly property bool hasChildren: itemChildCount > 0 + readonly property bool isSelectedIndex: root.selectionEnabled && currentIndex === root.selectedIndex + readonly property bool isHoveredIndex: root.hoverEnabled && currentIndex === root.hoveredIndex + readonly property bool isSelectedAndHoveredIndex: hoverEnabled && selectionEnabled && isHoveredIndex && isSelectedIndex + + function toggle(){ + if(_prop.hasChildren) + { + _prop.expanded = !_prop.expanded + } - _prop.focus() - root.toggled() - } + _prop.focus() + root.toggled() + } - function focus(){ - controller.endpoint_click(_prop.currentId) - controller.participant_click(_prop.currentId) - } + function focus(){ + controller.endpoint_click(_prop.currentId) + controller.participant_click(_prop.currentId) + } } Connections { @@ -309,11 +309,11 @@ Item { target: root.model ignoreUnknownSignals: true function onDataChanged(modelIndex) { - const changedId = modelIndex.internalId - const currentId = _prop.currentIndex.internalId - if(changedId === currentId){ - contentItemLoader.currentRow.currentData = root.model.data(modelIndex); - } + const changedId = modelIndex.internalId + const currentId = _prop.currentIndex.internalId + if(changedId === currentId){ + contentItemLoader.currentRow.currentData = root.model.data(modelIndex); + } } } } @@ -358,60 +358,60 @@ Item { // loader to populate the children row for each node Loader { - id: loader - - Layout.fillWidth: true + id: loader - source: "StatusTreeViewItem.qml" - visible: _prop.expanded + Layout.fillWidth: true - onLoaded: { - item.model = root.model - item.parentIndex = _prop.currentIndex - item.childCount = _prop.itemChildCount - } + source: "StatusTreeViewItem.qml" + visible: _prop.expanded - Connections { - target: root.model - ignoreUnknownSignals: true - function onLayoutChanged() { - const parent = root.model.index(index, 0, parentIndex) - loader.item.childCount = root.model.rowCount(parent) + onLoaded: { + item.model = root.model + item.parentIndex = _prop.currentIndex + item.childCount = _prop.itemChildCount } - function onToggled() { - root.toggled() + Connections { + target: root.model + ignoreUnknownSignals: true + function onLayoutChanged() { + const parent = root.model.index(index, 0, parentIndex) + loader.item.childCount = root.model.rowCount(parent) + } + + function onToggled() { + root.toggled() + } } - } - Binding { target: loader.item; property: "model"; value: root.model; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "handle"; value: root.handle; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "contentItem"; value: root.contentItem; when: loader.status == Loader.Ready } - - Binding { target: loader.item; property: "currentItem"; value: root.currentItem; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "selectedIndex"; value: root.selectedIndex; when: loader.status == Loader.Ready } - Binding { target: root; property: "currentItem"; value: loader.item.currentItem; when: loader.status == Loader.Ready } - Binding { target: root; property: "selectedIndex"; value: loader.item.selectedIndex; when: loader.status == Loader.Ready } - - Binding { target: loader.item; property: "color"; value: root.color; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "handleColor"; value: root.handleColor; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "hoverEnabled"; value: root.hoverEnabled; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "hoverColor"; value: root.hoverColor; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "selectionEnabled"; value: root.selectionEnabled; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "selectedColor"; value: root.selectedColor; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "selectedItemColor"; value: root.selectedItemColor; when: loader.status == Loader.Ready } - - Binding { target: loader.item; property: "itemLeftPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "rowHeight"; value: root.rowHeight; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "rowPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "rowSpacing"; value: root.rowSpacing; when: loader.status == Loader.Ready } - Binding { target: loader.item; property: "fontMetrics"; value: root.selectedItemColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "model"; value: root.model; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "handle"; value: root.handle; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "contentItem"; value: root.contentItem; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "currentItem"; value: root.currentItem; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedIndex"; value: root.selectedIndex; when: loader.status == Loader.Ready } + Binding { target: root; property: "currentItem"; value: loader.item.currentItem; when: loader.status == Loader.Ready } + Binding { target: root; property: "selectedIndex"; value: loader.item.selectedIndex; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "color"; value: root.color; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "handleColor"; value: root.handleColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "hoverEnabled"; value: root.hoverEnabled; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "hoverColor"; value: root.hoverColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectionEnabled"; value: root.selectionEnabled; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedColor"; value: root.selectedColor; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "selectedItemColor"; value: root.selectedItemColor; when: loader.status == Loader.Ready } + + Binding { target: loader.item; property: "itemLeftPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowHeight"; value: root.rowHeight; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowPadding"; value: root.rowPadding; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "rowSpacing"; value: root.rowSpacing; when: loader.status == Loader.Ready } + Binding { target: loader.item; property: "fontMetrics"; value: root.selectedItemColor; when: loader.status == Loader.Ready } } } } } - function filter (entityId) { + function filter(entityId) { root.filter_(entityId) } From ebcdc84ed6532cf6c1d704a5773dca318dbb9e58 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 11:33:06 +0100 Subject: [PATCH 22/43] Refs #19743: [ARS] Remove unnecessary dead code Signed-off-by: JesusPoderoso --- qml/StatusTreeViewItem.qml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/qml/StatusTreeViewItem.qml b/qml/StatusTreeViewItem.qml index c4d01a8f..cc2762fa 100644 --- a/qml/StatusTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -82,9 +82,6 @@ Item { property alias font: root.fontMetrics.font enum Role { Id=257, Status, Kind, Value, Description, Alive, Name } - // public signal - signal toggled() - // private (internal) signals signal filter_(int entityId) signal unfilter_() @@ -228,7 +225,6 @@ Item { } _prop.focus() - root.toggled() } function focus(){ @@ -378,10 +374,6 @@ Item { const parent = root.model.index(index, 0, parentIndex) loader.item.childCount = root.model.rowCount(parent) } - - function onToggled() { - root.toggled() - } } Binding { target: loader.item; property: "model"; value: root.model; when: loader.status == Loader.Ready } From 119401ae55134dc2070908a0695ba4e4e24848b5 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 11:57:13 +0100 Subject: [PATCH 23/43] Refs #19743: [ARS] Remove unnecessary method Signed-off-by: JesusPoderoso --- qml/StatusLayout.qml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index 9c39a6c5..accf79c5 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -315,8 +315,4 @@ Item function filter_entity_status_log(entityId) { statusLayout.focus_entity_(entityId) } - function clean_filter() - { - statusLayout.clean_filter_() - } } From 4095424866bdda01a47d788285460e0157a26361 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 11:47:59 +0100 Subject: [PATCH 24/43] Refs #19743: [ARS] Refactor tree model filtering Signed-off-by: JesusPoderoso --- qml/StatusTreeView.qml | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/qml/StatusTreeView.qml b/qml/StatusTreeView.qml index 6371a37a..c58f3226 100644 --- a/qml/StatusTreeView.qml +++ b/qml/StatusTreeView.qml @@ -88,7 +88,8 @@ Flickable { Arrow } - property int current_filter_: -2 // backend::ID_ALL + readonly property int filter_all_: -2 // backend::ID_ALL + property int current_filter_: filter_all_ signal entity_status_filtered() property int handleStyle: StatusTreeView.Handle.TriangleSmallOutline @@ -106,7 +107,7 @@ Flickable { { target: root.model function onLayoutChanged() { - root.filter_model() + root.filter_model_by_id(root.current_filter_) } } @@ -176,26 +177,18 @@ Flickable { function clean_filter() { - root.filter_model() - model.filter_proxy(-2) + root.filter_model_by_id(filter_all_) tree.unfilter() } - function filter_model() + function filter_model_by_id(entityId) { - var filter_all = -2 // backend::ID_ALL - - if (current_filter_ != filter_all) + if (current_filter_ != entityId) { - current_filter_ = filter_all - root.filter_model_by_id(current_filter_) + current_filter_ = entityId + model.filter_proxy(current_filter_) + root.entity_status_filtered() + tree.filter(current_filter_) } } - - function filter_model_by_id(entityId) - { - model.filter_proxy(entityId) - root.entity_status_filtered() - tree.filter(entityId) - } } From 5620d090e1490173fc1481f88feb3e6a686f8b12 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 12:00:22 +0100 Subject: [PATCH 25/43] Refs #19743: [ARS] Remove info dead code Signed-off-by: JesusPoderoso --- qml/StatusLayout.qml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index accf79c5..bfc17f96 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -282,21 +282,7 @@ Item warning_value.text = warnings } } - /*IconSVG { - id: info_icon - anchors.left: warning_value.right - anchors.leftMargin: elements_spacing_ - name: "info" - size: parent.height - elements_spacing_ -1 - anchors.verticalCenter: parent.verticalCenter - } - Label { - id: info_value - anchors.left: info_icon.right - anchors.leftMargin: elements_spacing_/2 - anchors.verticalCenter: parent.verticalCenter - text: "19" - }*/ + MouseArea { anchors.fill: parent onClicked: { From 737cfc05440d75340a2a14a52dbb7d0c974863ad Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 12:10:04 +0100 Subject: [PATCH 26/43] Refs #19743: [ARS] Improve StatusLayout.qml comments Signed-off-by: JesusPoderoso --- qml/StatusLayout.qml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index bfc17f96..f27b238e 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -56,30 +56,34 @@ Item property int firstIndentation: 5 property int secondIndentation: firstIndentation + iconSize + spacingIconLabel - + // Main tab view with possibility of multiple tabs TabView { id: tab_view anchors.top: parent.top anchors.bottom: separator_line.top width: parent.width + // Main Problems tab Tab { title: "Problems" Rectangle { color: "white" + // Main content of problems tab: problem tree view with problems per entity StatusTreeView { id: status_tree_view anchors.fill: parent anchors.margins: 1 - model: entityStatusModel + model: entityStatusModel // problems model: entity status proxy model + // display if hidden when problems filtered (from right-click dialog) onEntity_status_filtered:{ collapse_status_layout() } + // filter and clean filter signal-slots management Connections { target: statusLayout @@ -94,8 +98,11 @@ Item } } } + + // Tab main stlye style: TabViewStyle { frameOverlap: 1 + // Each tab style: simple rounded rect header with text tab: Rectangle { color: styleData.selected ? "white" : Theme.lightGrey implicitWidth: Math.max(text.width + 10, tabs_width_) @@ -115,12 +122,15 @@ Item text: styleData.title } } + // Tab bar style: would contain all tabs, and the custom menu on the right section + // (close, expand/collapse, and filter buttons, from right to left) tabBar: Rectangle { anchors.top: parent.top width: parent.width height: tabs_height_ color: grey_background_ + // Close button IconSVG { id: close_icon anchors.right: parent.right @@ -140,6 +150,7 @@ Item } } + // Container with expand and collapse buttons Rectangle { id: rect anchors.right: close_icon.left @@ -178,6 +189,7 @@ Item } } + // Container with filter buttons (filtered/not filtered icons) Rectangle { id: filter_rect anchors.right: rect.left @@ -210,6 +222,7 @@ Item } } + // connections to update filter icons Connections { target: statusLayout @@ -234,6 +247,7 @@ Item color: Theme.grey } + // footer (and ALWAYS displayed) error and warning counters bar section Rectangle { id: icon_section anchors.bottom: parent.bottom @@ -241,7 +255,10 @@ Item width: parent.width color: grey_background_ - Component.onCompleted: { close_status_layout() } + // Close status so only this section is displayed, when component is loaded + Component.onCompleted: { + close_status_layout() + } IconSVG { id: error_icon From f09da2b8d6099f373b8f9ffc1eb47580e4163485 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 12:30:21 +0100 Subject: [PATCH 27/43] Refs #19743: [ARS] Improve pointers deletion Signed-off-by: JesusPoderoso --- src/Engine.cpp | 3 ++- src/model/tree/StatusTreeItem.cpp | 1 + src/model/tree/StatusTreeModel.cpp | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index c00e2e5e..0bbc5b95 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -994,9 +994,10 @@ bool Engine::update_entity_status( backend::StatusKind kind) { int counter = 0; - auto empty_item = new models::StatusTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string("")); if (id == backend::ID_ALL) { + auto empty_item = new models::StatusTreeItem(backend::ID_ALL, + std::string("No issues found"), false, std::string("")); entity_status_model_->addTopLevelItem(empty_item); } else diff --git a/src/model/tree/StatusTreeItem.cpp b/src/model/tree/StatusTreeItem.cpp index d5964343..45bb171b 100644 --- a/src/model/tree/StatusTreeItem.cpp +++ b/src/model/tree/StatusTreeItem.cpp @@ -166,6 +166,7 @@ void StatusTreeItem::removeChild( if (item) { child_items_.removeAll(item); + delete item; } } diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 54e2045e..9bd17384 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -92,7 +92,6 @@ void StatusTreeModel::filter( { for (int i = 0; i < source_model_->rootItem()->childCount(); i++) { - addTopLevelItem(copy(source_model_->rootItem()->child(i), entity_id)); } } From 70ef10a2a1f3b7879dda9459a2116ab7f129c992 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 13 Nov 2023 15:20:18 +0100 Subject: [PATCH 28/43] Refs #19743: Refactor model roles to use direct get methods Signed-off-by: JesusPoderoso --- .../model/tree/StatusTreeItem.h | 7 -- .../model/tree/StatusTreeModel.h | 46 +++++--- qml/StatusTreeViewItem.qml | 15 ++- src/model/tree/StatusTreeItem.cpp | 28 ----- src/model/tree/StatusTreeModel.cpp | 104 ++++++++++++++---- 5 files changed, 119 insertions(+), 81 deletions(-) diff --git a/include/fastdds_monitor/model/tree/StatusTreeItem.h b/include/fastdds_monitor/model/tree/StatusTreeItem.h index 42fe0799..095397ea 100644 --- a/include/fastdds_monitor/model/tree/StatusTreeItem.h +++ b/include/fastdds_monitor/model/tree/StatusTreeItem.h @@ -86,13 +86,6 @@ class StatusTreeItem //! Destroy the item. It will destroy every child. ~StatusTreeItem(); - //! Return the stored data of the node. - const QVariant& data() const; - - //! Return the stored data of the node. - const QVariant& data( - int role) const; - const QVariant& entity_id() const; const QVariant& status_kind() const; diff --git a/include/fastdds_monitor/model/tree/StatusTreeModel.h b/include/fastdds_monitor/model/tree/StatusTreeModel.h index 1611209b..b22a61fd 100644 --- a/include/fastdds_monitor/model/tree/StatusTreeModel.h +++ b/include/fastdds_monitor/model/tree/StatusTreeModel.h @@ -55,7 +55,6 @@ namespace models { class StatusTreeModel : public QAbstractItemModel { Q_OBJECT - //Q_ENUMS(models::StatusTreeItem::ModelItemRoles) public: explicit StatusTreeModel( @@ -66,21 +65,6 @@ class StatusTreeModel : public QAbstractItemModel // Overriden method from QAbstractItemModel public: - - //! Role names to allow queries to get some specific information from the Item - enum ModelItemRoles - { - idRole = Qt::UserRole + 1, //! Role for attribute Id - statusRole, //! Role for attribute Status - kindRole, //! Role for attribute Kind - valueRole, //! Role for attribute Value - descriptionRole, //! Role for attribute Description - aliveRole, //! Role for attribute Alive - nameRole //! Role for attribute Name - // The nameRole must always be the last one as it is used in child classes - // as the initial role of the enumeration) - }; - int rowCount( const QModelIndex& index) const override; int columnCount( @@ -98,6 +82,34 @@ class StatusTreeModel : public QAbstractItemModel const QModelIndex& index, int role = 0) const override; + Q_INVOKABLE QVariant name( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant id( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant status( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant kind( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant value( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant description( + const QModelIndex& index, + int role = 0) const; + + Q_INVOKABLE QVariant alive( + const QModelIndex& index, + int role = 0) const; + bool setData( const QModelIndex& index, const QVariant& value, @@ -107,8 +119,6 @@ class StatusTreeModel : public QAbstractItemModel int row, const QModelIndex &index = QModelIndex()); - QHash roleNames() const override; - public: //! Add an item to the top level. void addTopLevelItem( diff --git a/qml/StatusTreeViewItem.qml b/qml/StatusTreeViewItem.qml index cc2762fa..09395ea6 100644 --- a/qml/StatusTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -80,7 +80,6 @@ Item { font.pointSize: Theme.font.pointSize } property alias font: root.fontMetrics.font - enum Role { Id=257, Status, Kind, Value, Description, Alive, Name } // private (internal) signals signal filter_(int entityId) @@ -202,12 +201,12 @@ Item { property var currentIndex: root.model.index(index, 0, parentIndex) property var currentData: root.model.data(currentIndex) - property var currentId: root.model.data(currentIndex, StatusTreeViewItem.Role.Id) - property var currentStatus: root.model.data(currentIndex, StatusTreeViewItem.Role.Status) - property var currentKind: root.model.data(currentIndex, StatusTreeViewItem.Role.Kind) - property var currentValue: root.model.data(currentIndex, StatusTreeViewItem.Role.Value) - property var currentDescription: root.model.data(currentIndex, StatusTreeViewItem.Role.Description) - property var currentAlive: root.model.data(currentIndex, StatusTreeViewItem.Role.Alive) + property var currentId: root.model.id(currentIndex) + property var currentStatus: root.model.status(currentIndex) + property var currentKind: root.model.kind(currentIndex) + property var currentValue: root.model.value(currentIndex) + property var currentDescription: root.model.description(currentIndex) + property var currentAlive: root.model.alive(currentIndex) property Item currentItem: repeater.itemAt(index) property bool expanded: true property bool selected: false @@ -240,7 +239,7 @@ Item { const parent = root.model.index(index, 0, parentIndex) _prop.itemChildCount = root.model.rowCount(parent) // refresh counter - var new_value = root.model.data(_prop.currentIndex, StatusTreeViewItem.Role.Value) + var new_value = root.model.value(_prop.currentIndex) if (new_value != undefined) { _prop.currentValue = new_value diff --git a/src/model/tree/StatusTreeItem.cpp b/src/model/tree/StatusTreeItem.cpp index 45bb171b..73826b08 100644 --- a/src/model/tree/StatusTreeItem.cpp +++ b/src/model/tree/StatusTreeItem.cpp @@ -181,34 +181,6 @@ int StatusTreeItem::childCount() const return child_items_.count(); } -const QVariant& StatusTreeItem::data() const -{ - return this->data(models::StatusTreeModel::ModelItemRoles::nameRole); -} - -const QVariant& StatusTreeItem::data( - int role) const -{ - switch (role) - { - case models::StatusTreeModel::ModelItemRoles::idRole: - return this->entity_id(); - case models::StatusTreeModel::ModelItemRoles::statusRole: - return this->status(); - case models::StatusTreeModel::ModelItemRoles::kindRole: - return this->status_kind(); - case models::StatusTreeModel::ModelItemRoles::valueRole: - return this->value(); - case models::StatusTreeModel::ModelItemRoles::descriptionRole: - return this->description(); - case models::StatusTreeModel::ModelItemRoles::aliveRole: - return this->alive(); - case models::StatusTreeModel::ModelItemRoles::nameRole: - default: - return this->name(); - } -} - const QVariant& StatusTreeItem::entity_id() const { return id_variant_; diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 9bd17384..777c8f3c 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -187,16 +187,97 @@ QModelIndex StatusTreeModel::parent( return createIndex(parentItem->row(), 0, parentItem); } + QVariant StatusTreeModel::data( const QModelIndex& index, - const int role) const + const int role) const +{ + return name(index, role); +} + +QVariant StatusTreeModel::name( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->name(); +} + + +QVariant StatusTreeModel::id( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->entity_id(); +} + +QVariant StatusTreeModel::status( + const QModelIndex& index, + const int /*role*/) const { - if (!index.isValid()/* || role != Qt::DisplayRole*/) + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->status(); +} + +QVariant StatusTreeModel::kind( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) { return QVariant(); } - return internalPointer(index)->data(role); + return internalPointer(index)->status_kind(); +} + +QVariant StatusTreeModel::value( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->value(); +} + +QVariant StatusTreeModel::description( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->description(); +} + +QVariant StatusTreeModel::alive( + const QModelIndex& index, + const int /*role*/) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + return internalPointer(index)->alive(); } bool StatusTreeModel::setData( @@ -444,21 +525,4 @@ StatusTreeItem* StatusTreeModel::getTopLevelItem( return new_entity_item; } - -QHash StatusTreeModel::roleNames() const -{ - // TODO Jesus this roles are not currently used in the QML, find out why - QHash roles; - - roles[idRole] = "id"; - roles[statusRole] = "status"; - roles[kindRole] = "kind"; - roles[valueRole] = "value"; - roles[descriptionRole] = "description"; - roles[aliveRole] = "alive"; - roles[nameRole] = "name"; - - return roles; -} - } // namespace models From 0dd23966730f2a53302b2a5b980be82ee14827e8 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 09:52:34 +0100 Subject: [PATCH 29/43] Refs #19743: [ALRS] Rename 'copy' model method as 'filtered_copy' Signed-off-by: JesusPoderoso --- include/fastdds_monitor/model/tree/StatusTreeModel.h | 2 +- src/model/tree/StatusTreeModel.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fastdds_monitor/model/tree/StatusTreeModel.h b/include/fastdds_monitor/model/tree/StatusTreeModel.h index b22a61fd..347de647 100644 --- a/include/fastdds_monitor/model/tree/StatusTreeModel.h +++ b/include/fastdds_monitor/model/tree/StatusTreeModel.h @@ -187,7 +187,7 @@ class StatusTreeModel : public QAbstractItemModel StatusTreeItem* internalPointer( const QModelIndex& index) const; - StatusTreeItem* copy( + StatusTreeItem* filtered_copy( StatusTreeItem* source, const backend::EntityId entity_id); diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 777c8f3c..2d8c3667 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -92,12 +92,12 @@ void StatusTreeModel::filter( { for (int i = 0; i < source_model_->rootItem()->childCount(); i++) { - addTopLevelItem(copy(source_model_->rootItem()->child(i), entity_id)); + addTopLevelItem(filtered_copy(source_model_->rootItem()->child(i), entity_id)); } } } -StatusTreeItem* StatusTreeModel::copy( +StatusTreeItem* StatusTreeModel::filtered_copy( StatusTreeItem* source, const backend::EntityId entity_id) { @@ -113,7 +113,7 @@ StatusTreeItem* StatusTreeModel::copy( source->description_str()); for (int i = 0; i < source->childCount(); i++) { - addItem(destination, copy(source->child(i), entity_id)); + addItem(destination, filtered_copy(source->child(i), entity_id)); } return destination; } @@ -190,7 +190,7 @@ QModelIndex StatusTreeModel::parent( QVariant StatusTreeModel::data( const QModelIndex& index, - const int role) const + const int role) const { return name(index, role); } From 1d1d043611c222093e4b7d6e1f828e0661dadb51 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 09:56:25 +0100 Subject: [PATCH 30/43] Refs #19743: [ALRS] Remove repeated description in problems Signed-off-by: JesusPoderoso --- src/Engine.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 0bbc5b95..b4843184 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1023,14 +1023,14 @@ bool Engine::update_entity_status( new_status == backend::StatusLevel::ERROR, std::string(""), description); auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), new_status == backend::StatusLevel::ERROR, - std::to_string(sample.deadline_missed_status.total_count()), description); + std::to_string(sample.deadline_missed_status.total_count()), std::string("")); for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) { handle_string = handle_string + std::to_string(handler); } auto last_instance_handle_item = new models::StatusTreeItem(id, kind, std::string("Last instance handle:"), - new_status == backend::StatusLevel::ERROR, handle_string, description); + new_status == backend::StatusLevel::ERROR, handle_string, std::string("")); entity_status_model_->addItem(deadline_missed_item, total_count_item); entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); entity_status_model_->addItem(entity_item, deadline_missed_item); @@ -1107,17 +1107,17 @@ bool Engine::update_entity_status( std::string handle_string; auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), new_status == backend::StatusLevel::ERROR, - std::to_string(sample.liveliness_changed_status.alive_count()), description); + std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), new_status == backend::StatusLevel::ERROR, - std::to_string(sample.liveliness_changed_status.not_alive_count()), description); + std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) { handle_string = handle_string + std::to_string(handler); } auto last_publication_handle_item = new models::StatusTreeItem(id, kind, std::string("Last publication handle:"), - new_status == backend::StatusLevel::ERROR, handle_string, description); + new_status == backend::StatusLevel::ERROR, handle_string, std::string("")); entity_status_model_->addItem(liveliness_changed_item, alive_count_item); entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); From 1e19b6b76c1b7238b79276a0c3605f821e6c90bf Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 10:54:22 +0100 Subject: [PATCH 31/43] Refs #19743: [ALRS] Rename domain graph public property entity id as 'domain_entity_id' Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 20 ++++++++++---------- qml/TabLayout.qml | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 47765886..d48cbe94 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -27,7 +27,7 @@ Item // Public properties property var model: {} // domain view graph JSON model - property int entity_id // entity id associated to the domain id + property int domain_entity_id // entity id associated to the domain id property int domain_id // domain id required property string component_id // mandatory to be included when object created @@ -237,7 +237,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openTopicMenu(entity_id, domain_id, modelData["id"], modelData["alias"], modelData["kind"]) + openTopicMenu(domain_entity_id, domain_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.topic_click(modelData["id"]) } @@ -573,7 +573,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + openEntitiesMenu(domain_entity_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.host_click(modelData["id"]) } @@ -717,7 +717,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + openEntitiesMenu(domain_entity_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.user_click(modelData["id"]) } @@ -860,7 +860,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + openEntitiesMenu(domain_entity_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.process_click(modelData["id"]) } @@ -1001,7 +1001,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + openEntitiesMenu(domain_entity_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.participant_click(modelData["id"]) } @@ -1198,7 +1198,7 @@ Item onClicked: { if(mouse.button & Qt.RightButton) { - openEntitiesMenu(entity_id, modelData["id"], modelData["alias"], modelData["kind"]) + openEntitiesMenu(domain_entity_id, modelData["id"], modelData["alias"], modelData["kind"]) } else { controller.endpoint_click(modelData["id"]) } @@ -1333,7 +1333,7 @@ Item clear_graph() // Obtain model from backend - var model_string = controller.get_domain_view_graph(entity_id) + var model_string = controller.get_domain_view_graph(domain_entity_id) // declare obtained hosts and topics variables var new_topics = [] @@ -1616,7 +1616,7 @@ Item if (domainEntityId != "") { // belongs to the current domain - if (entity_id.toString() != domainEntityId) + if (domain_entity_id.toString() != domainEntityId) { return false } @@ -1624,7 +1624,7 @@ Item // check all entities by entityId // check domain - if(entity_id.toString() == entityId) + if(domain_entity_id.toString() == entityId) { return true } diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index 942715bf..be26a7d6 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -223,9 +223,9 @@ Item { for (var j=0; j 0) + stack_layout.children[j].currentItem.domain_entity_id > 0) { - controller.domain_click(stack_layout.children[j].currentItem.entity_id) + controller.domain_click(stack_layout.children[j].currentItem.domain_entity_id) break; } } @@ -247,7 +247,7 @@ Item { function onInitialize_domain_view_(stack_id, entity_id, domain_id) { if (domainGraphLayout.component_id == stack_id) { - domainGraphLayout.entity_id = entity_id + domainGraphLayout.domain_entity_id = entity_id domainGraphLayout.domain_id = domain_id domainGraphLayout.load_model() } @@ -255,7 +255,7 @@ Item { function onFilter_domain_view_by_topic_(stack_id, domain_entity_id, topic_id) { if (domainGraphLayout.component_id == stack_id && - domainGraphLayout.entity_id == domain_entity_id) + domainGraphLayout.domain_entity_id == domain_entity_id) { domainGraphLayout.filter_model_by_topic(topic_id) } @@ -507,9 +507,9 @@ Item { for (var i=0; i 0) + stack_layout.children[i].currentItem.domain_entity_id > 0) { - controller.domain_click(stack_layout.children[i].currentItem.entity_id) + controller.domain_click(stack_layout.children[i].currentItem.domain_entity_id) break; } } @@ -634,7 +634,7 @@ Item { function refresh_domain_graph_view(domainEntityId, entityId) { for (var i=0; i Date: Tue, 14 Nov 2023 11:19:22 +0100 Subject: [PATCH 32/43] Refs #19743: [ALRS] Improve status counter anchoring to avoid overlapping numbers and icons Signed-off-by: JesusPoderoso --- qml/StatusLayout.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index f27b238e..b65b7f24 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -277,8 +277,8 @@ Item } IconSVG { id: warning_icon - anchors.left: error_icon.right - anchors.leftMargin: elements_spacing_ * 4 + anchors.left: error_value.right + anchors.leftMargin: elements_spacing_ anchors.verticalCenter: parent.verticalCenter name: "issues" size: parent.height - elements_spacing_ From eccba1995a88ec9c16a1a037486457ab1dce27ad Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 11:24:59 +0100 Subject: [PATCH 33/43] Refs #19743: [ALRS] Improve status sample kind usage Signed-off-by: JesusPoderoso --- src/Engine.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index b4843184..05d1182e 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1020,9 +1020,9 @@ bool Engine::update_entity_status( new_status = sample.status; std::string handle_string; auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), - new_status == backend::StatusLevel::ERROR, std::string(""), description); + sample.status == backend::StatusLevel::ERROR, std::string(""), description); auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), - new_status == backend::StatusLevel::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.deadline_missed_status.total_count()), std::string("")); for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) { @@ -1030,7 +1030,7 @@ bool Engine::update_entity_status( } auto last_instance_handle_item = new models::StatusTreeItem(id, kind, std::string("Last instance handle:"), - new_status == backend::StatusLevel::ERROR, handle_string, std::string("")); + sample.status == backend::StatusLevel::ERROR, handle_string, std::string("")); entity_status_model_->addItem(deadline_missed_item, total_count_item); entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); entity_status_model_->addItem(entity_item, deadline_missed_item); @@ -1051,14 +1051,14 @@ bool Engine::update_entity_status( entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), - new_status == backend::StatusLevel::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::StatusTreeItem(id, kind, std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), - new_status == backend::StatusLevel::ERROR, std::to_string(policy.count()), + sample.status == backend::StatusLevel::ERROR, std::to_string(policy.count()), std::string("Check for compatible rules ") + std::string("addItem(entity_item, inconsistent_topic_item); counter = entity_item->recalculate_entity_counter(); @@ -1103,13 +1103,13 @@ bool Engine::update_entity_status( entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto liveliness_changed_item = new models::StatusTreeItem(id, kind, std::string("Liveliness changed"), - new_status == backend::StatusLevel::ERROR, std::string(""), description); + sample.status == backend::StatusLevel::ERROR, std::string(""), description); std::string handle_string; auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), - new_status == backend::StatusLevel::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), - new_status == backend::StatusLevel::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) { @@ -1117,7 +1117,7 @@ bool Engine::update_entity_status( } auto last_publication_handle_item = new models::StatusTreeItem(id, kind, std::string("Last publication handle:"), - new_status == backend::StatusLevel::ERROR, handle_string, std::string("")); + sample.status == backend::StatusLevel::ERROR, handle_string, std::string("")); entity_status_model_->addItem(liveliness_changed_item, alive_count_item); entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); @@ -1139,7 +1139,7 @@ bool Engine::update_entity_status( entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), - new_status == backend::StatusLevel::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.liveliness_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, liveliness_lost_item); counter = entity_item->recalculate_entity_counter(); @@ -1158,7 +1158,7 @@ bool Engine::update_entity_status( entity_status == backend::StatusLevel::ERROR, description); new_status = sample.status; auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), - new_status == backend::StatusLevel::ERROR, + sample.status == backend::StatusLevel::ERROR, std::to_string(sample.sample_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, samples_lost_item); counter = entity_item->recalculate_entity_counter(); From b54565e6542281ffc73900e0a446cf0a03975c56 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 11:58:43 +0100 Subject: [PATCH 34/43] Refs #19743: [ALRS] Treat entity status model status as StatusLevel instead of as boolean Signed-off-by: JesusPoderoso --- .../fastdds_monitor/backend/backend_types.h | 1 + .../fastdds_monitor/backend/backend_utils.h | 4 ++ .../model/tree/StatusTreeItem.h | 14 ++--- .../model/tree/StatusTreeModel.h | 2 +- qml/StatusTreeViewItem.qml | 6 +- src/Engine.cpp | 57 +++++++------------ src/backend/backend_utils.cpp | 15 +++++ src/model/tree/StatusTreeItem.cpp | 34 +++++------ src/model/tree/StatusTreeModel.cpp | 6 +- 9 files changed, 74 insertions(+), 65 deletions(-) diff --git a/include/fastdds_monitor/backend/backend_types.h b/include/fastdds_monitor/backend/backend_types.h index b21f5b0b..72b3bb32 100644 --- a/include/fastdds_monitor/backend/backend_types.h +++ b/include/fastdds_monitor/backend/backend_types.h @@ -35,6 +35,7 @@ using EntityId = eprosima::statistics_backend::EntityId; using EntityKind = eprosima::statistics_backend::EntityKind; using DataKind = eprosima::statistics_backend::DataKind; using StatusKind = eprosima::statistics_backend::StatusKind; +using StatusLevel = eprosima::statistics_backend::StatusLevel; using StatisticKind = eprosima::statistics_backend::StatisticKind; using EntityInfo = eprosima::statistics_backend::Info; using Timestamp = eprosima::statistics_backend::Timestamp; diff --git a/include/fastdds_monitor/backend/backend_utils.h b/include/fastdds_monitor/backend/backend_utils.h index e6dc56da..5418208d 100644 --- a/include/fastdds_monitor/backend/backend_utils.h +++ b/include/fastdds_monitor/backend/backend_utils.h @@ -91,6 +91,10 @@ std::string statistic_kind_to_string( std::string status_kind_to_string( const StatusKind& status_kind); +//! Converts the \c StatusLevel to string +std::string status_level_to_string( + const StatusLevel& status_level); + //! Retrieves the \c EntityKind related with its name in QString backend::EntityKind string_to_entity_kind( const QString& entity_kind); diff --git a/include/fastdds_monitor/model/tree/StatusTreeItem.h b/include/fastdds_monitor/model/tree/StatusTreeItem.h index 095397ea..89caa2de 100644 --- a/include/fastdds_monitor/model/tree/StatusTreeItem.h +++ b/include/fastdds_monitor/model/tree/StatusTreeItem.h @@ -71,7 +71,7 @@ class StatusTreeItem explicit StatusTreeItem( const backend::EntityId& id, const std::string& name, - const bool& is_error, + const backend::StatusLevel& status_level, const std::string& description); //! Create an item with the status parameters @@ -79,7 +79,7 @@ class StatusTreeItem const backend::EntityId& id, const backend::StatusKind& kind, const std::string& name, - const bool& is_error, + const backend::StatusLevel& status_level, const std::string& value, const std::string& description); @@ -122,10 +122,10 @@ class StatusTreeItem backend::StatusKind kind(); - bool is_error(); + backend::StatusLevel status_level(); - void is_error( - bool val); + void status_level( + backend::StatusLevel val); std::string name_str(); @@ -154,14 +154,14 @@ class StatusTreeItem backend::EntityId id_; backend::StatusKind kind_; std::string name_; - bool is_status_error_; + backend::StatusLevel status_level_; std::string value_; std::string description_; bool is_active_; QVariant id_variant_; QVariant kind_variant_; QVariant name_variant_; - QVariant is_status_error_variant_; + QVariant status_level_variant_; QVariant value_variant_; QVariant description_variant_; QVariant is_active_variant_; diff --git a/include/fastdds_monitor/model/tree/StatusTreeModel.h b/include/fastdds_monitor/model/tree/StatusTreeModel.h index 347de647..1305b240 100644 --- a/include/fastdds_monitor/model/tree/StatusTreeModel.h +++ b/include/fastdds_monitor/model/tree/StatusTreeModel.h @@ -171,7 +171,7 @@ class StatusTreeModel : public QAbstractItemModel StatusTreeItem* getTopLevelItem( const backend::EntityId& id, const std::string& data, - const bool& is_error, + const backend::StatusLevel& status, const std::string& description); void set_source_model( diff --git a/qml/StatusTreeViewItem.qml b/qml/StatusTreeViewItem.qml index 09395ea6..244c06fb 100644 --- a/qml/StatusTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -115,10 +115,12 @@ Item { IconSVG { id: status_icon visible: !(currentRow.currentId === "all" && currentRow.currentKind === "INVALID") + && currentRow.currentStatus != "OK" anchors.left: parent.left; anchors.leftMargin: -5 anchors.verticalCenter: parent.verticalCenter - name: currentRow.currentStatus ? "error" :"issues" - color: currentRow.currentAlive ? currentRow.currentStatus ? "red" :"black" : "grey" + name: currentRow.currentStatus == "ERROR" ? "error" + : currentRow.currentStatus == "WARNING" ? "issues" : "" + color: currentRow.currentAlive ? currentRow.currentStatus == "ERROR" ? "red" :"black" : "grey" size: 15 } diff --git a/src/Engine.cpp b/src/Engine.cpp index 05d1182e..dbf04a64 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -997,7 +997,7 @@ bool Engine::update_entity_status( if (id == backend::ID_ALL) { auto empty_item = new models::StatusTreeItem(backend::ID_ALL, - std::string("No issues found"), false, std::string("")); + std::string("No issues found"), backend::StatusLevel::OK, std::string("")); entity_status_model_->addTopLevelItem(empty_item); } else @@ -1015,22 +1015,19 @@ bool Engine::update_entity_status( { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; std::string handle_string; auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), - sample.status == backend::StatusLevel::ERROR, std::string(""), description); + sample.status, std::string(""), description); auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.deadline_missed_status.total_count()), std::string("")); + sample.status, std::to_string(sample.deadline_missed_status.total_count()), std::string("")); for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) { handle_string = handle_string + std::to_string(handler); } auto last_instance_handle_item = new models::StatusTreeItem(id, kind, - std::string("Last instance handle:"), - sample.status == backend::StatusLevel::ERROR, handle_string, std::string("")); + std::string("Last instance handle:"), sample.status, handle_string, std::string("")); entity_status_model_->addItem(deadline_missed_item, total_count_item); entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); entity_status_model_->addItem(entity_item, deadline_missed_item); @@ -1047,18 +1044,17 @@ bool Engine::update_entity_status( std::string fastdds_version = "v2.12.0"; backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), - sample.status == backend::StatusLevel::ERROR, std::string(""), description); + sample.status, std::string(""), description); for (eprosima::fastdds::statistics::QosPolicyCount_s policy : sample.incompatible_qos_status.policies()) { if (policy.count() > 0) { auto policy_item = new models::StatusTreeItem(id, kind, std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), - sample.status == backend::StatusLevel::ERROR, std::to_string(policy.count()), + sample.status, std::to_string(policy.count()), std::string("Check for compatible rules ") + std::string("getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; auto inconsistent_topic_item = new models::StatusTreeItem(id, kind, std::string("Inconsistent topics:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.inconsistent_topic_status.total_count()), description); + sample.status, std::to_string(sample.inconsistent_topic_status.total_count()), description); entity_status_model_->addItem(entity_item, inconsistent_topic_item); counter = entity_item->recalculate_entity_counter(); } @@ -1099,25 +1093,21 @@ bool Engine::update_entity_status( { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; auto liveliness_changed_item = new models::StatusTreeItem(id, kind, std::string("Liveliness changed"), - sample.status == backend::StatusLevel::ERROR, std::string(""), description); + sample.status, std::string(""), description); std::string handle_string; auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); + sample.status, std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); + sample.status, std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) { handle_string = handle_string + std::to_string(handler); } auto last_publication_handle_item = new models::StatusTreeItem(id, kind, - std::string("Last publication handle:"), - sample.status == backend::StatusLevel::ERROR, handle_string, std::string("")); + std::string("Last publication handle:"), sample.status, handle_string, std::string("")); entity_status_model_->addItem(liveliness_changed_item, alive_count_item); entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); @@ -1135,12 +1125,10 @@ bool Engine::update_entity_status( { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.liveliness_lost_status.total_count()), description); + sample.status, std::to_string(sample.liveliness_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, liveliness_lost_item); counter = entity_item->recalculate_entity_counter(); } @@ -1154,12 +1142,10 @@ bool Engine::update_entity_status( { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), - entity_status == backend::StatusLevel::ERROR, description); + id, backend_connection_.get_name(id), entity_status, description); new_status = sample.status; auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), - sample.status == backend::StatusLevel::ERROR, - std::to_string(sample.sample_lost_status.total_count()), description); + sample.status, std::to_string(sample.sample_lost_status.total_count()), description); entity_status_model_->addItem(entity_item, samples_lost_item); counter = entity_item->recalculate_entity_counter(); } @@ -1241,12 +1227,13 @@ bool Engine::remove_inactive_entities_from_status_model( if (!entity_info["alive"]) { // remove item from tree - entity_status_model_->removeItem(entity_status_model_->getTopLevelItem(id, "", false, "")); + entity_status_model_->removeItem(entity_status_model_->getTopLevelItem(id, "", backend::StatusLevel::OK, "")); // add empty item if removed last item if (entity_status_model_->rowCount(entity_status_model_->rootIndex()) == 0) { - entity_status_model_->addTopLevelItem(new models::StatusTreeItem(backend::ID_ALL, std::string("No issues found"), false, std::string(""))); + entity_status_model_->addTopLevelItem(new models::StatusTreeItem( + backend::ID_ALL, std::string("No issues found"), backend::StatusLevel::OK, std::string(""))); } // update error counter diff --git a/src/backend/backend_utils.cpp b/src/backend/backend_utils.cpp index 27c1982c..7c830b2d 100644 --- a/src/backend/backend_utils.cpp +++ b/src/backend/backend_utils.cpp @@ -152,6 +152,21 @@ std::string status_kind_to_string( } } +std::string status_level_to_string( + const StatusLevel& status_level) +{ + switch (status_level) + { + case StatusLevel::WARNING: + return "WARNING"; + case StatusLevel::ERROR: + return "ERROR"; + case StatusLevel::OK: + default: + return "OK"; + } +} + std::string data_kind_to_string( const DataKind& data_kind) { diff --git a/src/model/tree/StatusTreeItem.cpp b/src/model/tree/StatusTreeItem.cpp index 73826b08..95ab319f 100644 --- a/src/model/tree/StatusTreeItem.cpp +++ b/src/model/tree/StatusTreeItem.cpp @@ -53,14 +53,14 @@ StatusTreeItem::StatusTreeItem() , id_(backend::ID_ALL) , kind_(backend::StatusKind::INVALID) , name_() - , is_status_error_(false) + , status_level_(backend::StatusLevel::OK) , value_() , description_() , is_active_(true) , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) , name_variant_(QVariant()) - , is_status_error_variant_(QVariant(false)) + , status_level_variant_(QVariant(QString::fromStdString(backend::status_level_to_string(status_level_)))) , value_variant_(QVariant()) , description_variant_(QVariant()) , is_active_variant_(QVariant(true)) @@ -73,14 +73,14 @@ StatusTreeItem::StatusTreeItem( , id_(backend::ID_ALL) , kind_(backend::StatusKind::INVALID) , name_(data.toString().toStdString()) - , is_status_error_(false) + , status_level_(backend::StatusLevel::OK) , value_() , description_() , is_active_(true) , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) , name_variant_(QVariant(QString::fromStdString(name_))) - , is_status_error_variant_(QVariant(false)) + , status_level_variant_(QVariant(QString::fromStdString(backend::status_level_to_string(status_level_)))) , value_variant_(QVariant()) , description_variant_(QVariant()) , is_active_variant_(QVariant(true)) @@ -90,20 +90,20 @@ StatusTreeItem::StatusTreeItem( StatusTreeItem::StatusTreeItem( const backend::EntityId& id, const std::string& name, - const bool& is_error, + const backend::StatusLevel& status_level, const std::string& description) : parent_item_(nullptr) , id_(id) , kind_(backend::StatusKind::INVALID) , name_(name) - , is_status_error_(is_error) + , status_level_(status_level) , value_() , description_(description) , is_active_(true) , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) , name_variant_(QVariant(QString::fromStdString(name))) - , is_status_error_variant_(QVariant(is_error)) + , status_level_variant_(QVariant(QString::fromStdString(backend::status_level_to_string(status_level_)))) , value_variant_(QVariant()) , description_variant_(QVariant(QString::fromStdString(description))) , is_active_variant_(QVariant(true)) @@ -114,21 +114,21 @@ StatusTreeItem::StatusTreeItem( const backend::EntityId& id, const backend::StatusKind& kind, const std::string& name, - const bool& is_error, + const backend::StatusLevel& status_level, const std::string& value, const std::string& description) : parent_item_(nullptr) , id_(id) , kind_(kind) , name_(name) - , is_status_error_(is_error) + , status_level_(status_level) , value_(value) , description_(description) , is_active_(true) , id_variant_(QVariant(backend::backend_id_to_models_id(id_))) , kind_variant_(QVariant(QString::fromStdString(backend::status_kind_to_string(kind_)))) , name_variant_(QVariant(QString::fromStdString(name_))) - , is_status_error_variant_(QVariant(is_error)) + , status_level_variant_(QVariant(QString::fromStdString(backend::status_level_to_string(status_level_)))) , value_variant_(QVariant(QString::fromStdString(value))) , description_variant_(QVariant(QString::fromStdString(description))) , is_active_variant_(QVariant(true)) @@ -198,7 +198,7 @@ const QVariant& StatusTreeItem::name() const const QVariant& StatusTreeItem::status() const { - return is_status_error_variant_; + return status_level_variant_; } const QVariant& StatusTreeItem::value() const @@ -260,16 +260,16 @@ backend::StatusKind StatusTreeItem::kind() return kind_; } -bool StatusTreeItem::is_error() +backend::StatusLevel StatusTreeItem::status_level() { - return is_status_error_; + return status_level_; } -void StatusTreeItem::is_error( - bool val) +void StatusTreeItem::status_level( + backend::StatusLevel val) { - is_status_error_ = val; - is_status_error_variant_ = QVariant(val); + status_level_ = val; + status_level_variant_ = QVariant(QString::fromStdString(backend::status_level_to_string(status_level_))); } std::string StatusTreeItem::name_str() diff --git a/src/model/tree/StatusTreeModel.cpp b/src/model/tree/StatusTreeModel.cpp index 2d8c3667..535d7e8d 100644 --- a/src/model/tree/StatusTreeModel.cpp +++ b/src/model/tree/StatusTreeModel.cpp @@ -108,7 +108,7 @@ StatusTreeItem* StatusTreeModel::filtered_copy( source->id(), source->kind(), source->name_str(), - source->is_error(), + source->status_level(), source->value_str(), source->description_str()); for (int i = 0; i < source->childCount(); i++) @@ -506,7 +506,7 @@ void StatusTreeModel::removeEmptyItem() StatusTreeItem* StatusTreeModel::getTopLevelItem( const backend::EntityId& id, const std::string& data, - const bool& is_error, + const backend::StatusLevel& status, const std::string& description) { // For each entity item in the three (root) @@ -520,7 +520,7 @@ StatusTreeItem* StatusTreeModel::getTopLevelItem( } // if not existing, create new topLevelItem - StatusTreeItem* new_entity_item = new StatusTreeItem(id, data, is_error, description); + StatusTreeItem* new_entity_item = new StatusTreeItem(id, data, status, description); addTopLevelItem(new_entity_item); return new_entity_item; } From 82f82ffb51b435c9082f179aee5eb101c5c94d0f Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 14 Nov 2023 12:00:46 +0100 Subject: [PATCH 35/43] Refs #19743: [ALRS] Comment typo Signed-off-by: JesusPoderoso --- qml/GraphConnection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index ee2f2151..b52b4fe6 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -30,7 +30,7 @@ Item { color: "white" } - //background to make connection overlap nicely left panel + // background to make connection overlap nicely left panel Rectangle { id: left_background anchors.top: parent.top; anchors.bottom: parent.bottom From ea8c0d2fd01dc860ddc7ee4c61c9357be76ebbdd Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 08:42:11 +0100 Subject: [PATCH 36/43] Refs #19743: [ARS] Improve entity info update when new status reported Signed-off-by: JesusPoderoso --- .../fastdds_monitor/backend/SyncBackendConnection.h | 4 ++++ src/Engine.cpp | 13 ++++++++++--- src/backend/SyncBackendConnection.cpp | 6 ++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/fastdds_monitor/backend/SyncBackendConnection.h b/include/fastdds_monitor/backend/SyncBackendConnection.h index d7e82fae..9dd4b5b0 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 alias of an entity from the Backend by calling \c get_info + std::string get_alias( + backend::EntityId id); + //! Get the status level of an entity from the Backend by calling \c get_status StatusLevel get_status( backend::EntityId id); diff --git a/src/Engine.cpp b/src/Engine.cpp index dbf04a64..60b99be9 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -982,10 +982,17 @@ bool Engine::read_callback_( + backend::status_kind_to_string(status_callback.status_kind), utils::now()); - // update left panel - update_entity_generic(status_callback.entity_id, backend_connection_.get_type(status_callback.entity_id) , true, false); + // Update status in info model + if (last_entities_clicked_.dds.id == status_callback.entity_id) + { + info_model_->update_selected_entity(backend::backend_id_to_models_id( + status_callback.entity_id), utils::to_QString(backend_connection_.get_alias(status_callback.entity_id))); + } + + // Remove entities from status layout if needed + remove_inactive_entities_from_status_model(status_callback.entity_id); - // update model + // update status model return update_entity_status(status_callback.entity_id, status_callback.status_kind); } diff --git a/src/backend/SyncBackendConnection.cpp b/src/backend/SyncBackendConnection.cpp index 6d6f2847..9066b42a 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"); } +std::string SyncBackendConnection::get_alias( + EntityId id) +{ + return backend::get_info_value(get_info(id), "alias"); +} + StatusLevel SyncBackendConnection:: get_status( EntityId id) { From 94d1e49720649e765adff881f441ef5139e82d70 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 08:47:07 +0100 Subject: [PATCH 37/43] Refs #19743: [ARS] Remove unnecessary error check Signed-off-by: JesusPoderoso --- src/Engine.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 60b99be9..f3675396 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1176,10 +1176,6 @@ bool Engine::update_entity_status( if(it != controller_->status_counters.errors.end()) { controller_->status_counters.total_errors -= controller_->status_counters.errors[id]; - if (controller_->status_counters.total_errors < 0) - { - controller_->status_counters.total_errors = 0; - } } controller_->status_counters.errors[id] = counter; controller_->status_counters.total_errors += controller_->status_counters.errors[id]; @@ -1190,10 +1186,6 @@ bool Engine::update_entity_status( if(it != controller_->status_counters.warnings.end()) { controller_->status_counters.total_warnings -= controller_->status_counters.warnings[id]; - if (controller_->status_counters.total_warnings < 0) - { - controller_->status_counters.total_warnings = 0; - } } controller_->status_counters.warnings[id] = counter; controller_->status_counters.total_warnings += controller_->status_counters.warnings[id]; From a096479b8dffa582320d1d37099ced4ec0e79acc Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 08:54:12 +0100 Subject: [PATCH 38/43] Refs #19743: [ARS] Get Status Level string from sources (backend) Signed-off-by: JesusPoderoso --- src/backend/backend_utils.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/backend/backend_utils.cpp b/src/backend/backend_utils.cpp index 7c830b2d..b5c7c51d 100644 --- a/src/backend/backend_utils.cpp +++ b/src/backend/backend_utils.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -155,16 +156,7 @@ std::string status_kind_to_string( std::string status_level_to_string( const StatusLevel& status_level) { - switch (status_level) - { - case StatusLevel::WARNING: - return "WARNING"; - case StatusLevel::ERROR: - return "ERROR"; - case StatusLevel::OK: - default: - return "OK"; - } + return eprosima::statistics_backend::status_level_str[(int)status_level]; } std::string data_kind_to_string( From a292074baeb3707fafd34b5f36d6b66da4222ed3 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 09:00:08 +0100 Subject: [PATCH 39/43] Refs #19743: [ARS] Fix visual bug with expand/collapse status layout icon Signed-off-by: JesusPoderoso --- qml/StatusLayout.qml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qml/StatusLayout.qml b/qml/StatusLayout.qml index b65b7f24..beca6d9f 100644 --- a/qml/StatusLayout.qml +++ b/qml/StatusLayout.qml @@ -164,7 +164,8 @@ Item IconSVG { id: expand_icon - name: "expand" + name: statusLayout.current_status === StatusLayout.Status.Expanded + ? "collapse" : "expand" size: parent.width } @@ -177,13 +178,11 @@ Item if (statusLayout.current_status === StatusLayout.Status.Expanded) { collapse_status_layout() - expand_icon.name = "expand" } else if (statusLayout.current_status === StatusLayout.Status.Collapsed) { expand_status_layout() - expand_icon.name = "collapse" } } } @@ -278,7 +277,7 @@ Item IconSVG { id: warning_icon anchors.left: error_value.right - anchors.leftMargin: elements_spacing_ + anchors.leftMargin: elements_spacing_ anchors.verticalCenter: parent.verticalCenter name: "issues" size: parent.height - elements_spacing_ From 83f858ae7a06dd427e0a5bfd3b8074ff0b8ecf17 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 09:11:32 +0100 Subject: [PATCH 40/43] Refs #19743: [ARS] Fix timer flow Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index d48cbe94..0c3de6a8 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -70,6 +70,7 @@ Item readonly property int scrollbar_max_size_: 12 readonly property int topic_thickness_: 10 readonly property int wheel_displacement_: 30 + readonly property int timer_initial_ms_interval_: 200 readonly property string topic_color_: Theme.grey readonly property string host_color_: Theme.darkGrey readonly property string user_color_: Theme.eProsimaLightBlue @@ -1302,9 +1303,19 @@ Item Timer { id: safety_timer - interval: 200; running: false - onTriggered: { interval += interval; load_model() } - } function stop_timer() { safety_timer.stop() } + interval: timer_initial_ms_interval_; running: false + onTriggered: { + interval += interval + load_model() + } + } + function stop_timer() { + if (safety_timer.running) + { + safety_timer.stop() + safety_timer.interval = timer_initial_ms_interval_ + } + } // Obtain given domain id graph JSON model function load_model() From dbbd7ef37d12e3d82083f91e0a870da053d9b2d6 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 10:51:07 +0100 Subject: [PATCH 41/43] Refs #19743: [ARS] Add try-catch in get_status_data Signed-off-by: JesusPoderoso --- .../backend/SyncBackendConnection.h | 18 +- src/Engine.cpp | 200 ++++++++++-------- src/backend/SyncBackendConnection.cpp | 136 ++++++++++-- 3 files changed, 235 insertions(+), 119 deletions(-) diff --git a/include/fastdds_monitor/backend/SyncBackendConnection.h b/include/fastdds_monitor/backend/SyncBackendConnection.h index 9dd4b5b0..4b2e479a 100644 --- a/include/fastdds_monitor/backend/SyncBackendConnection.h +++ b/include/fastdds_monitor/backend/SyncBackendConnection.h @@ -156,39 +156,39 @@ class SyncBackendConnection Timestamp start_time = Timestamp(), Timestamp end_time = std::chrono::system_clock::now()); - void get_status_data( + bool get_status_data( EntityId source_entity_id, ConnectionListSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, DeadlineMissedSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, IncompatibleQosSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, InconsistentTopicSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, LivelinessChangedSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, LivelinessLostSample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, ProxySample& sample); - void get_status_data( + bool get_status_data( EntityId source_entity_id, SampleLostSample& sample); - /*void get_status_data( + /*bool get_status_data( EntityId source_entity_id, StatusesSizeSample& sample);*/ diff --git a/src/Engine.cpp b/src/Engine.cpp index f3675396..bc341015 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1017,144 +1017,156 @@ bool Engine::update_entity_status( case backend::StatusKind::DEADLINE_MISSED: { backend::DeadlineMissedSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - std::string handle_string; - auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), - sample.status, std::string(""), description); - auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), - sample.status, std::to_string(sample.deadline_missed_status.total_count()), std::string("")); - for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) + if (sample.status != backend::StatusLevel::OK) { - handle_string = handle_string + std::to_string(handler); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + std::string handle_string; + auto deadline_missed_item = new models::StatusTreeItem(id, kind, std::string("Deadline missed"), + sample.status, std::string(""), description); + auto total_count_item = new models::StatusTreeItem(id, kind, std::string("Total count:"), + sample.status, std::to_string(sample.deadline_missed_status.total_count()), std::string("")); + for (uint8_t handler : sample.deadline_missed_status.last_instance_handle()) + { + handle_string = handle_string + std::to_string(handler); + } + auto last_instance_handle_item = new models::StatusTreeItem(id, kind, + std::string("Last instance handle:"), sample.status, handle_string, std::string("")); + entity_status_model_->addItem(deadline_missed_item, total_count_item); + entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); + entity_status_model_->addItem(entity_item, deadline_missed_item); + counter = entity_item->recalculate_entity_counter(); } - auto last_instance_handle_item = new models::StatusTreeItem(id, kind, - std::string("Last instance handle:"), sample.status, handle_string, std::string("")); - entity_status_model_->addItem(deadline_missed_item, total_count_item); - entity_status_model_->addItem(deadline_missed_item, last_instance_handle_item); - entity_status_model_->addItem(entity_item, deadline_missed_item); - counter = entity_item->recalculate_entity_counter(); } break; } case backend::StatusKind::INCOMPATIBLE_QOS: { backend::IncompatibleQosSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - std::string fastdds_version = "v2.12.0"; - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), - sample.status, std::string(""), description); - for (eprosima::fastdds::statistics::QosPolicyCount_s policy : sample.incompatible_qos_status.policies()) + if (sample.status != backend::StatusLevel::OK) { - if (policy.count() > 0) + std::string fastdds_version = "v2.12.0"; + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + auto incompatible_qos_item = new models::StatusTreeItem(id, kind, std::string("Incompatible QoS"), + sample.status, std::string(""), description); + for (eprosima::fastdds::statistics::QosPolicyCount_s policy : sample.incompatible_qos_status.policies()) { - auto policy_item = new models::StatusTreeItem(id, kind, - std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), - sample.status, std::to_string(policy.count()), - std::string("Check for compatible rules ") + - std::string("here")); - entity_status_model_->addItem(incompatible_qos_item, policy_item); + if (policy.count() > 0) + { + auto policy_item = new models::StatusTreeItem(id, kind, + std::string(backend::policy_id_to_string(policy.policy_id()) + ":"), + sample.status, std::to_string(policy.count()), + std::string("Check for compatible rules ") + + std::string("here")); + entity_status_model_->addItem(incompatible_qos_item, policy_item); + } } + entity_status_model_->addItem(entity_item, incompatible_qos_item); + counter = entity_item->recalculate_entity_counter(); } - entity_status_model_->addItem(entity_item, incompatible_qos_item); - counter = entity_item->recalculate_entity_counter(); } break; } case backend::StatusKind::INCONSISTENT_TOPIC: { backend::InconsistentTopicSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - auto inconsistent_topic_item = new models::StatusTreeItem(id, kind, std::string("Inconsistent topics:"), - sample.status, std::to_string(sample.inconsistent_topic_status.total_count()), description); - entity_status_model_->addItem(entity_item, inconsistent_topic_item); - counter = entity_item->recalculate_entity_counter(); + if (sample.status != backend::StatusLevel::OK) + { + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + auto inconsistent_topic_item = new models::StatusTreeItem(id, kind, std::string("Inconsistent topics:"), + sample.status, std::to_string(sample.inconsistent_topic_status.total_count()), description); + entity_status_model_->addItem(entity_item, inconsistent_topic_item); + counter = entity_item->recalculate_entity_counter(); + } } break; } case backend::StatusKind::LIVELINESS_CHANGED: { backend::LivelinessChangedSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - auto liveliness_changed_item = new models::StatusTreeItem(id, kind, std::string("Liveliness changed"), - sample.status, std::string(""), description); - std::string handle_string; - auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), - sample.status, std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); - auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), - sample.status, std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); - for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) + if (sample.status != backend::StatusLevel::OK) { - handle_string = handle_string + std::to_string(handler); + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + auto liveliness_changed_item = new models::StatusTreeItem(id, kind, std::string("Liveliness changed"), + sample.status, std::string(""), description); + std::string handle_string; + auto alive_count_item = new models::StatusTreeItem(id, kind, std::string("Alive count:"), + sample.status, std::to_string(sample.liveliness_changed_status.alive_count()), std::string("")); + auto not_alive_count_item = new models::StatusTreeItem(id, kind, std::string("Not alive count:"), + sample.status, std::to_string(sample.liveliness_changed_status.not_alive_count()), std::string("")); + for (uint8_t handler : sample.liveliness_changed_status.last_publication_handle()) + { + handle_string = handle_string + std::to_string(handler); + } + auto last_publication_handle_item = new models::StatusTreeItem(id, kind, + std::string("Last publication handle:"), sample.status, handle_string, std::string("")); + + entity_status_model_->addItem(liveliness_changed_item, alive_count_item); + entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); + entity_status_model_->addItem(liveliness_changed_item, last_publication_handle_item); + entity_status_model_->addItem(entity_item, liveliness_changed_item); + counter = entity_item->recalculate_entity_counter(); } - auto last_publication_handle_item = new models::StatusTreeItem(id, kind, - std::string("Last publication handle:"), sample.status, handle_string, std::string("")); - - entity_status_model_->addItem(liveliness_changed_item, alive_count_item); - entity_status_model_->addItem(liveliness_changed_item, not_alive_count_item); - entity_status_model_->addItem(liveliness_changed_item, last_publication_handle_item); - entity_status_model_->addItem(entity_item, liveliness_changed_item); - counter = entity_item->recalculate_entity_counter(); } break; } case backend::StatusKind::LIVELINESS_LOST: { backend::LivelinessLostSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), - sample.status, std::to_string(sample.liveliness_lost_status.total_count()), description); - entity_status_model_->addItem(entity_item, liveliness_lost_item); - counter = entity_item->recalculate_entity_counter(); + if (sample.status != backend::StatusLevel::OK) + { + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + auto liveliness_lost_item = new models::StatusTreeItem(id, kind, std::string("Liveliness lost:"), + sample.status, std::to_string(sample.liveliness_lost_status.total_count()), description); + entity_status_model_->addItem(entity_item, liveliness_lost_item); + counter = entity_item->recalculate_entity_counter(); + } } break; } case backend::StatusKind::SAMPLE_LOST: { backend::SampleLostSample sample; - backend_connection_.get_status_data(id, sample); - if (sample.status != backend::StatusLevel::OK) + if (backend_connection_.get_status_data(id, sample)) { - backend::StatusLevel entity_status = backend_connection_.get_status(id); - auto entity_item = entity_status_model_->getTopLevelItem( - id, backend_connection_.get_name(id), entity_status, description); - new_status = sample.status; - auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), - sample.status, std::to_string(sample.sample_lost_status.total_count()), description); - entity_status_model_->addItem(entity_item, samples_lost_item); - counter = entity_item->recalculate_entity_counter(); + if (sample.status != backend::StatusLevel::OK) + { + backend::StatusLevel entity_status = backend_connection_.get_status(id); + auto entity_item = entity_status_model_->getTopLevelItem( + id, backend_connection_.get_name(id), entity_status, description); + new_status = sample.status; + auto samples_lost_item = new models::StatusTreeItem(id, kind, std::string("Samples lost:"), + sample.status, std::to_string(sample.sample_lost_status.total_count()), description); + entity_status_model_->addItem(entity_item, samples_lost_item); + counter = entity_item->recalculate_entity_counter(); + } } break; } diff --git a/src/backend/SyncBackendConnection.cpp b/src/backend/SyncBackendConnection.cpp index 9066b42a..83aec3ae 100644 --- a/src/backend/SyncBackendConnection.cpp +++ b/src/backend/SyncBackendConnection.cpp @@ -730,60 +730,164 @@ bool SyncBackendConnection::data_available( return !data.empty(); } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, ConnectionListSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, DeadlineMissedSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, IncompatibleQosSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, InconsistentTopicSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, LivelinessChangedSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, LivelinessLostSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, ProxySample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } -void SyncBackendConnection::get_status_data( +bool SyncBackendConnection::get_status_data( EntityId id, SampleLostSample& sample) { - StatisticsBackend::get_status_data(id, sample); + try + { + StatisticsBackend::get_status_data(id, sample); + return true; + } + catch (const Error& e) + { + qWarning() << "Error retrieving sample: " << e.what(); + } + catch (const BadParameter& e) + { + qWarning() << "Bad Parameter retrieving sample " << e.what(); + } + return false; } From 69acbc9949b53cf22a397d87fc029a68c1264b4d Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 11:08:57 +0100 Subject: [PATCH 42/43] Refs #19743: [ARS] Fix timer Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 0c3de6a8..0797f116 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -1560,6 +1560,9 @@ Item "hosts": [], } + // disable recovery timer + stop_timer(); + // display empty screen label emptyScreenLabel.visible = true } From 3ace55c46fc266c9a00e765e8d9f0f28d94aeaad Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 Nov 2023 12:21:41 +0100 Subject: [PATCH 43/43] Refs #19743: [ARS] Fix left panel focus Signed-off-by: JesusPoderoso --- src/Engine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index bc341015..22de100d 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -985,8 +985,7 @@ bool Engine::read_callback_( // Update status in info model if (last_entities_clicked_.dds.id == status_callback.entity_id) { - info_model_->update_selected_entity(backend::backend_id_to_models_id( - status_callback.entity_id), utils::to_QString(backend_connection_.get_alias(status_callback.entity_id))); + info_model_->update(backend_connection_.get_info(status_callback.entity_id)); } // Remove entities from status layout if needed