GCC Code Coverage Report


Directory: ./
File: src/gui/mainwindow.cc
Date: 2024-10-14 11:04:13
Exec Total Coverage
Lines: 0 347 0.0%
Branches: 0 674 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/mainwindow.hh"
18
19 #include <QMessageBox>
20 #include <QScrollBar>
21 #include <QtGlobal>
22 #include <sstream>
23
24 #include "ui_mainwindow.h"
25 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
26 #include <QtConcurrent>
27 #endif
28
29 #include <gepetto/gui/config-dep.hh>
30 #include <osg/Version>
31
32 #include "gepetto/gui/action-search-bar.hh"
33 #include "gepetto/gui/dialog/dialogloadenvironment.hh"
34 #include "gepetto/gui/dialog/dialogloadrobot.hh"
35 #include "gepetto/gui/node-action.hh"
36 #include "gepetto/gui/osgwidget.hh"
37 #include "gepetto/gui/plugin-interface.hh"
38 #include "gepetto/gui/selection-handler.hh"
39 #include "gepetto/gui/shortcut-factory.hh"
40 #include "gepetto/gui/tree-item.hh"
41 #include "gepetto/gui/windows-manager.hh"
42
43 #if GEPETTO_GUI_HAS_PYTHONQT
44 #include <gepetto/gui/pythonwidget.hh>
45 #endif
46
47 #include "../log.hh"
48
49 namespace gepetto {
50 namespace gui {
51 MainWindow* MainWindow::instance_ = NULL;
52
53 MainWindow::MainWindow(Settings* settings, QWidget* parent)
54 : QMainWindow(parent),
55 settings_(settings),
56 ui_(new ::Ui::MainWindow),
57 centralWidget_(),
58 osgViewerManagers_(),
59 worker_(),
60 actionSearchBar_(new ActionSearchBar(this)) {
61 MainWindow::instance_ = this;
62 ui_->setupUi(this);
63
64 // Setup the body tree view
65 osgViewerManagers_ = WindowsManager::create(ui_->bodyTreeContent);
66 ui_->bodyTreeContent->init(ui_->bodyTree, ui_->propertyArea);
67
68 // This scene contains elements required for User Interaction.
69 osg()->createScene("gepetto-gui");
70 // TODO remove me. This is kept for backward compatibility
71 osg()->createScene("hpp-gui");
72
73 // Setup the main OSG widget
74 connect(ui_->actionRefresh, SIGNAL(triggered()), SLOT(requestRefresh()));
75
76 collisionLabel_ = new QLabel("No collisions.");
77 shortcutFactory_ = new ShortcutFactory;
78 #if GEPETTO_GUI_HAS_PYTHONQT
79 pythonWidget_ = new PythonWidget(this);
80 #endif
81 setupInterface();
82 connect(ui_->actionChange_shortcut, SIGNAL(triggered()), shortcutFactory_,
83 SLOT(open()));
84
85 selectionHandler_ = new SelectionHandler(osgViewerManagers_);
86 selectionHandler_->addMode(new MultiSelection(osgViewerManagers_));
87 selectionHandler_->addMode(new UniqueSelection(osgViewerManagers_));
88
89 ui_->mainToolBar->addWidget(selectionHandler_);
90 }
91
92 MainWindow::~MainWindow() {
93 delete shortcutFactory_;
94 #if GEPETTO_GUI_HAS_PYTHONQT
95 removeDockWidget(pythonWidget_);
96 delete pythonWidget_;
97 #endif
98 pluginManager()->clearPlugins();
99 osgViewerManagers_.reset();
100 worker_.quit();
101 worker_.wait();
102 delete ui_;
103 }
104
105 MainWindow* MainWindow::instance() { return instance_; }
106
107 void MainWindow::insertDockWidget(QDockWidget* dock, Qt::DockWidgetArea area,
108 Qt::Orientation orientation) {
109 addDockWidget(area, dock, orientation);
110 dock->setVisible(false);
111 dock->toggleViewAction()->setIcon(QIcon::fromTheme("window-new"));
112 dock->adjustSize();
113 ui_->menuWindow->addAction(dock->toggleViewAction());
114 actionSearchBar_->addAction(dock->toggleViewAction());
115 connect(dock, SIGNAL(visibilityChanged(bool)),
116 SLOT(dockVisibilityChanged(bool)));
117 }
118
119 void MainWindow::removeDockWidget(QDockWidget* dock) {
120 ui_->menuWindow->removeAction(dock->toggleViewAction());
121 disconnect(dock);
122 QMainWindow::removeDockWidget(dock);
123 }
124
125 WindowsManagerPtr_t MainWindow::osg() const { return osgViewerManagers_; }
126
127 BodyTreeWidget* MainWindow::bodyTree() const { return ui_->bodyTreeContent; }
128
129 QList<OSGWidget*> MainWindow::osgWindows() const { return osgWindows_; }
130
131 PluginManager* MainWindow::pluginManager() {
132 return &(settings_->pluginManager_);
133 }
134
135 ActionSearchBar* MainWindow::actionSearchBar() const {
136 return actionSearchBar_;
137 }
138
139 void MainWindow::log(const QString& text) {
140 if (thread() != QThread::currentThread()) {
141 emit logString(text);
142 return;
143 }
144 ui_->logText->insertHtml("<hr/><font color=black>" + text + "</font>");
145 }
146
147 void MainWindow::logError(const QString& text) {
148 if (thread() != QThread::currentThread()) {
149 emit logErrorString(text);
150 return;
151 }
152 if (!ui_->dockWidget_log->isVisible()) {
153 ui_->dockWidget_log->show();
154 }
155 QScrollBar* sb = ui_->logText->verticalScrollBar();
156 bool SBwasAtBottom = sb->value() == sb->maximum();
157 ui_->logText->insertHtml("<hr/><font color=red>" + text + "</font>");
158 if (SBwasAtBottom) sb->setValue(sb->maximum());
159 }
160
161 QMenu* MainWindow::pluginMenu() const { return ui_->menuWindow; }
162
163 void MainWindow::logJobStarted(int id, const QString& text) {
164 emit logString(QString("Starting job ") + QString::number(id) + ": " + text);
165 }
166
167 void MainWindow::logJobDone(int id, const QString& text) {
168 emit logString(QString("Job ") + QString::number(id) + " done: " + text);
169 }
170
171 void MainWindow::logJobFailed(int id, const QString& text) {
172 emit logErrorString(QString("Job ") + QString::number(id) +
173 " failed: " + text);
174 }
175
176 OSGWidget* MainWindow::createView(const std::string& name) {
177 if (thread() != QThread::currentThread()) {
178 qDebug() << "createView must be called from the main thread.";
179 throw std::runtime_error("Cannot create a new window.");
180 }
181 OSGWidget* osgWidget = new OSGWidget(osgViewerManagers_, name, this, 0
182 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
183 ,
184 osgViewer::Viewer::SingleThreaded
185 #endif
186 );
187 osgWidget->setObjectName(name.c_str());
188 addOSGWidget(osgWidget);
189 emit viewCreated(osgWidget);
190 return osgWidget;
191 }
192
193 void MainWindow::requestRefresh() { emit refresh(); }
194
195 void MainWindow::createDefaultView() {
196 std::stringstream ss;
197 ss << "View " << osgWindows_.size();
198 createView(ss.str());
199 }
200
201 void MainWindow::addOSGWidget(OSGWidget* osgWidget) {
202 QDockWidget* dockOSG =
203 new QDockWidget(tr("Window ") + osgWidget->objectName(), this);
204 dockOSG->setObjectName("gepetto-gui.osg." + osgWidget->objectName());
205 dockOSG->setWidget(osgWidget);
206 dockOSG->setSizePolicy(QSizePolicy::MinimumExpanding,
207 QSizePolicy::MinimumExpanding);
208 // TODO at the moment, when the widget is made floating and then non-floating
209 // again, the OSGWidget becomes hidden. I could not find the bug so I removed
210 // the feature DockWidgetFloatable.
211 dockOSG->setFeatures(QDockWidget::DockWidgetClosable |
212 QDockWidget::DockWidgetMovable);
213 connect(dockOSG, SIGNAL(visibilityChanged(bool)),
214 SLOT(dockVisibilityChanged(bool)));
215 addDockWidget(Qt::RightDockWidgetArea, dockOSG);
216 if (osgWindows_.empty()) {
217 // This OSGWidget should be the central view
218 centralWidget_ = osgWidget;
219 osg()->addSceneToWindow("gepetto-gui", centralWidget_->windowID());
220 // TODO remove me. This is kept for backward compatibility
221 osg()->addSceneToWindow("hpp-gui", centralWidget_->windowID());
222 }
223 actionSearchBar_->addAction(new NodeAction(
224 "Attach camera " + osgWidget->objectName() + " to selected node",
225 osgWidget, this));
226 osgWidget->addAction(actionSearchBar_->showAction());
227 osgWindows_.append(osgWidget);
228 settings_->restoreDockWidgetsState();
229 // When creating a window from Python, it isn't desirable to create a
230 // hidden window. We overwrite the visibility.
231 dockOSG->show();
232
233 // Add the widget to the window list.
234 QMenu* views3D = ui_->menuWindow->findChild<QMenu*>("3d views"
235 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
236 ,
237 Qt::FindDirectChildrenOnly
238 #endif
239 );
240 views3D->addAction(dockOSG->toggleViewAction());
241 }
242
243 void MainWindow::openLoadRobotDialog() {
244 statusBar()->showMessage("Loading a robot...");
245 DialogLoadRobot* d = new DialogLoadRobot(this);
246 if (d->exec() == QDialog::Accepted) {
247 createCentralWidget();
248 DialogLoadRobot::RobotDefinition rd = d->getSelectedRobotDescription();
249
250 QString urdfFile = QString("package://%1/urdf/%2%3.urdf")
251 .arg(rd.package_)
252 .arg(rd.modelName_)
253 .arg(rd.urdfSuf_);
254 try {
255 osgViewerManagers_->addURDF(rd.robotName_.toStdString(),
256 urdfFile.toStdString());
257 osgViewerManagers_->addSceneToWindow(rd.robotName_.toStdString(),
258 centralWidget_->windowID());
259 } catch (std::runtime_error& exc) {
260 logError(exc.what());
261 }
262 robotNames_.append(rd.robotName_);
263
264 QString what = QString("Loading robot ") + rd.name_;
265 foreach (ModelInterface* loader, pluginManager()->get<ModelInterface>()) {
266 QtConcurrent::run(loader, &ModelInterface::loadRobotModel, rd);
267 logString(what);
268 }
269 }
270 d->close();
271 statusBar()->clearMessage();
272 d->deleteLater();
273 }
274
275 void MainWindow::openLoadEnvironmentDialog() {
276 statusBar()->showMessage("Loading an environment...");
277 DialogLoadEnvironment* e = new DialogLoadEnvironment(this);
278 if (e->exec() == QDialog::Accepted) {
279 createCentralWidget();
280 DialogLoadEnvironment::EnvironmentDefinition ed =
281 e->getSelectedDescription();
282
283 QString urdfFile = QString("package://%1/urdf/%2.urdf")
284 .arg(ed.package_)
285 .arg(ed.urdfFilename_);
286 try {
287 osgViewerManagers_->addUrdfObjects(ed.envName_.toStdString(),
288 urdfFile.toStdString(), true);
289 osgViewerManagers_->addSceneToWindow(ed.envName_.toStdString(),
290 centralWidget_->windowID());
291 } catch (std::runtime_error& exc) {
292 log(exc.what());
293 }
294
295 QString what = QString("Loading environment ") + ed.name_;
296 foreach (ModelInterface* loader, pluginManager()->get<ModelInterface>()) {
297 QtConcurrent::run(loader, &ModelInterface::loadEnvironmentModel, ed);
298 logString(what);
299 }
300 }
301 statusBar()->clearMessage();
302 e->close();
303 e->deleteLater();
304 }
305
306 void MainWindow::handleWorkerDone(int /*id*/) {}
307
308 void MainWindow::resetConnection() {
309 foreach (ConnectionInterface* e,
310 pluginManager()->get<ConnectionInterface>()) {
311 e->openConnection();
312 }
313 }
314
315 void MainWindow::closeConnection() {
316 foreach (ConnectionInterface* e,
317 pluginManager()->get<ConnectionInterface>()) {
318 e->closeConnection();
319 }
320 }
321
322 #define _to_str_(a) #a
323 #define _to_str(a) _to_str_(a)
324 #define _osg_version_str \
325 _to_str(OPENSCENEGRAPH_MAJOR_VERSION) "." _to_str( \
326 OPENSCENEGRAPH_MINOR_VERSION) "." _to_str(OPENSCENEGRAPH_PATCH_VERSION)
327
328 void MainWindow::about() {
329 QString devString;
330 devString =
331 trUtf8(
332 "<p>Version %1. For more information visit <a href=\"%2\">%2</a></p>"
333 "<p><ul>"
334 "<li>Compiled with Qt %3, run with Qt %4</li>"
335 "<li>Compiled with OpenSceneGraph version " _osg_version_str
336 ", run with version %5</li>"
337 #if GEPETTO_GUI_HAS_PYTHONQT
338 "<li>Compiled with PythonQt.</li>"
339 #else
340 "<li>Compiled without PythonQt</li>"
341 #endif
342 "<li></li>"
343 "<li></li>"
344 "</ul></p>"
345 "<p><small>Copyright (c) 2013-2020 CNRS<br/>By Joseph Mirabel and "
346 "others.</small></p>"
347 "<p><small>"
348 "BSD 2-Clause License<br/>"
349 "All rights reserved.<br/><br/>"
350 "Redistribution and use in source and binary forms, with or without"
351 "modification, are permitted provided that the following conditions "
352 "are met:"
353 "<ol><li>Redistributions of source code must retain the above "
354 "copyright notice, this"
355 "list of conditions and the following disclaimer.</li>"
356 "<li>Redistributions in binary form must reproduce the above "
357 "copyright notice,"
358 "this list of conditions and the following disclaimer in the "
359 "documentation"
360 "and/or other materials provided with the distribution.</li></ol>"
361 "</small></p>")
362 .arg(QApplication::applicationVersion())
363 .arg(QApplication::organizationDomain())
364 .arg(QT_VERSION_STR)
365 .arg(qVersion())
366 .arg(osgGetVersion());
367
368 QMessageBox::about(this, QApplication::applicationName(), devString);
369 }
370
371 #undef _to_str
372 #undef _osg_version_str
373
374 void MainWindow::activateCollision(bool activate) {
375 if (activate) {
376 requestConfigurationValidation();
377 foreach (QString b, lastBodiesInCollision_) {
378 osg()->setHighlight(b.toLocal8Bit().data(), 1);
379 }
380 } else {
381 foreach (QString b, lastBodiesInCollision_) {
382 osg()->setHighlight(b.toLocal8Bit().data(), 0);
383 }
384 collisionIndicator_->switchLed(true);
385 collisionLabel_->setText("No collisions.");
386 }
387 }
388
389 void MainWindow::dockVisibilityChanged(bool visible) {
390 QWidget* cw = centralWidget();
391 if (visible && cw->isVisible())
392 cw->hide();
393 else {
394 const QObjectList& objs = children();
395 foreach (const QObject* obj, objs) {
396 const QDockWidget* dock = qobject_cast<const QDockWidget*>(obj);
397 if (dock != 0 && dock->isVisible()) return;
398 }
399 cw->show();
400 }
401 }
402
403 void MainWindow::hsplitTabifiedDockWidget() {
404 splitTabifiedDockWidget(Qt::Horizontal);
405 }
406
407 void MainWindow::vsplitTabifiedDockWidget() {
408 splitTabifiedDockWidget(Qt::Vertical);
409 }
410
411 QDockWidget* getParentDockWidget(QObject* child) {
412 QDockWidget* dock = NULL;
413 while (child != NULL) {
414 dock = qobject_cast<QDockWidget*>(child);
415 if (dock != NULL) break;
416 child = child->parent();
417 }
418 return dock;
419 }
420
421 void MainWindow::splitTabifiedDockWidget(Qt::Orientation orientation) {
422 // QDockWidget focused
423 QDockWidget* dock = getParentDockWidget(QApplication::focusWidget());
424 if (dock == NULL) return;
425 // QDockWidget under cursor
426 QDockWidget* other =
427 getParentDockWidget(QApplication::widgetAt(QCursor::pos()));
428 if (other == NULL) return;
429 if (other == dock) return;
430 splitDockWidget(dock, other, orientation);
431 }
432
433 void MainWindow::setupInterface() {
434 // Menu "Window/Tool bar"
435 QMenu* toolbar = ui_->menuWindow->addMenu("Tool bar");
436 toolbar->setIcon(QIcon::fromTheme("configure-toolbars"));
437 ui_->mainToolBar->setVisible(true);
438 toolbar->addAction(ui_->mainToolBar->toggleViewAction());
439
440 ui_->menuWindow->addSeparator();
441
442 // Menu "Window/3D views"
443 QMenu* views3D = ui_->menuWindow->addMenu("3D views");
444 views3D->setObjectName("3d views");
445
446 ui_->menuWindow->addSeparator();
447
448 // Menu "Window"
449 ui_->dockWidget_bodyTree->setVisible(false);
450 ui_->dockWidget_bodyTree->toggleViewAction()->setIcon(
451 QIcon::fromTheme("window-new"));
452 ui_->dockWidget_bodyTree->toggleViewAction()->setShortcut(Qt::CTRL + Qt::ALT +
453 Qt::Key_B);
454 ui_->menuWindow->addAction(ui_->dockWidget_bodyTree->toggleViewAction());
455 ui_->dockWidget_log->setVisible(false);
456 ui_->dockWidget_log->toggleViewAction()->setIcon(
457 QIcon::fromTheme("window-new"));
458 ui_->dockWidget_log->toggleViewAction()->setShortcut(Qt::CTRL + Qt::ALT +
459 Qt::Key_L);
460 ui_->menuWindow->addAction(ui_->dockWidget_log->toggleViewAction());
461 #if GEPETTO_GUI_HAS_PYTHONQT
462 insertDockWidget(pythonWidget_, Qt::BottomDockWidgetArea, Qt::Horizontal);
463 registerShortcut("Python console", "Toggle view",
464 pythonWidget_->toggleViewAction());
465 #endif
466
467 // Add QActions to split dock widgets
468 QAction* vsplit = new QAction("Split focused dock widget vertically", this);
469 vsplit->setShortcut(Qt::CTRL + Qt::Key_S);
470 addAction(vsplit);
471 connect(vsplit, SIGNAL(triggered()), SLOT(vsplitTabifiedDockWidget()));
472 QAction* hsplit = new QAction("Split focused dock widget horizontally", this);
473 hsplit->setShortcut(Qt::CTRL + Qt::Key_H);
474 addAction(hsplit);
475 connect(hsplit, SIGNAL(triggered()), SLOT(hsplitTabifiedDockWidget()));
476
477 registerShortcut("Log widget", "Toggle view",
478 ui_->dockWidget_log->toggleViewAction());
479 registerShortcut("Body tree widget", "Toggle view",
480 ui_->dockWidget_bodyTree->toggleViewAction());
481 registerShortcut("Main window", ui_->actionLoad_robot_from_file);
482 registerShortcut("Main window", ui_->actionLoad_environment);
483 registerShortcut("Main window", ui_->actionChange_shortcut);
484 registerShortcut("Main window", ui_->actionQuit);
485 registerShortcut("Main window", ui_->actionReconnect);
486 registerShortcut("Main window", ui_->actionRefresh);
487 registerShortcut("Main window", ui_->actionPlugins);
488 registerShortcut("Main window", vsplit);
489 registerShortcut("Main window", hsplit);
490
491 ui_->menuWindow->addSeparator();
492
493 // Setup the status bar
494 collisionIndicator_ = new LedIndicator(statusBar());
495 collisionValidationActivated_ = new QCheckBox();
496 collisionValidationActivated_->setToolTip(
497 tr("Automatically validate configurations."));
498 collisionValidationActivated_->setCheckState(Qt::Checked);
499 statusBar()->addPermanentWidget(collisionLabel_);
500 statusBar()->addPermanentWidget(collisionValidationActivated_);
501 statusBar()->addPermanentWidget(collisionIndicator_);
502
503 connect(collisionValidationActivated_, SIGNAL(clicked(bool)),
504 SLOT(activateCollision(bool)));
505 connect(collisionIndicator_, SIGNAL(mouseClickEvent()),
506 SLOT(requestConfigurationValidation()));
507 connect(ui_->actionAbout, SIGNAL(triggered()), SLOT(about()));
508 connect(ui_->actionReconnect, SIGNAL(triggered()), SLOT(resetConnection()));
509 connect(ui_->actionClose_connections, SIGNAL(triggered()),
510 SLOT(closeConnection()));
511
512 connect(this, SIGNAL(logString(QString)), SLOT(log(QString)));
513 connect(this, SIGNAL(logErrorString(QString)), SLOT(logError(QString)));
514
515 actionSearchBar_->addAction(
516 new NodeAction(NodeAction::VISIBILITY_ON, "Show node", this));
517 actionSearchBar_->addAction(
518 new NodeAction(NodeAction::VISIBILITY_OFF, "Hide node", this));
519 actionSearchBar_->addAction(
520 new NodeAction(NodeAction::ALWAYS_ON_TOP, "Always on top", this));
521 actionSearchBar_->addAction(
522 new NodeAction(NodeAction::REMOVE_NODE, "Remove node", this));
523 actionSearchBar_->addAction(ui_->actionFetch_configuration);
524 actionSearchBar_->addAction(ui_->actionSend_configuration);
525 actionSearchBar_->addAction(ui_->actionClose_connections);
526 actionSearchBar_->addAction(ui_->actionReconnect);
527 actionSearchBar_->addAction(ui_->actionRefresh);
528 }
529
530 void MainWindow::createCentralWidget() {
531 if (!osgWindows_.empty()) return;
532 createDefaultView();
533 }
534
535 void MainWindow::requestApplyCurrentConfiguration() {
536 emit applyCurrentConfiguration();
537 if (collisionValidationActivated_->isChecked())
538 requestConfigurationValidation();
539 }
540
541 void MainWindow::requestConfigurationValidation() {
542 emit configurationValidation();
543 }
544
545 void MainWindow::onOpenPluginManager() {
546 PluginManagerDialog d(pluginManager(), this);
547 d.exec();
548 }
549
550 void MainWindow::registerSignal(const char* signal, QObject* obj) {
551 if (registeredSignals_.find(signal) == registeredSignals_.end()) {
552 registeredSignals_[signal] = obj;
553 gepetto::log() << signal << " registered" << std::endl;
554 } else
555 gepetto::log() << "Signal" << signal << "already registered." << std::endl;
556 }
557
558 QObject* MainWindow::getFromSignal(const char* signal) {
559 if (registeredSignals_.find(signal) == registeredSignals_.end()) {
560 #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
561 gepetto::log() << "signal " << signal << "isn't registered" << std::endl;
562 #endif
563 return NULL;
564 }
565 return registeredSignals_[signal];
566 }
567
568 void MainWindow::connectSignal(const char* signal, const char* slot,
569 QObject* obj) {
570 QObject* obj_sig = getFromSignal(signal);
571 if (obj_sig != NULL) {
572 QObject::connect(obj_sig, signal, obj, slot);
573 }
574 }
575
576 void MainWindow::registerSlot(const char* slot, QObject* obj) {
577 if (registeredSlots_.find(slot) == registeredSlots_.end()) {
578 registeredSlots_[slot] = obj;
579 gepetto::log() << slot << " registered" << std::endl;
580 } else
581 gepetto::log() << "Slot " << slot << "already registered." << std::endl;
582 }
583
584 QObject* MainWindow::getFromSlot(const char* slot) {
585 if (registeredSlots_.find(slot) == registeredSlots_.end()) {
586 gepetto::log() << "slot" << slot << "isn't registered" << std::endl;
587 return NULL;
588 }
589 return registeredSlots_[slot];
590 }
591
592 void MainWindow::connectSlot(const char* slot, const char* signal,
593 QObject* obj) {
594 if (registeredSlots_.find(slot) != registeredSlots_.end()) {
595 QObject::connect(obj, signal, registeredSlots_[slot], slot);
596 }
597 }
598
599 void MainWindow::registerShortcut(QString widgetName, QString actionName,
600 QAction* action) {
601 shortcutFactory_->addBinding(widgetName, actionName, action);
602 }
603
604 void MainWindow::registerShortcut(QString widgetName, QAction* action) {
605 shortcutFactory_->addBinding(widgetName, action->text(), action);
606 }
607
608 void MainWindow::configurationValidationStatusChanged(bool valid) {
609 collisionIndicator_->switchLed(valid);
610 int state = (valid) ? 0 : 1;
611 foreach (const QString& s, robotNames_) {
612 osg()->setHighlight(s.toLocal8Bit().data(), state);
613 }
614 }
615
616 void MainWindow::configurationValidationStatusChanged(
617 QStringList bodiesInCollision) {
618 QStringList lastBodiesInCollision = lastBodiesInCollision_;
619 lastBodiesInCollision_.clear();
620 collisionIndicator_->switchLed(bodiesInCollision.empty());
621 foreach (QString b, lastBodiesInCollision) {
622 if (bodiesInCollision.removeAll(b) == 0) {
623 /// This body is not in collision
624 osg()->setHighlight(b.toLocal8Bit().data(), 0);
625 } else {
626 /// This body is still in collision
627 lastBodiesInCollision_.append(b);
628 }
629 }
630 QString tooltip("Collision between ");
631 foreach (const QString& b, bodiesInCollision) {
632 osg()->setHighlight(b.toLocal8Bit().data(), 1);
633 lastBodiesInCollision_.append(b);
634 }
635 tooltip += lastBodiesInCollision_.join(", ");
636 if (lastBodiesInCollision_.count() > 0)
637 collisionLabel_->setText(tooltip);
638 else
639 collisionLabel_->setText("No collisions.");
640 }
641
642 void MainWindow::requestSelectJointFromBodyName(const QString bodyName) {
643 emit selectJointFromBodyName(bodyName);
644 }
645 } // namespace gui
646 } // namespace gepetto
647