INSTINCT Code Coverage Report


Directory: src/
File: internal/FlowManager.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 146 256 57.0%
Functions: 9 16 56.2%
Branches: 200 740 27.0%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "internal/FlowManager.hpp"
10
11 #include "util/Json.hpp"
12
13 #include "internal/NodeManager.hpp"
14 namespace nm = NAV::NodeManager;
15
16 #include <implot.h>
17 #include <imgui_node_editor.h>
18 namespace ed = ax::NodeEditor;
19
20 #include "NodeRegistry.hpp"
21
22 #include "internal/Node/Node.hpp"
23 #include "internal/Node/Pin.hpp"
24 #include "internal/ConfigManager.hpp"
25 #include "internal/FlowExecutor.hpp"
26
27 #include "internal/gui/windows/ImPlotStyleEditor.hpp"
28 #include "internal/gui/NodeEditorApplication.hpp"
29 #include "internal/gui/windows/NodeEditorStyleEditor.hpp"
30 #include "util/Plot/Colormap.hpp"
31 #include "util/Logger/CommonLog.hpp"
32
33 #include <fstream>
34 #include <set>
35 #include <iomanip>
36 #include <string>
37 #include <memory>
38
39 #include <iostream>
40
41 namespace NAV::flow
42 {
43 namespace
44 {
45
46 bool unsavedChanges = false;
47
48 constexpr int loadingFramesToWait = 2;
49
50 std::string currentFilename;
51 std::filesystem::path programRootPath;
52
53 // The current number for the rotated parent folder
54 size_t currentRotatedParentFolderNumber;
55
56 } // namespace
57
58 bool saveLastActions = true;
59 int loadingFrameCount = 0;
60
61 } // namespace NAV::flow
62
63 void NAV::flow::SaveFlow(GlobalActions& globalAction)
64 {
65 if (currentFilename.empty())
66 {
67 globalAction = GlobalActions::SaveAs;
68 }
69 else
70 {
71 SaveFlowAs(currentFilename);
72 }
73 }
74
75 void NAV::flow::SaveFlowAs(const std::string& filepath)
76 {
77 std::ofstream filestream(filepath);
78
79 if (!filestream.good())
80 {
81 std::cerr << "Save Flow error: Could not open file: " << filepath;
82 return;
83 }
84
85 json j;
86 for (const auto& node : nm::m_Nodes())
87 {
88 j["nodes"]["node-" + std::to_string(size_t(node->id))] = *node;
89 j["nodes"]["node-" + std::to_string(size_t(node->id))]["data"] = node->save();
90
91 for (const auto& outputPin : node->outputPins)
92 {
93 for (const auto& link : outputPin.links)
94 {
95 auto& jLink = j["links"]["link-" + std::to_string(size_t(link.linkId))];
96 jLink["id"] = size_t(link.linkId);
97 jLink["startPinId"] = size_t(outputPin.id);
98 jLink["endPinId"] = size_t(link.connectedPinId);
99 }
100 }
101 }
102 if (gui::windows::saveConfigInFlow)
103 {
104 j["implot"]["style"] = ImPlot::GetStyle();
105 j["implot"]["prefereFlowOverGlobal"] = gui::windows::prefereFlowOverGlobal;
106 }
107
108 j["fonts"]["useBigDefaultFont"] = gui::NodeEditorApplication::isUsingBigDefaultFont();
109 j["fonts"]["useBigWindowFont"] = gui::NodeEditorApplication::isUsingBigWindowFont();
110 j["fonts"]["useBigPanelFont"] = gui::NodeEditorApplication::isUsingBigPanelFont();
111 j["fonts"]["useBigMonoFont"] = gui::NodeEditorApplication::isUsingBigMonoFont();
112 j["leftPane"]["hide"] = gui::NodeEditorApplication::hideLeftPane;
113 j["leftPane"]["leftWidth"] = gui::NodeEditorApplication::leftPaneWidth;
114 j["leftPane"]["rightWidth"] = gui::NodeEditorApplication::rightPaneWidth;
115 j["bottomViewHeight"] = gui::NodeEditorApplication::bottomViewHeight;
116 j["hideFPS"] = gui::NodeEditorApplication::hideFPS;
117 j["lightMode"] = gui::windows::nodeEditorLightMode;
118 j["gridLinesEnabled"] = ed::GetStyle().Colors[ed::StyleColor_Grid].w;
119 j["transparentWindows"] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w;
120
121 // if (ImGui::Checkbox("Light mode", &nodeEditorLightMode))
122 // {
123 // ApplyDarkLightMode(NodeEditorApplication::m_colors);
124 // flow::ApplyChanges();
125 // }
126
127 j["colormaps"] = ColormapsFlow;
128 j["commonLog"] = CommonLog::save();
129
130 filestream << std::setw(4) << j << std::endl; // NOLINT(performance-avoid-endl)
131
132 unsavedChanges = false;
133 }
134
135 112 bool NAV::flow::LoadFlow(const std::string& filepath)
136 {
137 LOG_TRACE("called for path {}", filepath);
138 112 bool loadSuccessful = true;
139
140 try
141 {
142
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 std::ifstream filestream(filepath);
143
144
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
112 if (!filestream.good())
145 {
146 LOG_ERROR("Load Flow error: Could not open file: {}", filepath);
147 return false;
148 }
149
150
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
112 if (FlowExecutor::isRunning()) { FlowExecutor::stop(); }
151
152 112 json j;
153
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 filestream >> j;
154
155 112 saveLastActions = false;
156
157
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 nm::DeleteAllNodes();
158
159
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
112 if (!j.contains("commonLog")) { CommonLog::restore(json{}); }
160
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 LoadJson(j);
161
162 #ifdef TESTING
163
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 nm::CallPreInitCallback();
164 #endif
165
166
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
224 if (!ConfigManager::Get<bool>("noinit"))
167 {
168
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 112 times.
✗ Branch 8 not taken.
224 if (ConfigManager::Get<bool>("nogui"))
169 {
170
3/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 111 times.
112 if (!nm::InitializeAllNodes())
171 {
172 1 loadSuccessful = false;
173 }
174 }
175 else
176 {
177 nm::InitializeAllNodesAsync();
178 }
179 }
180
181
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 112 times.
224 if (!ConfigManager::Get<bool>("nogui"))
182 {
183 loadingFrameCount = ImGui::GetFrameCount();
184 }
185 112 unsavedChanges = false;
186 112 saveLastActions = true;
187
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 currentFilename = filepath;
188
189
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 112 times.
224 if (!ConfigManager::Get<bool>("nogui"))
190 {
191 gui::clearLastActionList();
192 gui::saveLastAction();
193 }
194
195
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 std::string path = filepath;
196
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 112 times.
112 if (path.find(GetProgramRootPath().string()) != std::string::npos)
197 {
198 path = path.substr(GetProgramRootPath().string().size());
199 if (path.starts_with('\\') || path.starts_with('/')) { path = path.substr(1); }
200 }
201
202
2/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
112 LOG_INFO("Loaded flow file: {}", path);
203 112 }
204 catch (const std::exception& e)
205 {
206 LOG_ERROR("Loading flow file failed with error: {}", e.what());
207 loadSuccessful = false;
208 }
209
210 112 return loadSuccessful;
211 }
212
213 112 bool NAV::flow::LoadJson(const json& j, bool requestNewIds)
214 {
215 112 bool loadSuccessful = true;
216
217
3/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 110 times.
112 if (j.contains("implot"))
218 {
219 2 gui::windows::saveConfigInFlow = true;
220
221
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (j.at("implot").contains("prefereFlowOverGlobal"))
222 {
223
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 j.at("implot").at("prefereFlowOverGlobal").get_to(gui::windows::prefereFlowOverGlobal);
224 }
225
226
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::filesystem::path filepath = flow::GetProgramRootPath();
227
4/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("implot-config") };
228 2 inputPath.is_relative())
229 {
230
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 filepath /= inputPath;
231 }
232 else
233 {
234 filepath = inputPath;
235 2 }
236
237
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 if (gui::windows::prefereFlowOverGlobal || !std::filesystem::exists(filepath))
238 {
239
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
4 if (!ConfigManager::Get<bool>("nogui"))
240 {
241 if (j.at("implot").contains("style"))
242 {
243 j.at("implot").at("style").get_to(ImPlot::GetStyle());
244 }
245 }
246 }
247 2 }
248 else
249 {
250 110 gui::windows::saveConfigInFlow = false;
251 }
252
253
3/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
✓ Branch 4 taken 43 times.
112 if (j.contains("colormaps"))
254 {
255
2/4
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
69 j.at("colormaps").get_to(ColormapsFlow);
256 }
257 else
258 {
259 43 ColormapsFlow.clear();
260 }
261
2/8
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
112 if (j.contains("commonLog")) { CommonLog::restore(j.at("commonLog")); }
262
263
3/6
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 112 times.
224 if (!ConfigManager::Get<bool>("nogui"))
264 {
265 if (j.contains("fonts"))
266 {
267 if (j.at("fonts").contains("useBigDefaultFont"))
268 {
269 gui::NodeEditorApplication::swapDefaultFont(j.at("fonts").at("useBigDefaultFont").get<bool>());
270 }
271 if (j.at("fonts").contains("useBigWindowFont"))
272 {
273 gui::NodeEditorApplication::swapWindowFont(j.at("fonts").at("useBigWindowFont").get<bool>());
274 }
275 if (j.at("fonts").contains("useBigPanelFont"))
276 {
277 gui::NodeEditorApplication::swapPanelFont(j.at("fonts").at("useBigPanelFont").get<bool>());
278 }
279 if (j.at("fonts").contains("useBigMonoFont"))
280 {
281 gui::NodeEditorApplication::swapMonoFont(j.at("fonts").at("useBigMonoFont").get<bool>());
282 }
283 }
284 if (j.contains("leftPane"))
285 {
286 j.at("leftPane").at("hide").get_to(gui::NodeEditorApplication::hideLeftPane);
287 j.at("leftPane").at("leftWidth").get_to(gui::NodeEditorApplication::leftPaneWidth);
288 j.at("leftPane").at("rightWidth").get_to(gui::NodeEditorApplication::rightPaneWidth);
289 }
290 if (j.contains("bottomViewHeight")) { j.at("bottomViewHeight").get_to(gui::NodeEditorApplication::bottomViewHeight); }
291 if (j.contains("hideFPS")) { j.at("hideFPS").get_to(gui::NodeEditorApplication::hideFPS); }
292 if (j.contains("lightMode"))
293 {
294 j.at("lightMode").get_to(gui::windows::nodeEditorLightMode);
295 gui::windows::ApplyDarkLightMode(gui::NodeEditorApplication::m_colors);
296 }
297 if (j.contains("gridLinesEnabled")) { j.at("gridLinesEnabled").get_to(ed::GetStyle().Colors[ed::StyleColor_Grid].w); }
298 if (j.contains("transparentWindows")) { j.at("transparentWindows").get_to(ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w); }
299 }
300
301
2/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✗ Branch 4 not taken.
112 if (j.contains("nodes"))
302 {
303
6/10
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 346 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 346 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 458 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 346 times.
✓ Branch 15 taken 112 times.
458 for (const auto& nodeJson : j.at("nodes"))
304 {
305
2/4
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 346 times.
346 if (!nodeJson.contains("type"))
306 {
307 LOG_ERROR("Node does not contain a type");
308 continue;
309 }
310 346 Node* node = nullptr;
311
2/4
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 1827 times.
✗ Branch 9 not taken.
1827 for (const auto& registeredNode : NAV::NodeRegistry::RegisteredNodes())
312 {
313
2/2
✓ Branch 5 taken 19074 times.
✓ Branch 6 taken 1481 times.
20555 for (const auto& nodeInfo : registeredNode.second)
314 {
315
4/6
✓ Branch 1 taken 19074 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19074 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 346 times.
✓ Branch 9 taken 18728 times.
19074 if (nodeInfo.type == nodeJson.at("type").get<std::string>())
316 {
317
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 node = nodeInfo.constructor();
318 346 break;
319 }
320 }
321
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 1481 times.
1827 if (node != nullptr)
322 {
323 346 break;
324 }
325 }
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (node == nullptr)
327 {
328 LOG_ERROR("Node type ({}) is not a valid type.", nodeJson.at("type").get<std::string>());
329 loadSuccessful = false;
330 continue;
331 }
332
333
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 nm::AddNode(node);
334 346 auto newNodeId = node->id;
335
336
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 nodeJson.get_to<Node>(*node);
337
2/4
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 346 times.
✗ Branch 4 not taken.
346 if (nodeJson.contains("data"))
338 {
339
2/4
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 346 times.
✗ Branch 5 not taken.
346 node->restore(nodeJson.at("data"));
340 }
341 // Load second time in case restore changed the amount of pins
342
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 nodeJson.get_to<Node>(*node);
343
344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 346 times.
346 if (requestNewIds)
345 {
346 node->id = newNodeId;
347 for (auto& pin : node->inputPins)
348 {
349 pin.id = nm::GetNextPinId();
350 }
351 for (auto& pin : node->outputPins)
352 {
353 pin.id = nm::GetNextPinId();
354 }
355 }
356
357
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 nm::UpdateNode(node);
358
359
3/6
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 346 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 346 times.
692 if (!ConfigManager::Get<bool>("nogui"))
360 {
361 ed::SetNodePosition(node->id, nodeJson.at("pos").get<ImVec2>());
362
363 if (node->getSize().x > 0 && node->getSize().y > 0)
364 {
365 ed::SetGroupSize(node->id, node->getSize());
366 }
367 }
368 }
369 }
370
371 // Collect the node ids which get new links to call the restoreAfterLinks function on them
372 112 std::set<Node*> newlyLinkedNodes;
373
374
3/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 37 times.
112 if (j.contains("links"))
375 {
376
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 75 times.
225 for (size_t i = 0; i < 2; i++) // Run twice because pins can change type depending on other links
377 {
378
6/10
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 538 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 538 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 688 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 538 times.
✓ Branch 15 taken 150 times.
688 for (const auto& linkJson : j.at("links"))
379 {
380
2/4
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 538 times.
✗ Branch 5 not taken.
538 auto linkId = linkJson.at("id").get<size_t>();
381
2/4
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 538 times.
✗ Branch 5 not taken.
538 auto startPinId = linkJson.at("startPinId").get<size_t>();
382
2/4
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 538 times.
✗ Branch 5 not taken.
538 auto endPinId = linkJson.at("endPinId").get<size_t>();
383
384 538 InputPin* endPin = nullptr;
385 538 OutputPin* startPin = nullptr;
386
2/4
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2466 times.
✗ Branch 9 not taken.
2466 for (auto* node : nm::m_Nodes())
387 {
388
2/2
✓ Branch 0 taken 1896 times.
✓ Branch 1 taken 570 times.
2466 if (!endPin)
389 {
390
2/2
✓ Branch 5 taken 2396 times.
✓ Branch 6 taken 1896 times.
4292 for (auto& inputPin : node->inputPins)
391 {
392
3/4
✓ Branch 1 taken 2396 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 538 times.
✓ Branch 4 taken 1858 times.
2396 if (endPinId == size_t(inputPin.id)) { endPin = &inputPin; }
393 }
394 }
395
2/2
✓ Branch 0 taken 1754 times.
✓ Branch 1 taken 712 times.
2466 if (!startPin)
396 {
397
2/2
✓ Branch 5 taken 1846 times.
✓ Branch 6 taken 1754 times.
3600 for (auto& outputPin : node->outputPins)
398 {
399
3/4
✓ Branch 1 taken 1846 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 538 times.
✓ Branch 4 taken 1308 times.
1846 if (startPinId == size_t(outputPin.id)) { startPin = &outputPin; }
400 }
401 }
402
4/4
✓ Branch 0 taken 1250 times.
✓ Branch 1 taken 1216 times.
✓ Branch 2 taken 538 times.
✓ Branch 3 taken 712 times.
2466 if (startPin && endPin) { break; }
403 }
404
2/4
✓ Branch 0 taken 538 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 538 times.
✗ Branch 3 not taken.
538 if (startPin && endPin)
405 {
406
4/6
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 538 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 536 times.
538 if (!startPin->createLink(*endPin, linkId))
407 {
408 2 loadSuccessful = false;
409 2 continue;
410 }
411
1/2
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
536 newlyLinkedNodes.insert(startPin->parentNode);
412
1/2
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
536 newlyLinkedNodes.insert(endPin->parentNode);
413 }
414 }
415 }
416 }
417
2/4
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✗ Branch 4 not taken.
112 if (j.contains("nodes"))
418 {
419
2/2
✓ Branch 5 taken 305 times.
✓ Branch 6 taken 112 times.
417 for (auto* node : newlyLinkedNodes)
420 {
421
6/12
✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 305 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 305 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 305 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 305 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 305 times.
✗ Branch 18 not taken.
305 if (j.at("nodes").contains("node-" + std::to_string(size_t(node->id))))
422 {
423
3/6
✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 305 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 305 times.
✗ Branch 9 not taken.
305 LOG_DEBUG("Calling restoreAtferLink() for new node '{}'", node->nameId());
424
425
5/10
✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 305 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 305 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 305 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 305 times.
✗ Branch 14 not taken.
305 const auto& nodeJson = j.at("nodes").at("node-" + std::to_string(size_t(node->id)));
426
2/4
✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 305 times.
✗ Branch 4 not taken.
305 if (nodeJson.contains("data"))
427 {
428
2/4
✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 305 times.
✗ Branch 5 not taken.
305 node->restoreAtferLink(nodeJson.at("data"));
429 }
430 }
431 }
432 }
433
434 112 return loadSuccessful;
435 112 }
436
437 bool NAV::flow::HasUnsavedChanges()
438 {
439 return unsavedChanges;
440 }
441
442 14088 void NAV::flow::ApplyChanges()
443 {
444 // This prevents the newly loaded gui elements from triggering the unsaved changes
445
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 14088 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 14088 times.
14088 if (ImGui::GetCurrentContext() && ImGui::GetFrameCount() - loadingFrameCount >= loadingFramesToWait)
446 {
447 unsavedChanges = true;
448 if (saveLastActions)
449 {
450 gui::saveLastAction();
451 }
452 }
453 14088 }
454
455 void NAV::flow::DiscardChanges()
456 {
457 unsavedChanges = false;
458 }
459
460 std::string NAV::flow::GetCurrentFilename()
461 {
462 return currentFilename;
463 }
464
465 void NAV::flow::SetCurrentFilename(const std::string& newFilename)
466 {
467 currentFilename = newFilename;
468 }
469
470 813 std::filesystem::path NAV::flow::GetProgramRootPath()
471 {
472 813 return programRootPath;
473 }
474
475 116 void NAV::flow::SetProgramRootPath(const std::filesystem::path& newRootPath)
476 {
477
1/2
✓ Branch 3 taken 116 times.
✗ Branch 4 not taken.
116 LOG_DEBUG("Program root path set to {}", newRootPath);
478 116 programRootPath = newRootPath;
479 116 }
480
481 260 std::filesystem::path NAV::flow::GetOutputPath()
482 {
483 260 std::filesystem::path filepath = flow::GetProgramRootPath();
484
485
4/8
✓ Branch 1 taken 260 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 259 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 260 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 259 times.
✗ Branch 11 not taken.
519 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
486 260 outputPath.is_relative())
487 {
488
1/2
✓ Branch 1 taken 259 times.
✗ Branch 2 not taken.
259 filepath /= outputPath;
489 }
490 else
491 {
492 filepath = outputPath;
493 259 }
494
495
4/6
✓ Branch 1 taken 260 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 260 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 229 times.
518 if (ConfigManager::Get<bool>("rotate-output"))
496 {
497
1/2
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
60 filepath /= fmt::format("{:04d}", currentRotatedParentFolderNumber);
498 }
499
500 259 return filepath;
501 }
502
503 125 void NAV::flow::SetOutputPath()
504 {
505 125 currentRotatedParentFolderNumber = 0;
506
2/2
✓ Branch 0 taken 1250080 times.
✓ Branch 1 taken 115 times.
1250195 for (int i = 10000; i >= 0; --i)
507 {
508
1/2
✓ Branch 1 taken 1250080 times.
✗ Branch 2 not taken.
1250080 std::filesystem::path outputDir{ programRootPath };
509
510
4/8
✓ Branch 1 taken 1250080 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1250080 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1250080 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1250080 times.
✗ Branch 11 not taken.
2500160 if (std::filesystem::path outputPath{ ConfigManager::Get<std::string>("output-path") };
511 1250080 outputPath.is_relative())
512 {
513
1/2
✓ Branch 1 taken 1250080 times.
✗ Branch 2 not taken.
1250080 outputDir /= outputPath;
514 }
515 else
516 {
517 outputDir = outputPath;
518 1250080 }
519
1/2
✓ Branch 2 taken 1250080 times.
✗ Branch 3 not taken.
2500160 outputDir /= fmt::format("{:04d}", i);
520
3/4
✓ Branch 1 taken 1250080 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1250070 times.
1250080 if (std::filesystem::exists(outputDir))
521 {
522 10 currentRotatedParentFolderNumber = static_cast<size_t>(i + 1); // NOLINT(bugprone-misplaced-widening-cast)
523 10 break;
524 }
525 1250080 }
526
2/4
✓ Branch 2 taken 125 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 125 times.
✗ Branch 7 not taken.
125 LOG_DEBUG("Output directory set to {}", GetOutputPath());
527 125 }
528
529 321 std::filesystem::path NAV::flow::GetInputPath()
530 {
531 321 std::filesystem::path filepath = flow::GetProgramRootPath();
532
533
4/8
✓ Branch 1 taken 321 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 321 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 322 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 320 times.
✗ Branch 11 not taken.
641 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("input-path") };
534 320 inputPath.is_relative())
535 {
536
1/2
✓ Branch 1 taken 322 times.
✗ Branch 2 not taken.
320 filepath /= inputPath;
537 }
538 else
539 {
540 filepath = inputPath;
541 322 }
542
543 320 return filepath;
544 }
545
546 3 std::filesystem::path NAV::flow::GetFlowPath()
547 {
548 3 std::filesystem::path filepath = flow::GetProgramRootPath();
549
550
4/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
6 if (std::filesystem::path inputPath{ ConfigManager::Get<std::string>("flow-path") };
551 3 inputPath.is_relative())
552 {
553
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 filepath /= inputPath;
554 }
555 else
556 {
557 filepath = inputPath;
558 3 }
559
560 3 return filepath;
561 }
562
563 std::filesystem::path NAV::flow::GetConfigPath()
564 {
565 return flow::GetProgramRootPath() / "config";
566 }
567