GCC Code Coverage Report


Directory: ./
File: src/gui/windows-manager.cc
Date: 2025-04-14 11:18:00
Exec Total Coverage
Lines: 0 163 0.0%
Branches: 0 310 0.0%

Line Branch Exec Source
1 // Copyright (c) 2015-2018, LAAS-CNRS
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4 // This file is part of gepetto-viewer.
5 // gepetto-viewer is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 //
10 // gepetto-viewer is distributed in the hope that it will be
11 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Lesser Public License for more details. You should have
14 // received a copy of the GNU Lesser General Public License along with
15 // gepetto-viewer. If not, see <http://www.gnu.org/licenses/>.
16
17 #include "gepetto/gui/windows-manager.hh"
18
19 #include <gepetto/viewer/group-node.h>
20 #include <gepetto/viewer/window-manager.h>
21
22 #include <gepetto/gui/bodytreewidget.hh>
23
24 #include "gepetto/gui/mainwindow.hh"
25 #include "gepetto/gui/osgwidget.hh"
26 #include "gepetto/gui/tree-item.hh"
27
28 namespace gepetto {
29 namespace gui {
30 using viewer::ScopedLock;
31
32 ✗ Qt::ConnectionType connectionType(QObject* o, int blocking) {
33 ✗ if (o->thread() == QThread::currentThread())
34 ✗ return Qt::DirectConnection;
35 ✗ else if (blocking)
36 ✗ return Qt::BlockingQueuedConnection;
37 else
38 ✗ return Qt::QueuedConnection;
39 }
40
41 ✗ WindowsManagerPtr_t WindowsManager::create(BodyTreeWidget* bodyTree) {
42 ✗ return WindowsManagerPtr_t(new WindowsManager(bodyTree));
43 }
44
45 ✗ WindowsManager::WindowID WindowsManager::createWindow(QString windowName) {
46 ✗ return createWindow(windowName.toStdString());
47 }
48
49 ✗ WindowsManager::WindowID WindowsManager::createWindow(
50 const std::string& windowName) {
51 ✗ if (getWindowManager(windowName, false)) return windowName;
52 ✗ MainWindow* main = MainWindow::instance();
53 OSGWidget* widget;
54 ✗ QMetaObject::invokeMethod(main, "createView", connectionType(main, true),
55 ✗ Q_RETURN_ARG(OSGWidget*, widget),
56 ✗ Q_ARG(std::string, windowName));
57 ✗ return widget->windowID();
58 }
59
60 ✗ WindowsManager::WindowID WindowsManager::createWindow(
61 const std::string& windowName, gepetto::gui::OSGWidget* widget,
62 osgViewer::Viewer* viewer, osg::GraphicsContext* gc) {
63 ✗ if (getWindowManager(windowName, false)) return windowName;
64 viewer::WindowManagerPtr_t newWindow =
65 ✗ viewer::WindowManager::create(viewer, gc);
66 ✗ WindowID windowId = addWindow(windowName, newWindow);
67 ✗ assert(windowId == windowName);
68 ✗ widgets_.insert(std::make_pair(windowId, widget));
69 ✗ return windowId;
70 }
71
72 ✗ WindowsManager::WindowsManager(BodyTreeWidget* bodyTree)
73 ✗ : Parent_t(), bodyTree_(bodyTree), refreshIsSynchronous_(false) {}
74
75 ✗ void WindowsManager::addNode(const std::string& nodeName, NodePtr_t node,
76 GroupNodePtr_t parent) {
77 ✗ Parent_t::addNode(nodeName, node, parent);
78 ✗ if (parent) initParent(node, parent, false);
79 }
80
81 ✗ void WindowsManager::insertNode(const std::string& nodeName, NodePtr_t node) {
82 ✗ ScopedLock lock(osgFrameMutex());
83 ✗ addNode(nodeName, node, GroupNodePtr_t());
84 }
85
86 ✗ void WindowsManager::addGroup(const std::string& groupName,
87 GroupNodePtr_t group, GroupNodePtr_t parent) {
88 ✗ Parent_t::addGroup(groupName, group, parent);
89 ✗ if (!parent || !initParent(group, parent, true)) {
90 // Consider it a root group
91 ✗ BodyTreeItem* bti = new BodyTreeItem(NULL, group);
92 ✗ nodeItemMap_[groupName].first.push_back(bti);
93 ✗ nodeItemMap_[groupName].second = true;
94 ✗ if (bti->thread() != bodyTree_->thread())
95 ✗ bti->moveToThread(bodyTree_->thread());
96 ✗ bti->initialize();
97 ✗ bodyTree_->model()->appendRow(bti);
98 }
99 }
100
101 ✗ void WindowsManager::addToGroup(const std::string& nodeName,
102 const std::string& groupName,
103 const NodePtr_t& node,
104 const BodyTreeItems_t& groups, bool isGroup) {
105 ✗ for (std::size_t i = 0; i < groups.size(); ++i) {
106 ✗ BodyTreeItem* bti = new BodyTreeItem(NULL, node);
107 ✗ nodeItemMap_[nodeName].first.push_back(bti);
108 ✗ nodeItemMap_[nodeName].second = isGroup;
109 ✗ bti->setParentGroup(groupName);
110 ✗ if (bti->thread() != bodyTree_->thread())
111 ✗ bti->moveToThread(bodyTree_->thread());
112 ✗ bti->initialize();
113 ✗ groups[i]->appendRow(bti);
114 }
115 }
116
117 ✗ bool WindowsManager::addToGroup(const std::string& nodeName,
118 const std::string& groupName) {
119 ✗ if (Parent_t::addToGroup(nodeName, groupName)) {
120 ✗ NodePtr_t node = getNode(nodeName, false);
121 ✗ bool isGroup = true;
122 try {
123 ✗ getGroup(nodeName, true);
124 ✗ } catch (const std::invalid_argument& exc) {
125 ✗ isGroup = false;
126 }
127 ✗ assert(node);
128 ✗ BodyTreeItemMap_t::const_iterator _groups = nodeItemMap_.find(groupName);
129 ✗ assert(_groups != nodeItemMap_.end());
130 ✗ assert(!_groups->second.first.empty());
131 ✗ assert(_groups->second.second);
132 ✗ assert(getGroup(groupName));
133 ✗ addToGroup(nodeName, groupName, node, _groups->second.first, isGroup);
134 ✗ return true;
135 }
136 ✗ return false;
137 }
138
139 ✗ bool WindowsManager::removeFromGroup(const std::string& nodeName,
140 const std::string& groupName) {
141 ✗ bool ret = Parent_t::removeFromGroup(nodeName, groupName);
142 ✗ if (ret) {
143 ✗ BodyTreeItemMap_t::iterator _nodes = nodeItemMap_.find(nodeName);
144 ✗ BodyTreeItemMap_t::iterator _groups = nodeItemMap_.find(groupName);
145 ✗ assert(_nodes != nodeItemMap_.end());
146 ✗ assert(_groups != nodeItemMap_.end());
147 ✗ BodyTreeItems_t& nodes = _nodes->second.first;
148 ✗ const BodyTreeItems_t& groups = _groups->second.first;
149 ✗ bool found = false;
150 ✗ for (BodyTreeItems_t::iterator _node = nodes.begin(); _node != nodes.end();
151 ✗ ++_node) {
152 ✗ BodyTreeItems_t::const_iterator _group = std::find(
153 ✗ groups.begin(), groups.end(), (*_node)->QStandardItem::parent());
154 ✗ if (_group == groups.end()) continue;
155 ✗ bodyTree_->model()->takeRow((*_node)->row());
156 ✗ nodes.erase(_node);
157 ✗ found = true;
158 ✗ break;
159 }
160 ✗ if (!found)
161 ✗ qDebug() << "Could not find body tree item parent" << groupName.c_str()
162 << "of" << nodeName.c_str();
163 }
164 ✗ return ret;
165 }
166
167 ✗ bool WindowsManager::deleteNode(const std::string& nodeName, bool all) {
168 ✗ bool ret = Parent_t::deleteNode(nodeName, all);
169 ✗ if (ret) deleteBodyItem(nodeName);
170 ✗ return ret;
171 }
172
173 ✗ BodyTreeItems_t WindowsManager::bodyTreeItems(const std::string& name) const {
174 ✗ BodyTreeItemMap_t::const_iterator _btis = nodeItemMap_.find(name);
175 ✗ if (_btis != nodeItemMap_.end()) return _btis->second.first;
176 ✗ return BodyTreeItems_t();
177 }
178
179 ✗ void WindowsManager::deleteBodyItem(const std::string& nodeName) {
180 ✗ BodyTreeItemMap_t::iterator _nodes = nodeItemMap_.find(nodeName);
181 ✗ assert(_nodes != nodeItemMap_.end());
182 ✗ for (std::size_t i = 0; i < _nodes->second.first.size(); ++i) {
183 ✗ BodyTreeItem* bti = _nodes->second.first[i];
184 ✗ QStandardItem* parent = bti->QStandardItem::parent();
185 ✗ if (parent == NULL) {
186 ✗ bodyTree_->model()->takeRow(bti->row());
187 } else {
188 ✗ parent->takeRow(bti->row());
189 }
190 ✗ bti->deleteLater();
191 ✗ _nodes->second.first[i] = NULL;
192 }
193 ✗ nodeItemMap_.erase(_nodes);
194 }
195
196 ✗ bool WindowsManager::initParent(NodePtr_t node, GroupNodePtr_t parent,
197 bool isGroup) {
198 BodyTreeItemMap_t::const_iterator _groups =
199 ✗ nodeItemMap_.find(parent->getID());
200 ✗ if (_groups != nodeItemMap_.end() && _groups->second.second) {
201 ✗ assert(!_groups->second.first.empty());
202 ✗ addToGroup(node->getID(), parent->getID(), node, _groups->second.first,
203 isGroup);
204 ✗ return true;
205 }
206 ✗ return false;
207 }
208
209 ✗ void WindowsManager::captureFrame(const WindowID wid,
210 const std::string& filename) {
211 ✗ WindowManagerPtr_t wm = getWindowManager(wid, true);
212 ✗ OSGWidget* widget = widgets_[wid];
213 ✗ assert(widget->windowID() == wid);
214 // Here, it is not requred that invokeMethod is blocking. However, it may
215 // be suprising in user script to have this call done later...
216 ✗ QMetaObject::invokeMethod(widget, "captureFrame",
217 connectionType(widget, true),
218 ✗ Q_ARG(std::string, filename));
219 }
220
221 ✗ bool WindowsManager::startCapture(const WindowID wid,
222 const std::string& filename,
223 const std::string& extension) {
224 ✗ WindowManagerPtr_t wm = getWindowManager(wid, true);
225 ✗ OSGWidget* widget = widgets_[wid];
226 ✗ assert(widget->windowID() == wid);
227 bool res;
228 ✗ QMetaObject::invokeMethod(
229 widget, "startCapture", connectionType(widget, true),
230 ✗ Q_RETURN_ARG(bool, res), Q_ARG(std::string, filename),
231 ✗ Q_ARG(std::string, extension));
232 ✗ return res;
233 }
234
235 ✗ bool WindowsManager::stopCapture(const WindowID wid) {
236 ✗ WindowManagerPtr_t wm = getWindowManager(wid, true);
237 ✗ OSGWidget* widget = widgets_[wid];
238 ✗ assert(widget->windowID() == wid);
239 bool res;
240 ✗ QMetaObject::invokeMethod(widget, "stopCapture", connectionType(widget, true),
241 ✗ Q_RETURN_ARG(bool, res));
242 ✗ return res;
243 }
244
245 struct ApplyConfigurationFunctor {
246 ✗ void operator()(const viewer::NodeConfiguration& nc) const {
247 ✗ nc.node->applyConfiguration(nc);
248 }
249 };
250
251 ✗ void WindowsManager::refresh() {
252 ✗ if (refreshIsSynchronous_) {
253 {
254 ✗ ScopedLock lock(configListMtx_);
255 {
256 ✗ ScopedLock lock(osgFrameMutex());
257 // refresh scene with the new configuration
258 ✗ std::for_each(newNodeConfigurations_.begin(),
259 newNodeConfigurations_.end(),
260 ApplyConfigurationFunctor());
261 }
262 ✗ newNodeConfigurations_.resize(0);
263 }
264 ✗ if (autoCaptureTransform_) captureTransform();
265 } else {
266 {
267 ✗ ScopedLock lock1(configsAsyncMtx_);
268 ✗ ScopedLock lock2(configListMtx_);
269 ✗ if (configsAsync_.size() == 0) {
270 ✗ configsAsync_.swap(newNodeConfigurations_);
271 ✗ QMetaObject::invokeMethod(this, "asyncRefresh", Qt::QueuedConnection);
272 } else {
273 ✗ configsAsync_.insert(configsAsync_.end(),
274 newNodeConfigurations_.begin(),
275 newNodeConfigurations_.end());
276 ✗ newNodeConfigurations_.resize(0);
277 // No need to reinvoke asyncRefresh as it hasn't been ran yet.
278 }
279 }
280 }
281 }
282
283 ✗ void WindowsManager::asyncRefresh() {
284 ✗ NodeConfigurations_t& cfgs = configsAsync_;
285 {
286 ✗ ScopedLock lock(configsAsyncMtx_);
287 {
288 ✗ ScopedLock lock(osgFrameMutex());
289 // refresh scene with the new configuration
290 ✗ std::for_each(cfgs.begin(), cfgs.end(), ApplyConfigurationFunctor());
291 }
292 ✗ cfgs.resize(0);
293 }
294 ✗ if (autoCaptureTransform_) captureTransform();
295 }
296
297 ✗ void WindowsManager::setRefreshIsSynchronous(bool synchonous) {
298 ✗ refreshIsSynchronous_ = synchonous;
299 }
300 } // namespace gui
301 } // namespace gepetto
302