GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gui/mainwindow.cc Lines: 0 342 0.0 %
Date: 2023-03-14 11:04:37 Branches: 0 728 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