From 5f24f1539d83d2cdfdd8e2f84fe5bf66ce1eba17 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 22 Nov 2023 09:43:56 +0100 Subject: [PATCH 01/10] Refs #19973: Fix topic lines below entities visual bug Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 0797f116..812dc7ba 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -79,6 +79,7 @@ Item readonly property string reader_color_: Theme.eProsimaYellow readonly property string writer_color_: Theme.eProsimaGreen + // Horizontal scroll view for topics section. This will contain also a Flickable that replicates entities height // and will move accordingly to display the connections Flickable { @@ -354,6 +355,15 @@ Item } } + // Left section background (over right section) + Rectangle { + anchors.top: parent.top + anchors.left: parent.left + height: parent.height + width: entity_box_width_ + 2*elements_spacing_ + color: "white" + } + // Entities vertical flickable (left section) Flickable { id: mainView @@ -1253,7 +1263,7 @@ Item } } - // top section to cut entities layout and display the REFRESH butotn + // top section to cut entities layout and display the REFRESH button Rectangle { anchors.top: parent.top anchors.left: parent.left From 5e85585a5fdc6ed15310fc4c69dfabe651bae531 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 22 Nov 2023 10:49:34 +0100 Subject: [PATCH 02/10] Refs #19973: Update Warning Icon to be more visible Signed-off-by: JesusPoderoso --- qml.qrc | 1 + qml/DomainGraphLayout.qml | 17 ++++++++++++----- qml/StatusTreeViewItem.qml | 2 +- resources/images/icons/issues/issues_yellow.svg | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 resources/images/icons/issues/issues_yellow.svg diff --git a/qml.qrc b/qml.qrc index 8eb72d0b..8c046d53 100644 --- a/qml.qrc +++ b/qml.qrc @@ -163,6 +163,7 @@ resources/images/icons/issues/issues_eProsimaLightBlue.svg resources/images/icons/issues/issues_grey.svg resources/images/icons/issues/issues_white.svg + resources/images/icons/issues/issues_yellow.svg resources/images/icons/lessthan/lessthan_black.svg resources/images/icons/lessthan/lessthan_eProsimaLightBlue.svg resources/images/icons/lessthan/lessthan_grey.svg diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 812dc7ba..9af7c80a 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -562,7 +562,7 @@ Item IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "black" : "red" + color: modelData["status"] == "WARNING" ? "yellow" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -706,7 +706,7 @@ Item IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "black" : "red" + color: modelData["status"] == "WARNING" ? "yellow" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -849,7 +849,7 @@ Item IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "black" : "red" + color: modelData["status"] == "WARNING" ? "yellow" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -992,7 +992,7 @@ Item IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "black" : "red" + color: modelData["status"] == "WARNING" ? "yellow" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } @@ -1185,10 +1185,17 @@ Item 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 { + visible: modelData["status"] == "WARNING" + anchors.centerIn: parent + name: "issues" + color: "white" + size: icon_size_ * (3/2) + } IconSVG { anchors.centerIn: parent name: modelData["status"] == "WARNING" ? "issues" : "error" - color: modelData["status"] == "WARNING" ? "black" : "red" + color: modelData["status"] == "WARNING" ? "yellow" : "red" size: modelData["status"] != "OK"? icon_size_ : 0 } } diff --git a/qml/StatusTreeViewItem.qml b/qml/StatusTreeViewItem.qml index 244c06fb..b9b6c683 100644 --- a/qml/StatusTreeViewItem.qml +++ b/qml/StatusTreeViewItem.qml @@ -120,7 +120,7 @@ Item { anchors.verticalCenter: parent.verticalCenter name: currentRow.currentStatus == "ERROR" ? "error" : currentRow.currentStatus == "WARNING" ? "issues" : "" - color: currentRow.currentAlive ? currentRow.currentStatus == "ERROR" ? "red" :"black" : "grey" + color: currentRow.currentAlive ? currentRow.currentStatus == "ERROR" ? "red" :"yellow" : "grey" size: 15 } diff --git a/resources/images/icons/issues/issues_yellow.svg b/resources/images/icons/issues/issues_yellow.svg new file mode 100644 index 00000000..5e099d44 --- /dev/null +++ b/resources/images/icons/issues/issues_yellow.svg @@ -0,0 +1,14 @@ + + + + + + + +Layer 1 + + + + + + \ No newline at end of file From 53e94144bc9359b5ca858781273095b391b7de55 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 22 Nov 2023 10:56:29 +0100 Subject: [PATCH 03/10] Refs #19973: Remove info panel refresh call when new status is reported Signed-off-by: JesusPoderoso --- src/Engine.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 22de100d..2216f38c 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -982,12 +982,6 @@ bool Engine::read_callback_( + backend::status_kind_to_string(status_callback.status_kind), utils::now()); - // Update status in info model - if (last_entities_clicked_.dds.id == status_callback.entity_id) - { - info_model_->update(backend_connection_.get_info(status_callback.entity_id)); - } - // Remove entities from status layout if needed remove_inactive_entities_from_status_model(status_callback.entity_id); From 8a96a165022aaaf57aa318d536d050a19c8ce096 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 22 Nov 2023 14:00:24 +0100 Subject: [PATCH 04/10] Refs #19973: Improve arrows when related topic is not displayed Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 45 ++++++++++++++++++++++++-- qml/GraphConnection.qml | 66 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 9af7c80a..768de88d 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -44,6 +44,7 @@ Item 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 var filtered_topics_: [] // flitered topic entity id in the graph + property var endpoints_per_topic: {} // list of endpoint ids associated to each topic property int entity_box_width_: 0 // entity box width management // Private (resize) signals The signal resize_elements_ will trigger all entities resize methods in @@ -54,6 +55,7 @@ Item signal topics_updated_() signal endpoints_updated_() signal record_connections_() + signal topic_visibility_changed_(string endpoint_id, bool new_status) // Read only design properties (sizes and colors) readonly property int radius_: 10 @@ -257,6 +259,15 @@ Item width: topic_thickness_ color: topic_color_ } + + Connections { + target: topicView + function onContentXChanged() + { + domainGraphLayout.topic_visibility_changed( + topic_id, ((x + width/2 + topic_thickness_/2 + elements_spacing_) < topicView.contentX)) + } + } } } @@ -346,7 +357,8 @@ Item ,"y": endpoint_topic_connections_[key]["y"] - (connection_thickness_ / 2) ,"width": topic_locations_[topic_id]["width"] ,"height":connection_thickness_, "z":200, "left_margin": 2*elements_spacing_ - ,"arrow_color": topic_color_, "background_color": background_color.color } + ,"arrow_color": topic_color_, "background_color": background_color.color + ,"endpoint_id": key } var connection_bar = arrow_component.createObject(topic_connections, input) topic_painted_[topic_painted_.length] = key; } @@ -436,7 +448,16 @@ Item Component { id: arrow_component GraphConnection{ + id: conn + + Connections{ + target: domainGraphLayout + function onTopic_visibility_changed_(endpoint_id, new_status) + { + conn.topid_hidden(endpoint_id, new_status) + } + } } } @@ -1260,7 +1281,8 @@ Item ,"left_direction": endpoint_topic_connections_[key]["left_direction"] ,"width": 5*elements_spacing_ ,"height":connection_thickness_, "z":200 - ,"arrow_color": topic_color_, "background_color": background_color.color } + ,"arrow_color": topic_color_, "background_color": background_color.color + ,"endpoint_id": key } var connection_bar = arrow_component.createObject(mainSpace, input) endpoint_painted_[endpoint_painted_.length] = key } @@ -1396,6 +1418,7 @@ Item "kind":"Topic", "alias":new_model["topics"][topic]["alias"] } + endpoints_per_topic[topic] = [] } } } @@ -1406,6 +1429,7 @@ Item "kind":"Topic", "alias":new_model["topics"][topic]["alias"] } + endpoints_per_topic[topic] = [] } } } @@ -1460,14 +1484,16 @@ Item { kind = "DataReader" } + var endpoint_topic = new_model["hosts"][host]["users"][user]["processes"][process]["participants"][participant]["endpoints"][endpoint]["topic"] 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"], + "topic": endpoint_topic, "accum_y":accum_y } + endpoints_per_topic[endpoint_topic][endpoints_per_topic[endpoint_topic].length] = endpoint accum_y += endpoint_height_ + elements_spacing_ pending_endpoints_[pending_endpoints_.length] = endpoint } @@ -1621,6 +1647,7 @@ Item topic_painted_ = [] pending_endpoints_ = [] pending_connections_ = [] + endpoints_per_topic = {} vertical_bar.position = 0 horizontal_bar.position = 0 entity_box_width_ = 0; @@ -1722,4 +1749,16 @@ Item // not found yet return false } + + // report to the graph connections that the endpoint associated topic is not currently in view + function topic_visibility_changed(topic_id, inView) + { + if (topic_id in endpoints_per_topic) + { + for (var i = 0; i < endpoints_per_topic[topic_id].length; i++) + { + domainGraphLayout.topic_visibility_changed_(endpoints_per_topic[topic_id][i], inView) + } + } + } } diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index b52b4fe6..832e1835 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -1,12 +1,15 @@ import QtQuick 2.0 Item { + id: graphConnection // 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 string endpoint_id: "" // graph refferred entity id + property bool hidden_arrow: false // associated topic is not visible // readonly private design properties readonly property int arrow_margin_: -3 // margins for background @@ -18,6 +21,7 @@ Item { 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 + readonly property int hidden_arrow_margin_: 2 // hidden arrow margin // background to make connection overlap nicely with previous topics (looks like connection goes OVER the topic) Rectangle { @@ -41,8 +45,6 @@ Item { color: "white" } - - // left arrow if visible Item { id: left_arrow_background @@ -70,7 +72,6 @@ Item { } } - Item { id: left_arrow visible: left_direction @@ -96,6 +97,57 @@ Item { color: arrow_color } + // hidden topic icon + Rectangle { + visible: graphConnection.hidden_arrow + anchors.verticalCenter: base_arrow.verticalCenter + anchors.left: base_arrow.right + height: graphConnection.height - 2* arrow_margin_; width: 3*graphConnection.height + hidden_arrow_margin_*4 + color: "white" + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.right; anchors.leftMargin: -parent.height/2 + height: parent.height; width: parent.height + radius: parent.height + color: "white" + } + + Rectangle { + id: spot_1 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left; anchors.leftMargin: hidden_arrow_margin_*2 + height: graphConnection.height; width: graphConnection.height + radius: graphConnection.height + color: arrow_color + } + Rectangle { + id: spot_2 + anchors.verticalCenter: parent.verticalCenter + anchors.left: spot_1.right; anchors.leftMargin: hidden_arrow_margin_ + height: graphConnection.height; width: graphConnection.height + radius: graphConnection.height + color: arrow_color + } + Rectangle { + id: spot_3 + anchors.verticalCenter: parent.verticalCenter + anchors.left: spot_2.right; anchors.leftMargin: hidden_arrow_margin_ + height: graphConnection.height; width: graphConnection.height + radius: graphConnection.height + color: arrow_color + } + + Rectangle { + id: spot_0 + anchors.verticalCenter: parent.verticalCenter + anchors.right: spot_1.left; anchors.rightMargin: hidden_arrow_margin_*2-graphConnection.height/2 + height: graphConnection.height; width: graphConnection.height + radius: graphConnection.height + color: arrow_color + } + } + // right arrow if visible Item { id: right_arrow @@ -111,4 +163,12 @@ Item { size: arrow_size_ + right_arrow_margin_ } } + + function topid_hidden(entityId, is_hidden) + { + if (endpoint_id == entityId && graphConnection.hidden_arrow != is_hidden) + { + graphConnection.hidden_arrow = is_hidden + } + } } From b574808283eef5959e7af78717a57c75e2346e6c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 22 Nov 2023 16:52:40 +0100 Subject: [PATCH 05/10] Refs #19973: Fix glitch when filtering domain graph per topic Signed-off-by: JesusPoderoso --- qml.qrc | 1 + qml/DomainGraphLayout.qml | 50 +++++++++++++----- qml/TabLayout.qml | 82 +++++++++++++++++++++++++++-- resources/images/loading_graph.gif | Bin 0 -> 85424 bytes 4 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 resources/images/loading_graph.gif diff --git a/qml.qrc b/qml.qrc index 8c046d53..c3b06d16 100644 --- a/qml.qrc +++ b/qml.qrc @@ -76,6 +76,7 @@ resources/images/graphs.svg resources/images/domain_graph.svg resources/images/topic_graph.svg + resources/images/loading_graph.gif resources/images/icons/clearissues/clearissues_black.svg diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 768de88d..19d95955 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -26,26 +26,30 @@ Item id: domainGraphLayout // Public properties - property var model: {} // domain view graph JSON model - 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 + property var model: {} // domain view graph JSON model + 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 // Public signals 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) + signal initialized() // let tab layout know that graph has been generated // Private properties - property var topic_locations_: {} // topic information needed for connection representation - property var endpoint_topic_connections_: {} // endpoint information needed for connection representation - property var topic_painted_: [] // already painted topic connection references - 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 var filtered_topics_: [] // flitered topic entity id in the graph - property var endpoints_per_topic: {} // list of endpoint ids associated to each topic - property int entity_box_width_: 0 // entity box width management + property var topic_locations_: {} // topic information needed for connection representation + property var endpoint_topic_connections_: {} // endpoint information needed for connection representation + property var topic_painted_: [] // already painted topic connection references + 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 var filtered_topics_: [] // flitered topic entity id in the graph + property var endpoints_per_topic: {} // list of endpoint ids associated to each topic + property int entity_box_width_: 0 // entity box width management + property bool topic_connections_generated: false // topic side connections generated + property bool endpoint_connections_generated: false // endpoint side connections generated + // 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 @@ -364,6 +368,9 @@ Item } } } + + topic_connections_generated = true + domainGraphLayout.connections_generated() } } @@ -1288,6 +1295,9 @@ Item } } } + + endpoint_connections_generated = true + domainGraphLayout.connections_generated() } } } @@ -1608,6 +1618,9 @@ Item // display empty screen label emptyScreenLabel.visible = true + + // stop animation + domainGraphLayout.initialized() } // Update tab name with selected domain id @@ -1761,4 +1774,15 @@ Item } } } + + // set the graph as initialized + function connections_generated() + { + if (domainGraphLayout.topic_connections_generated && domainGraphLayout.endpoint_connections_generated) + { + domainGraphLayout.topic_connections_generated = false + domainGraphLayout.endpoint_connections_generated = false + domainGraphLayout.initialized() + } + } } diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index be26a7d6..b6a93fbd 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -36,6 +36,7 @@ Item { property int last_index_: 1 // force unique idx on QML components property var tab_model_: [{"idx":0, "title":"New Tab", "stack_id": 0}] // tab model for tab bad and tab management property bool disable_chart_selection_: false // flag to disable multiple chart view tabs + readonly property var allowed_stack_components_: ["view_selector", "chartsLayout", "domainGraphLayout_component"] // private signals signal open_domain_view_(int stack_id, int entity_id, int domain_id) @@ -50,6 +51,9 @@ Item { readonly property int tabs_margins_: 15 readonly property int tab_icons_size_: 16 readonly property int add_tab_width_: 50 + readonly property int timer_ms_interval_: 500 + readonly property int dialog_width_: 300 + readonly property int dialog_height_: 120 readonly property string selected_tab_color_: "#ffffff" readonly property string selected_shadow_tab_color_: "#c0c0c0" readonly property string not_selected_tab_color_: "#f0f0f0" @@ -84,7 +88,9 @@ Item { StackView { id: stack property int stack_id: 0 - initialItem: view_selector + property string customInitialItem: "view_selector" + initialItem: customInitialItem == "chartsLayout" ? chartsLayout : + customInitialItem == "domainGraphLayout_component" ? domainGraphLayout_component : view_selector // override push transition to none pushEnter: Transition {} @@ -241,6 +247,10 @@ Item { tabLayout.openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) } + onInitialized: { + loading_graph_dialog.soft_close() + } + Connections { target: tabLayout @@ -261,7 +271,6 @@ Item { } } } - } } @@ -271,6 +280,7 @@ Item { function onOpen_domain_view_(stack_id, entity_id, domain_id, topic_id) { if (stack.stack_id == stack_id) { + loading_graph_dialog.open() if (stack.deep > 1) { stack.pop() @@ -426,7 +436,7 @@ Item { x: (parent.width - width) / 2 y: (parent.height - height) / 2 - width: 300 + width: dialog_width_ modal: true title: "Select DDS Domain" @@ -478,11 +488,73 @@ Item { } } + Dialog { + id: loading_graph_dialog + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + width: dialog_width_ + height: dialog_height_ + + modal: true + + AnimatedImage { + source: "/resources/images/loading_graph.gif" + anchors.centerIn: parent + width: dialog_width_ + height: dialog_height_ + } + + onAboutToShow: + { + timer.start() + } + + function soft_close() + { + if (timer.running) + { + timer.should_close = true + } + else + { + loading_graph_dialog.close() + } + } + + Timer + { + id: timer + property bool should_close: false + interval: timer_ms_interval_; running: false + onTriggered: + { + if (timer.should_close) + { + loading_graph_dialog.close() + timer.should_close = false + } + } + } + } + function create_new_tab() { + create_new_custom_tab_("") + } + + function create_new_custom_tab_(component_identifier) + { + var initial_component = component_identifier + if (!allowed_stack_components_.includes(component_identifier)) + { + initial_component = "view_selector"; + } var idx = tabLayout.tab_model_.length tabLayout.tab_model_[idx] = {"idx" : idx, "title": "New Tab", "stack_id":last_index_} - var new_stack = stack_component.createObject(null, {"stack_id": tabLayout.tab_model_[idx]["stack_id"]}) + var new_stack = stack_component.createObject(null, { + "stack_id": tabLayout.tab_model_[idx]["stack_id"], "customInitialItem": initial_component }) last_index_++ stack_layout.children.push(new_stack) refresh_layout(idx) @@ -626,7 +698,7 @@ Item { } function open_topic_view(domainEntityId, domainId, entityId) { - create_new_tab() + create_new_custom_tab_("domainGraphLayout_component") open_domain_view_(tabLayout.tab_model_[current_]["stack_id"], domainEntityId, domainId) filter_domain_view_by_topic_(tabLayout.tab_model_[current_]["stack_id"], domainEntityId, entityId) } diff --git a/resources/images/loading_graph.gif b/resources/images/loading_graph.gif new file mode 100644 index 0000000000000000000000000000000000000000..da702cd0fdd447d0412116f28a327811e6dfe264 GIT binary patch literal 85424 zcmV(|K+(TPNk%w1VE_aG0{8y_FE1}JFfcJOF)}hTGcz+ZG&D6eH8wUjH#avpI5;^u zIXXHzJUl!-Jv~1^KR`f0LPA1ALqkPHMMg$OOG`^yT3TXaVq;@tWMpJzWo2e&W@l$- zXlQ6@X=!R|YHMq2Y;0_8ZEbFDZgFvOa&mHWb8~cbbai!gc6N4qdwYC*e0_a=fPjF3 zfq{a8f`x^JhK7cTiHVAeija_yl$4Z}m6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZ zo}ZteprD|kp`oIpqNAguq@<*!rKP5(rl+T;sHmu^si~@}s;jH3tgNiAuCA}IuduMN zv9YnTva++Yv$V9dwY9ajwzjvox45{txw*Nzy1Ki&yS%)-zrVl2!otJD!^OqL#>U3S z$H&OX$jQmc%F4>i%gfBn%+1Zs&d$!y&(F}%(9zM+($dn?)6>+{)YaA1*4Eb7*VowC z*xA|H+S=ON+uPjS+}+*X-rnBd-{0Wi;Njun;^N}tgww2>+9_7?CtIC?(XjI@9*&N@bU5S^78WY^Yird^!4@i_V)Jo_xJet`1$$y`uh6& z`}_R-{Qdp?{{H^||NlNdK2lOrNJvOePfvMyd3t(!etv$0goKikl9Q8@t*x!Sy}iJ| zz`?=6QBhG-Q&VtoaD#(`k&%(UzP`l7#6(0yR#sM5S64ebJ6l^@Z*OmSczAz*e^^*p zi;Ihnj*d!7N={BrSy@?)jg5zghmVhsUS3{QR8&bxNnl`LRaI3%K|x1HM@&picXxM; zjEsngh)_^aUteEcU0qyUTun_)VPRna000320RjR70|NsD1Ox>I1qKEN2L}fT2nY!Y z2?`1d3kwSj3=9no4Gs6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE&%@kA^!_bMO0HmK~P09E-(WD0000X`2+deV=r%#+eg905Yv}jMFM~z}qdWosirA?teohr2|)vHmlYR$@Zt5>UC z!G0Ypwk+ARVbQ8h%XY0>vu)wNO-gqzQoDHX>dniy?q0ur0|Oo`xbR=Yhz~1HEVnV^ zxQ`=4o-DbtW6GB;YtGDhvuDhoLxUDgn($)NrBkC`t-AGT*RWs9j!nC^?a{Y$cgDS2 zx9{G-e+%b5ytwh>tY;@j&V0G^=FpW#pH97caN^jlYrnp|JNNJ2!;AkP|6ICx^61N_ zU$4GBd+^!ezmGq^KK=Xl^UL3_|Gazu{Q)RofCT6Fn%cFj4{?Iqm3=1h@*}??&xEV zKL!b;kVMjW%sX{3@&HtFP$Pe$1zlv7H%VXrG84s%N5$D(YyXkUlD? zp_58l>7|xtN@=8wYU*jHpnfXqsH9@L>8YirYHFyQs_JU1u)hB)>#Ve*y6Ua9=Bn$i ztn%t>ufGOstFXilTkNsGBCBky%QkDQv(Vxi?X<}+;;1&wcvg$?zrSW zyY0E{Ag|1_%P_|*v&uBj{PN8< zx2$u{HK)vT&p!t(^w2o(Tr|->Cyg}FOfPM;(?>@Q_0&{Xt#s2@TP^j|Tx-3x*I0v{ z_1I#UZT8t;rycg%Xtzx^+i$DgwcKvkP50e!+pTxreDD7~x8HdGEjZwD7fyKJh9iD> z;ENB=_~VT$E_vjMQ|`FskYBDj=9PEO`Q)C1{(0u3Z%+E@rHih5>Y=ml`s=WpzIyAl z$8P)VvgdyL?x^d|`|r314}9;#6K{O+wF{p-^2#&syYtUS4}J60Phb7=*jq3C@!M

y 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 Date: Fri, 24 Nov 2023 12:14:20 +0100 Subject: [PATCH 06/10] Refs #19973: Apply rev suggestions Signed-off-by: JesusPoderoso --- qml/DomainGraphLayout.qml | 2 ++ qml/GraphConnection.qml | 2 +- qml/TabLayout.qml | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/qml/DomainGraphLayout.qml b/qml/DomainGraphLayout.qml index 19d95955..7756e77a 100644 --- a/qml/DomainGraphLayout.qml +++ b/qml/DomainGraphLayout.qml @@ -35,6 +35,7 @@ Item 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) + signal openLoadingGraphDialog() //l et tab layout know that graph is about to be generated signal initialized() // let tab layout know that graph has been generated // Private properties @@ -1322,6 +1323,7 @@ Item text: "Refresh" onClicked:{ + domainGraphLayout.openLoadingGraphDialog() load_model() } } diff --git a/qml/GraphConnection.qml b/qml/GraphConnection.qml index 832e1835..aa984d02 100644 --- a/qml/GraphConnection.qml +++ b/qml/GraphConnection.qml @@ -141,7 +141,7 @@ Item { Rectangle { id: spot_0 anchors.verticalCenter: parent.verticalCenter - anchors.right: spot_1.left; anchors.rightMargin: hidden_arrow_margin_*2-graphConnection.height/2 + anchors.right: spot_1.left; anchors.rightMargin: hidden_arrow_margin_*2-graphConnection.height/2 +1 height: graphConnection.height; width: graphConnection.height radius: graphConnection.height color: arrow_color diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index b6a93fbd..5769cd98 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -36,7 +36,8 @@ Item { property int last_index_: 1 // force unique idx on QML components property var tab_model_: [{"idx":0, "title":"New Tab", "stack_id": 0}] // tab model for tab bad and tab management property bool disable_chart_selection_: false // flag to disable multiple chart view tabs - readonly property var allowed_stack_components_: ["view_selector", "chartsLayout", "domainGraphLayout_component"] + readonly property var allowed_stack_components_: // list of allowed component names to be + ["view_selector", "chartsLayout", "domainGraphLayout_component"]// loaded in the tabs stack view // private signals signal open_domain_view_(int stack_id, int entity_id, int domain_id) @@ -247,6 +248,10 @@ Item { tabLayout.openTopicMenu(domainEntityId, domainId, entityId, currentAlias, entityKind) } + onOpenLoadingGraphDialog: { + loading_graph_dialog.open() + } + onInitialized: { loading_graph_dialog.soft_close() } From 90503f088f880eb22dd29a06ec4fcc64034fb01d Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Fri, 24 Nov 2023 12:51:38 +0100 Subject: [PATCH 07/10] Refs #19973: Fix identation Signed-off-by: JesusPoderoso --- qml/TabLayout.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index 5769cd98..4505038f 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -500,7 +500,7 @@ Item { y: (parent.height - height) / 2 width: dialog_width_ - height: dialog_height_ + height: dialog_height_ modal: true From d64c6efc21d4e8dfcb6da21bf385bce96aef036e Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 27 Nov 2023 08:18:03 +0100 Subject: [PATCH 08/10] Refs #19973: Fix Gif size to adapt resolution Signed-off-by: JesusPoderoso --- qml/TabLayout.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qml/TabLayout.qml b/qml/TabLayout.qml index 4505038f..4d83c8da 100644 --- a/qml/TabLayout.qml +++ b/qml/TabLayout.qml @@ -54,7 +54,7 @@ Item { readonly property int add_tab_width_: 50 readonly property int timer_ms_interval_: 500 readonly property int dialog_width_: 300 - readonly property int dialog_height_: 120 + readonly property int dialog_height_: 152 readonly property string selected_tab_color_: "#ffffff" readonly property string selected_shadow_tab_color_: "#c0c0c0" readonly property string not_selected_tab_color_: "#f0f0f0" From be169816ffb19bb51b6ee84cd13d5f903e843e31 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 27 Nov 2023 08:59:11 +0100 Subject: [PATCH 09/10] Refs #19973: Please uncrustify Signed-off-by: JesusPoderoso --- src/Engine.cpp | 108 ++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 2216f38c..4d4b7fbe 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"), backend::StatusLevel::OK, std::string("")); + std::string("No issues found"), backend::StatusLevel::OK, std::string("")); entity_status_model_->addTopLevelItem(empty_item); } else @@ -1016,19 +1016,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, 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, std::string(""), description); + 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("")); + 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("")); + 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,22 +1049,26 @@ 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, 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, std::string(""), description); - for (eprosima::fastdds::statistics::QosPolicyCount_s policy : sample.incompatible_qos_status.policies()) + 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 (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")); + 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); } } @@ -1081,10 +1087,12 @@ 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, 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, std::to_string(sample.inconsistent_topic_status.total_count()), description); + 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(); } @@ -1100,21 +1108,26 @@ 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, 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, std::string(""), description); + 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("")); + 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("")); + 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); @@ -1134,10 +1147,12 @@ 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, 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, std::to_string(sample.liveliness_lost_status.total_count()), description); + 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(); } @@ -1153,10 +1168,11 @@ 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, 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, 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(); } @@ -1177,8 +1193,8 @@ bool Engine::update_entity_status( { if (new_status == backend::StatusLevel::ERROR) { - std::map::iterator it = controller_->status_counters.errors.find(id); - if(it != controller_->status_counters.errors.end()) + std::map::iterator it = controller_->status_counters.errors.find(id); + if (it != controller_->status_counters.errors.end()) { controller_->status_counters.total_errors -= controller_->status_counters.errors[id]; } @@ -1187,8 +1203,8 @@ bool Engine::update_entity_status( } else if (new_status == backend::StatusLevel::WARNING) { - std::map::iterator it = controller_->status_counters.warnings.find(id); - if(it != controller_->status_counters.warnings.end()) + std::map::iterator it = controller_->status_counters.warnings.find(id); + if (it != controller_->status_counters.warnings.end()) { controller_->status_counters.total_warnings -= controller_->status_counters.warnings[id]; } @@ -1199,8 +1215,8 @@ bool Engine::update_entity_status( 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)); + QString::number(controller_->status_counters.total_errors), + QString::number(controller_->status_counters.total_warnings)); // remove empty message if exists if (entity_status_model_->is_empty()) @@ -1231,18 +1247,20 @@ 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, "", backend::StatusLevel::OK, "")); + 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"), backend::StatusLevel::OK, std::string(""))); + backend::ID_ALL, std::string("No issues found"), backend::StatusLevel::OK, + std::string(""))); } // update error counter - std::map::iterator err_it = controller_->status_counters.errors.find(id); - if(err_it != controller_->status_counters.errors.end()) + 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; @@ -1254,8 +1272,8 @@ bool Engine::remove_inactive_entities_from_status_model( 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()) + 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; @@ -1270,8 +1288,8 @@ bool Engine::remove_inactive_entities_from_status_model( 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)); + QString::number(controller_->status_counters.total_errors), + QString::number(controller_->status_counters.total_warnings)); // update view entity_status_proxy_model_->set_source_model(entity_status_model_); From 3369590aefefd05c3ac56a6c9687987d2deb7e57 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 12 Dec 2023 13:00:27 +0100 Subject: [PATCH 10/10] Refs #19973: Fix statistics backend StatusLevel references Signed-off-by: JesusPoderoso --- src/Engine.cpp | 26 +++++++++++++------------- src/model/tree/StatusTreeItem.cpp | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Engine.cpp b/src/Engine.cpp index 4d4b7fbe..ead4e246 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -997,12 +997,12 @@ bool Engine::update_entity_status( if (id == backend::ID_ALL) { auto empty_item = new models::StatusTreeItem(backend::ID_ALL, - std::string("No issues found"), backend::StatusLevel::OK, std::string("")); + std::string("No issues found"), backend::StatusLevel::OK_STATUS, std::string("")); entity_status_model_->addTopLevelItem(empty_item); } else { - backend::StatusLevel new_status = backend::StatusLevel::OK; + backend::StatusLevel new_status = backend::StatusLevel::OK_STATUS; std::string description = backend::entity_status_description(kind); switch (kind) @@ -1012,7 +1012,7 @@ bool Engine::update_entity_status( backend::DeadlineMissedSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( @@ -1044,7 +1044,7 @@ bool Engine::update_entity_status( backend::IncompatibleQosSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { std::string fastdds_version = "v2.12.0"; backend::StatusLevel entity_status = backend_connection_.get_status(id); @@ -1083,7 +1083,7 @@ bool Engine::update_entity_status( backend::InconsistentTopicSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( @@ -1104,7 +1104,7 @@ bool Engine::update_entity_status( backend::LivelinessChangedSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( @@ -1143,7 +1143,7 @@ bool Engine::update_entity_status( backend::LivelinessLostSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( @@ -1164,7 +1164,7 @@ bool Engine::update_entity_status( backend::SampleLostSample sample; if (backend_connection_.get_status_data(id, sample)) { - if (sample.status != backend::StatusLevel::OK) + if (sample.status != backend::StatusLevel::OK_STATUS) { backend::StatusLevel entity_status = backend_connection_.get_status(id); auto entity_item = entity_status_model_->getTopLevelItem( @@ -1189,9 +1189,9 @@ bool Engine::update_entity_status( break; } } - if (new_status != backend::StatusLevel::OK) + if (new_status != backend::StatusLevel::OK_STATUS) { - if (new_status == backend::StatusLevel::ERROR) + if (new_status == backend::StatusLevel::ERROR_STATUS) { std::map::iterator it = controller_->status_counters.errors.find(id); if (it != controller_->status_counters.errors.end()) @@ -1201,7 +1201,7 @@ bool Engine::update_entity_status( controller_->status_counters.errors[id] = counter; controller_->status_counters.total_errors += controller_->status_counters.errors[id]; } - else if (new_status == backend::StatusLevel::WARNING) + else if (new_status == backend::StatusLevel::WARNING_STATUS) { std::map::iterator it = controller_->status_counters.warnings.find(id); if (it != controller_->status_counters.warnings.end()) @@ -1247,14 +1247,14 @@ 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, "", backend::StatusLevel::OK, + entity_status_model_->removeItem(entity_status_model_->getTopLevelItem(id, "", backend::StatusLevel::OK_STATUS, "")); // 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"), backend::StatusLevel::OK, + backend::ID_ALL, std::string("No issues found"), backend::StatusLevel::OK_STATUS, std::string(""))); } diff --git a/src/model/tree/StatusTreeItem.cpp b/src/model/tree/StatusTreeItem.cpp index 95ab319f..e4adb760 100644 --- a/src/model/tree/StatusTreeItem.cpp +++ b/src/model/tree/StatusTreeItem.cpp @@ -53,7 +53,7 @@ StatusTreeItem::StatusTreeItem() , id_(backend::ID_ALL) , kind_(backend::StatusKind::INVALID) , name_() - , status_level_(backend::StatusLevel::OK) + , status_level_(backend::StatusLevel::OK_STATUS) , value_() , description_() , is_active_(true) @@ -73,7 +73,7 @@ StatusTreeItem::StatusTreeItem( , id_(backend::ID_ALL) , kind_(backend::StatusKind::INVALID) , name_(data.toString().toStdString()) - , status_level_(backend::StatusLevel::OK) + , status_level_(backend::StatusLevel::OK_STATUS) , value_() , description_() , is_active_(true)