GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gui/mainwindow.cc Lines: 1 321 0.3 %
Date: 2020-05-14 11:23:33 Branches: 2 774 0.3 %

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

3
} // namespace gepetto