Ember
Loading...
Searching...
No Matches
MonitorNavigatorTab.cpp
Go to the documentation of this file.
2
3namespace Ember {
4namespace Monitor {
5
6// ============================================================================
7// MonitorHierarchyView
8// ============================================================================
9
12
14 if (!node)
15 return "Unknown Node";
16
17 wxString label = node->GetName();
18 label += " [" + node->GetTypeString() + "]";
19
20 if (m_stateManager) {
21 int status = static_cast<int>(m_stateManager->GetNodeStatus(static_cast<int64_t>(node->GetId())));
22 wxString statusLabel = GetStatusLabel(status);
23 if (!statusLabel.IsEmpty()) {
24 label += " " + statusLabel;
25 }
26 }
27
28 return label;
29}
30
32 auto now = std::chrono::steady_clock::now();
33 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastRefreshTime);
34 if (elapsed.count() < REFRESH_INTERVAL_MS) {
35 return;
36 }
38
39 if (!m_stateManager)
40 return;
41
42 wxTreeCtrl *tc = GetTreeCtrl();
43 if (!tc || !tc->GetRootItem().IsOk())
44 return;
45
46 auto changedIds = m_stateManager->GetAndClearChangedNodes();
47 if (changedIds.empty())
48 return;
49
51
52 if (changedIds.size() > m_nodeIdToItem.size() / 2) {
54 } else {
55 UpdateChangedNodes(changedIds);
56 }
57}
58
60 m_nodeIdToItem.clear();
61 wxTreeCtrl *tc = GetTreeCtrl();
62 if (!tc || !tc->GetRootItem().IsOk())
63 return;
64 RebuildNodeIdMapRecursive(tc->GetRootItem());
65}
66
68 if (!item.IsOk())
69 return;
70
71 wxTreeCtrl *tc = GetTreeCtrl();
73 if (node) {
74 m_nodeIdToItem[static_cast<int64_t>(node->GetId())] = item;
75 }
76
77 wxTreeItemIdValue cookie;
78 wxTreeItemId child = tc->GetFirstChild(item, cookie);
79 while (child.IsOk()) {
81 child = tc->GetNextChild(item, cookie);
82 }
83}
84
85void MonitorHierarchyView::UpdateChangedNodes(const std::vector<int64_t> &changedIds) {
86 if (!m_stateManager || changedIds.empty())
87 return;
88
89 wxTreeCtrl *tc = GetTreeCtrl();
90 if (!tc || !tc->GetRootItem().IsOk())
91 return;
92
93 tc->Freeze();
94
95 for (int64_t nodeId : changedIds) {
96 auto it = m_nodeIdToItem.find(nodeId);
97 if (it == m_nodeIdToItem.end() || !it->second.IsOk())
98 continue;
99
100 wxTreeItemData *rawData = tc->GetItemData(it->second);
101 if (!rawData)
102 continue;
103
104 EmberCore::ITreeNode *node = GetNodeFromItem(it->second);
105 if (node) {
106 UpdateSingleItem(it->second, node);
107 }
108 }
109
110 tc->Thaw();
111}
112
114 wxTreeCtrl *tc = GetTreeCtrl();
115 wxString label = GetNodeDisplayText(node);
116 tc->SetItemText(item, label);
117
118 int status = static_cast<int>(m_stateManager->GetNodeStatus(static_cast<int64_t>(node->GetId())));
119
120 switch (status) {
121 case 1:
122 tc->SetItemTextColour(item, wxColour(100, 150, 255));
123 break;
124 case 2:
125 tc->SetItemTextColour(item, wxColour(100, 220, 100));
126 break;
127 case 3:
128 tc->SetItemTextColour(item, wxColour(255, 80, 80));
129 break;
130 case 4:
131 tc->SetItemTextColour(item, wxColour(255, 180, 50));
132 break;
133 default:
134 tc->SetItemTextColour(item, wxColour(200, 200, 200));
135 break;
136 }
137}
138
140 wxTreeCtrl *tc = GetTreeCtrl();
141 if (!tc || !m_stateManager || !tc->GetRootItem().IsOk())
142 return;
143
144 tc->Freeze();
145
146 std::function<void(wxTreeItemId)> updateItem = [&](wxTreeItemId item) {
147 if (!item.IsOk())
148 return;
149
151 if (node) {
152 UpdateSingleItem(item, node);
153 }
154
155 wxTreeItemIdValue cookie;
156 wxTreeItemId child = tc->GetFirstChild(item, cookie);
157 while (child.IsOk()) {
158 updateItem(child);
159 child = tc->GetNextChild(item, cookie);
160 }
161 };
162
163 updateItem(tc->GetRootItem());
164 tc->Thaw();
165}
166
167wxString MonitorHierarchyView::GetStatusLabel(int status) const {
168 switch (status) {
169 case 1:
170 return wxString::FromUTF8("\xe2\x96\xb6");
171 case 2:
172 return wxString::FromUTF8("\xe2\x9c\x93");
173 case 3:
174 return wxString::FromUTF8("\xe2\x9c\x97");
175 case 4:
176 return wxString::FromUTF8("\xe2\x96\xa0");
177 default:
178 return "";
179 }
180}
181
182// ============================================================================
183// MonitorNavigatorTab
184// ============================================================================
185
186MonitorNavigatorTab::MonitorNavigatorTab(wxWindow *parent) : EmberUI::NavigatorTab(parent, /*deferLayout=*/true) {
187 SetEditingEnabled(false);
188 InitLayout();
190}
191
193 const EmberUI::TreeHierarchyConfig &cfg) {
194 EmberUI::TreeHierarchyConfig monitorCfg = cfg;
195 monitorCfg.autoExpandDepth = 100;
196 monitorCfg.syncSelectionWithCanvas = true;
197 return new MonitorHierarchyView(parent, monitorCfg);
198}
199
200void MonitorNavigatorTab::SetMonitorTree(std::shared_ptr<EmberCore::ITreeStructure> tree,
201 std::shared_ptr<Network::StateManager> stateManager,
202 const std::string &treeId) {
203 m_stateManager = stateManager;
204 if (m_monitorHierView) {
205 m_monitorHierView->SetStateManager(stateManager);
206 }
207
208 std::string id = treeId.empty() ? "monitored_tree" : treeId;
209 SetActiveTree(tree, id);
210 DrillIntoTree(id);
211
212 if (m_monitorHierView) {
213 m_monitorHierView->Layout();
214 m_monitorHierView->wxWindow::Refresh();
215 }
216
217 Layout();
218 wxPanel::Refresh();
219}
220
222 m_stateManager.reset();
223 if (m_monitorHierView) {
224 m_monitorHierView->SetStateManager(nullptr);
225 m_monitorHierView->InvalidateNodeIdMap();
226 }
227 NavigateBack();
229}
230
232 if (m_monitorHierView) {
233 m_monitorHierView->RefreshStatus();
234 }
235}
236
237} // namespace Monitor
238} // namespace Ember
Abstract interface for tree nodes that can be visualized.
Definition ITreeNode.h:31
virtual String GetTypeString() const
Definition ITreeNode.h:115
virtual size_t GetId() const =0
virtual const String & GetName() const =0
TreeHierarchyTab subclass with context menu and node activation hooks.
NavigatorHierarchyView(wxWindow *parent, const EmberUI::TreeHierarchyConfig &config)
void SetEditingEnabled(bool enabled)
void SetActiveTree(std::shared_ptr< EmberCore::ITreeStructure > tree, const std::string &treeId)
Sets the active tree for hierarchy view and drills into it.
void NavigateBack()
Navigates back in breadcrumb history.
NavigatorHierarchyView * GetHierarchyView() const
void DrillIntoTree(const std::string &treeId)
Drills into a subtree (updates breadcrumb and hierarchy).
NavigatorTab(wxWindow *parent)
wxTreeCtrl * GetTreeCtrl() const
Returns the tree control widget.
EmberCore::ITreeNode * GetNodeFromItem(const wxTreeItemId &item) const
Extracts ITreeNode from a tree item (or nullptr if DummyTreeItemData).
Hierarchy view with live status updates.
std::unordered_map< int64_t, wxTreeItemId > m_nodeIdToItem
wxString GetNodeDisplayText(EmberCore::ITreeNode *node) const override
Returns display text including status for the given node.
std::shared_ptr< Network::StateManager > m_stateManager
void UpdateSingleItem(const wxTreeItemId &item, EmberCore::ITreeNode *node)
std::chrono::steady_clock::time_point m_lastRefreshTime
void UpdateChangedNodes(const std::vector< int64_t > &changedIds)
void RefreshStatus()
Refreshes status icons and labels for visible tree nodes.
void RebuildNodeIdMapRecursive(const wxTreeItemId &item)
MonitorHierarchyView(wxWindow *parent, const EmberUI::TreeHierarchyConfig &config)
static constexpr int64_t REFRESH_INTERVAL_MS
void RebuildNodeIdMap()
Rebuilds the node ID to tree item mapping.
void ClearMonitorTree()
Clears the current monitor tree.
EmberUI::NavigatorHierarchyView * CreateHierarchyView(wxWindow *parent, const EmberUI::TreeHierarchyConfig &cfg) override
Creates and returns a MonitorHierarchyView instance.
void RefreshStatus()
Refreshes status display for all visible nodes.
void SetMonitorTree(std::shared_ptr< EmberCore::ITreeStructure > tree, std::shared_ptr< Network::StateManager > stateManager, const std::string &treeId="")
Sets the monitor tree and state manager; optionally associates a tree ID.
std::shared_ptr< Network::StateManager > m_stateManager
Definition Panel.h:8
Configuration for TreeHierarchyTab appearance and behavior.
bool syncSelectionWithCanvas
Sync selection with canvas.
int autoExpandDepth
Depth to auto-expand.