MainWindow.cc 43 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    QGROUNDCONTROL is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

pixhawk's avatar
pixhawk committed
22 23 24 25
======================================================================*/

/**
 * @file
26
 *   @brief Implementation of class MainWindow
27
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
pixhawk's avatar
pixhawk committed
28 29 30 31 32 33 34 35 36 37
 */

#include <QSettings>
#include <QDockWidget>
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>
#include <QHostInfo>

38
#include "QGC.h"
pixhawk's avatar
pixhawk committed
39 40 41 42 43
#include "MAVLinkSimulationLink.h"
#include "SerialLink.h"
#include "UDPLink.h"
#include "MAVLinkProtocol.h"
#include "CommConfigurationWindow.h"
44
#include "QGCWaypointListMulti.h"
pixhawk's avatar
pixhawk committed
45 46
#include "MainWindow.h"
#include "JoystickWidget.h"
pixhawk's avatar
pixhawk committed
47
#include "GAudioOutput.h"
48
#include "QGCToolWidget.h"
49
#include "QGCMAVLinkLogPlayer.h"
50
#include "QGCSettingsWidget.h"
51
#include "QGCMapTool.h"
LM's avatar
LM committed
52
#include "MAVLinkDecoder.h"
53

54
#ifdef QGC_OSG_ENABLED
55
#include "Q3DWidgetFactory.h"
56
#endif
pixhawk's avatar
pixhawk committed
57

lm's avatar
lm committed
58 59 60 61
// FIXME Move
#include "PxQuadMAV.h"
#include "SlugsMAV.h"

pixhawk's avatar
pixhawk committed
62

63
#include "LogCompressor.h"
pixhawk's avatar
pixhawk committed
64

65 66
MainWindow* MainWindow::instance()
{
67
    static MainWindow* _instance = 0;
68 69
    if(_instance == 0)
    {
70
        _instance = new MainWindow();
71

72
        /* Set the application as parent to ensure that this object
73
                 * will be destroyed when the main application exits */
74 75 76
        //_instance->setParent(qApp);
    }
    return _instance;
77 78
}

pixhawk's avatar
pixhawk committed
79 80 81 82 83 84 85
/**
* Create new mainwindow. The constructor instantiates all parts of the user
* interface. It does NOT show the mainwindow. To display it, call the show()
* method.
*
* @see QMainWindow::show()
**/
86
MainWindow::MainWindow(QWidget *parent):
87 88 89 90 91 92
    QMainWindow(parent),
    currentView(VIEW_UNCONNECTED),
    aboutToCloseFlag(false),
    changingViewsFlag(false),
    styleFileName(QCoreApplication::applicationDirPath() + "/style-indoor.css"),
    autoReconnect(false),
93
    currentStyle(QGC_MAINWINDOW_STYLE_INDOOR),
94 95
    lowPowerMode(false),
    centerStackActionGroup(this)
pixhawk's avatar
pixhawk committed
96
{
97
    loadSettings();
98 99
    if (!settings.contains("CURRENT_VIEW"))
    {
100 101
        // Set this view as default view
        settings.setValue("CURRENT_VIEW", currentView);
102 103 104
    }
    else
    {
105 106 107
        // LOAD THE LAST VIEW
        VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
        if (currentViewCandidate != VIEW_ENGINEER &&
108
                currentViewCandidate != VIEW_OPERATOR &&
109 110 111
                currentViewCandidate != VIEW_PILOT &&
                currentViewCandidate != VIEW_FULL)
        {
112
            currentView = currentViewCandidate;
113
        }
114 115
    }

116 117
    settings.sync();

118 119 120
    // Setup UI state machines
    centerStackActionGroup.setExclusive(true);

pixhawk's avatar
pixhawk committed
121 122 123
    // Setup user interface
    ui.setupUi(this);

124 125
    centerStack = new QStackedWidget(this);
    setCentralWidget(centerStack);
126

127 128
    buildCommonWidgets();
    connectCommonWidgets();
129 130

    configureWindowName();
pixhawk's avatar
pixhawk committed
131

132
    loadStyle(currentStyle);
133

134
    // Create actions
135
    connectCommonActions();
136

137 138 139
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

lm's avatar
lm committed
140 141
    statusBar()->setSizeGripEnabled(true);

142 143 144 145 146 147
    // Restore the window setup
    if (settings.contains(getWindowStateKey()))
    {
        loadViewState();
    }

148
    // Restore the window position and size
149 150
    if (settings.contains(getWindowGeometryKey()))
    {
151
        // Restore the window geometry
152
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
153 154 155
    }
    else
    {
156 157 158
        // Adjust the size
        adjustSize();
    }
pixhawk's avatar
pixhawk committed
159

160 161
    // Populate link menu
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
162 163
    foreach(LinkInterface* link, links)
    {
164 165
        this->addLink(link);
    }
166

167 168
    connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));

169
    // Connect user interface devices
170 171
    joystickWidget = 0;
    joystick = new JoystickInput();
172

173 174 175 176 177 178 179 180
    // Load Toolbar
    toolBar = new QGCToolBar(this);
    this->addToolBar(toolBar);
    // Add actions
    toolBar->addPerspectiveChangeAction(ui.actionOperatorsView);
    toolBar->addPerspectiveChangeAction(ui.actionEngineersView);
    toolBar->addPerspectiveChangeAction(ui.actionPilotsView);

181
    // Connect link
182 183
    if (autoReconnect)
    {
184 185 186 187 188 189
        SerialLink* link = new SerialLink();
        // Add to registry
        LinkManager::instance()->add(link);
        LinkManager::instance()->addProtocol(link, mavlink);
        link->connect();
    }
190

191 192 193
    // Set low power mode
    enableLowPowerMode(lowPowerMode);

194 195
    // Initialize window state
    windowStateVal = windowState();
196 197

    show();
pixhawk's avatar
pixhawk committed
198 199
}

pixhawk's avatar
pixhawk committed
200
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
201
{
202
    delete mavlink;
203
    delete joystick;
lm's avatar
lm committed
204

205 206 207 208 209 210
    // Get and delete all dockwidgets and contained
    // widgets
    QObjectList childList( this->children() );

    QObjectList::iterator i;
    QDockWidget* dockWidget;
211 212
    for (i = childList.begin(); i != childList.end(); ++i)
    {
213
        dockWidget = dynamic_cast<QDockWidget*>(*i);
214 215
        if (dockWidget)
        {
216 217 218 219 220
            // Remove dock widget from main window
            removeDockWidget(dockWidget);
            delete dockWidget->widget();
            delete dockWidget;
        }
LM's avatar
LM committed
221 222 223 224
        else
        {
            delete dynamic_cast<QObject*>(*i);
        }
225 226
    }

LM's avatar
LM committed
227
    // Delete all UAS objects
228 229
}

lm's avatar
lm committed
230 231 232
void MainWindow::resizeEvent(QResizeEvent * event)
{
    Q_UNUSED(event);
233 234
    if (height() < 800)
    {
lm's avatar
lm committed
235
        ui.statusBar->setVisible(false);
236 237 238
    }
    else
    {
lm's avatar
lm committed
239
        ui.statusBar->setVisible(true);
240
        ui.statusBar->setSizeGripEnabled(true);
lm's avatar
lm committed
241 242 243
    }
}

244 245
QString MainWindow::getWindowStateKey()
{
246
    return QString::number(currentView)+"_windowstate";
247 248 249 250
}

QString MainWindow::getWindowGeometryKey()
{
251 252
    //return QString::number(currentView)+"_geometry";
    return "_geometry";
253 254
}

lm's avatar
lm committed
255 256 257
void MainWindow::buildCustomWidget()
{
    // Show custom widgets only if UAS is connected
258 259
    if (UASManager::instance()->getActiveUAS() != NULL)
    {
lm's avatar
lm committed
260 261 262
        // Create custom widgets
        QList<QGCToolWidget*> widgets = QGCToolWidget::createWidgetsFromSettings(this);

263 264
        if (widgets.size() > 0)
        {
lm's avatar
lm committed
265 266 267
            ui.menuTools->addSeparator();
        }

268 269
        for(int i = 0; i < widgets.size(); ++i)
        {
lm's avatar
lm committed
270
            // Check if this widget already has a parent, do not create it in this case
271 272
            QGCToolWidget* tool = widgets.at(i);
            QDockWidget* dock = dynamic_cast<QDockWidget*>(tool->parentWidget());
273 274
            if (!dock)
            {
275 276 277 278
                QDockWidget* dock = new QDockWidget(tool->windowTitle(), this);
                dock->setObjectName(tool->objectName()+"_DOCK");
                dock->setWidget(tool);
                connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
lm's avatar
lm committed
279
                QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this);
280
                showAction->setCheckable(true);
lm's avatar
lm committed
281 282 283 284
                connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
                connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
                widgets.at(i)->setMainMenuAction(showAction);
                ui.menuTools->addAction(showAction);
285 286 287 288 289

                // Load dock widget location (default is bottom)
                Qt::DockWidgetArea location = static_cast <Qt::DockWidgetArea>(tool->getDockWidgetArea(currentView));

                addDockWidget(location, dock);
lm's avatar
lm committed
290 291 292 293 294
            }
        }
    }
}

295 296 297 298
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
299
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
LM's avatar
LM committed
300 301
    // Add generic MAVLink decoder
    mavlinkDecoder = new MAVLinkDecoder(mavlink, this);
302 303

    // Dock widgets
304 305
    if (!controlDockWidget)
    {
306
        controlDockWidget = new QDockWidget(tr("Control"), this);
307
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
308
        controlDockWidget->setWidget( new UASControlWidget(this) );
309
        addTool(controlDockWidget, tr("Control"), Qt::LeftDockWidgetArea);
310
    }
311

312 313
    if (!listDockWidget)
    {
314 315
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
316
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
317
        addTool(listDockWidget, tr("Unmanned Systems"), Qt::RightDockWidgetArea);
318
    }
319

320 321
    if (!waypointsDockWidget)
    {
322
        waypointsDockWidget = new QDockWidget(tr("Mission Plan"), this);
323
        waypointsDockWidget->setWidget( new QGCWaypointListMulti(this) );
324
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
325
        addTool(waypointsDockWidget, tr("Mission Plan"), Qt::BottomDockWidgetArea);
326
    }
327

328 329
    if (!infoDockWidget)
    {
330 331
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
332
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
333
        addTool(infoDockWidget, tr("Status Details"), Qt::RightDockWidgetArea);
334
    }
335

336 337
    if (!debugConsoleDockWidget)
    {
338 339
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
340
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
LM's avatar
LM committed
341 342 343 344

        DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
        connect(mavlinkDecoder, SIGNAL(textMessageReceived(int, int, int, const QString)), debugConsole, SLOT(receiveTextMessage(int, int, int, const QString)));

345
        addTool(debugConsoleDockWidget, tr("Communication Console"), Qt::BottomDockWidgetArea);
346
    }
347

348 349
    if (!logPlayerDockWidget)
    {
350 351 352
        logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
        logPlayerDockWidget->setWidget( new QGCMAVLinkLogPlayer(mavlink, this) );
        logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
353
        addTool(logPlayerDockWidget, tr("MAVLink Log Replay"), Qt::RightDockWidgetArea);
354 355
    }

lm's avatar
lm committed
356 357 358 359 360
    if (!mavlinkInspectorWidget)
    {
        mavlinkInspectorWidget = new QDockWidget(tr("MAVLink Message Inspector"), this);
        mavlinkInspectorWidget->setWidget( new QGCMAVLinkInspector(mavlink, this) );
        mavlinkInspectorWidget->setObjectName("MAVLINK_INSPECTOR_DOCKWIDGET");
lm's avatar
lm committed
361
        addTool(mavlinkInspectorWidget, tr("MAVLink Inspector"), Qt::RightDockWidgetArea);
lm's avatar
lm committed
362 363
    }

364
    // Center widgets
365 366
    if (!mapWidget)
    {
367
        mapWidget = new QGCMapTool(this);
368
        addCentralWidget(mapWidget, "Maps");
369
    }
370

371 372
    if (!protocolWidget)
    {
373
        protocolWidget    = new XMLCommProtocolWidget(this);
374
        addCentralWidget(protocolWidget, "Mavlink Generator");
375
    }
lm's avatar
lm committed
376

377 378
    if (!dataplotWidget)
    {
lm's avatar
lm committed
379
        dataplotWidget    = new QGCDataPlot2D(this);
380
        addCentralWidget(dataplotWidget, "Logfile Plot");
lm's avatar
lm committed
381
    }
382

pixhawk's avatar
pixhawk committed
383 384
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
pixhawk's avatar
pixhawk committed
385 386 387
    acceptList->append("-105,roll deg,deg,+105,s");
    acceptList->append("-105,pitch deg,deg,+105,s");
    acceptList->append("-105,heading deg,deg,+105,s");
388

pixhawk's avatar
pixhawk committed
389 390 391
    acceptList->append("-60,rollspeed d/s,deg/s,+60,s");
    acceptList->append("-60,pitchspeed d/s,deg/s,+60,s");
    acceptList->append("-60,yawspeed d/s,deg/s,+60,s");
392
    acceptList->append("0,airspeed,m/s,30");
393 394
    acceptList->append("0,groundspeed,m/s,30");
    acceptList->append("0,climbrate,m/s,30");
395
    acceptList->append("0,throttle,%,100");
396

pixhawk's avatar
pixhawk committed
397 398
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
399 400 401
    acceptList2->append("900,servo #6,us,2100,s");
    acceptList2->append("900,servo #7,us,2100,s");
    acceptList2->append("900,servo #8,us,2100,s");
lm's avatar
lm committed
402
    acceptList2->append("0,abs pressure,hPa,65500");
403

404
    if (!hudWidget) {
405
        hudWidget         = new HUD(320, 240, this);
406
        addCentralWidget(hudWidget, tr("Head Up Display"));
lm's avatar
lm committed
407 408
    }

409
    if (!dataplotWidget) {
410
        dataplotWidget    = new QGCDataPlot2D(this);
411
        addCentralWidget(dataplotWidget, tr("Logfile Plot"));
412
    }
413

414
#ifdef QGC_OSG_ENABLED
415
    if (!_3DWidget) {
416
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
417
        addCentralWidget(_3DWidget, tr("Local 3D"));
418
    }
419
#endif
420

421
#if (defined _MSC_VER) | (defined Q_OS_MAC)
422
    if (!gEarthWidget) {
423
        gEarthWidget = new QGCGoogleEarthView(this);
424
        addCentralWidget(gEarthWidget, tr("Google Earth"));
425
    }
426
#endif
lm's avatar
lm committed
427
}
428

429
void MainWindow::addTool(QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
lm's avatar
lm committed
430
{
431
    QAction* tempAction = ui.menuTools->addAction(title);
432

433
    tempAction->setCheckable(true);
434 435 436 437
    QVariant var;
    var.setValue((QWidget*)widget);
    tempAction->setData(var);
    connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
LM's avatar
LM committed
438 439
    connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
    tempAction->setChecked(widget->isVisible());
440
    addDockWidget(area, widget);
441 442 443
}


444
void MainWindow::showTool(bool show)
lm's avatar
lm committed
445
{
446 447 448
    QAction* act = qobject_cast<QAction *>(sender());
    QWidget* widget = qVariantValue<QWidget *>(act->data());
    widget->setVisible(show);
449
}
450

451
void MainWindow::addCentralWidget(QWidget* widget, const QString& title)
lm's avatar
lm committed
452
{
453 454 455 456
    // Check if this widget already has been added
    if (centerStack->indexOf(widget) == -1)
    {
        centerStack->addWidget(widget);
457

458
        QAction* tempAction = ui.menuMain->addAction(title);
459

460 461 462 463 464 465
        tempAction->setCheckable(true);
        QVariant var;
        var.setValue((QWidget*)widget);
        tempAction->setData(var);
        centerStackActionGroup.addAction(tempAction);
        connect(tempAction,SIGNAL(triggered()),this, SLOT(showCentralWidget()));
LM's avatar
LM committed
466 467
        connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
        tempAction->setChecked(widget->isVisible());
468 469 470 471
    }
}


472
void MainWindow::showCentralWidget()
473
{
474 475 476
    QAction* act = qobject_cast<QAction *>(sender());
    QWidget* widget = qVariantValue<QWidget *>(act->data());
    centerStack->setCurrentWidget(widget);
477 478
}

479 480
void MainWindow::closeEvent(QCloseEvent *event)
{
pixhawk's avatar
pixhawk committed
481
    if (isVisible()) storeViewState();
482
    storeSettings();
483
    aboutToCloseFlag = true;
484
    mavlink->storeSettings();
485
    UASManager::instance()->storeSettings();
486 487
    QMainWindow::closeEvent(event);
}
488 489 490 491

/**
 * Connect the signals and slots of the common window widgets
 */
492
void MainWindow::connectCommonWidgets()
493
{
494
    if (infoDockWidget && infoDockWidget->widget()) {
pixhawk's avatar
pixhawk committed
495 496 497
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
498
}
499

500 501
void MainWindow::createCustomWidget()
{
502 503
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", dock);
lm's avatar
lm committed
504

LM's avatar
LM committed
505 506
    if (QGCToolWidget::instances()->size() < 2)
    {
lm's avatar
lm committed
507 508 509 510 511
        // This is the first widget
        ui.menuTools->addSeparator();
    }

    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
512
    dock->setWidget(tool);
513

514 515 516 517 518 519 520 521 522 523 524 525 526 527
    QAction* showAction = new QAction(tool->getTitle(), this);
    showAction->setCheckable(true);
    connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
    connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
    tool->setMainMenuAction(showAction);
    ui.menuTools->addAction(showAction);
    this->addDockWidget(Qt::BottomDockWidgetArea, dock);
    dock->setVisible(true);
}

void MainWindow::loadCustomWidget()
{
    QString widgetFileExtension(".qgw");
    QString fileName = QFileDialog::getOpenFileName(this, tr("Specify Widget File Name"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension));
528
    if (fileName != "") loadCustomWidget(fileName);
LM's avatar
LM committed
529
}
530

LM's avatar
LM committed
531 532 533 534
void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance)
{
    QGCToolWidget* tool = new QGCToolWidget("", this);
    if (tool->loadSettings(fileName, true) || !singleinstance)
LM's avatar
LM committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    {
        // Add widget to UI
        QDockWidget* dock = new QDockWidget(tool->getTitle(), this);
        connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
        dock->setWidget(tool);
        tool->setParent(dock);

        QAction* showAction = new QAction(tool->getTitle(), this);
        showAction->setCheckable(true);
        connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
        connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
        tool->setMainMenuAction(showAction);
        ui.menuTools->addAction(showAction);
        this->addDockWidget(Qt::BottomDockWidgetArea, dock);
        dock->setVisible(true);
    }
LM's avatar
LM committed
551 552 553
    else
    {
        return;
554
    }
555 556
}

LM's avatar
LM committed
557
void MainWindow::loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType)
558
{
LM's avatar
LM committed
559
    QString defaultsDir = qApp->applicationDirPath() + "/files/" + systemType.toLower() + "/" + autopilotType.toLower() + "/widgets/";
560

LM's avatar
LM committed
561 562 563 564 565 566
    QDir widgets(defaultsDir);
    QStringList files = widgets.entryList();
    if (files.count() == 0)
    {
        qDebug() << "No default custom widgets for system " << systemType << "autopilot" << autopilotType << " found";
        qDebug() << "Tried with path: " << defaultsDir;
lm's avatar
lm committed
567
        showStatusMessage(tr("Did not find any custom widgets in %1").arg(defaultsDir));
568
    }
569

LM's avatar
LM committed
570 571
    // Load all custom widgets found in the AP folder
    for(int i = 0; i < files.count(); ++i)
lm's avatar
lm committed
572
    {
LM's avatar
LM committed
573 574 575 576 577
        QString file = files[i];
        if (file.endsWith(".qgw"))
        {
            // Will only be loaded if not already a custom widget with
            // the same name is present
578
            loadCustomWidget(defaultsDir+"/"+file, true);
lm's avatar
lm committed
579
            showStatusMessage(tr("Loaded custom widget %1").arg(defaultsDir+"/"+file));
LM's avatar
LM committed
580
        }
lm's avatar
lm committed
581
    }
582 583
}

584 585 586 587 588 589
void MainWindow::loadSettings()
{
    QSettings settings;
    settings.beginGroup("QGC_MAINWINDOW");
    autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool();
    currentStyle = (QGC_MAINWINDOW_STYLE)settings.value("CURRENT_STYLE", currentStyle).toInt();
590
    lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool();
591 592 593 594 595 596 597 598 599 600
    settings.endGroup();
}

void MainWindow::storeSettings()
{
    QSettings settings;
    settings.beginGroup("QGC_MAINWINDOW");
    settings.setValue("AUTO_RECONNECT", autoReconnect);
    settings.setValue("CURRENT_STYLE", currentStyle);
    settings.endGroup();
pixhawk's avatar
pixhawk committed
601 602 603 604 605 606 607 608 609 610 611
    if (!aboutToCloseFlag && isVisible())
    {
        settings.setValue(getWindowGeometryKey(), saveGeometry());
        // Save the last current view in any case
        settings.setValue("CURRENT_VIEW", currentView);
        // Save the current window state, but only if a system is connected (else no real number of widgets would be present)
        if (UASManager::instance()->getUASList().length() > 0) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
        // Save the current view only if a UAS is connected
        if (UASManager::instance()->getUASList().length() > 0) settings.setValue("CURRENT_VIEW_WITH_UAS_CONNECTED", currentView);
        // Save the current power mode
    }
612
    settings.setValue("LOW_POWER_MODE", lowPowerMode);
613 614 615
    settings.sync();
}

616 617
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
618 619 620
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
621

pixhawk's avatar
pixhawk committed
622
    windowname.append(" (" + QHostInfo::localHostName() + ": ");
623

624 625
    for (int i = 0; i < hostAddresses.size(); i++)
    {
pixhawk's avatar
pixhawk committed
626
        // Exclude loopback IPv4 and all IPv6 addresses
627 628
        if (hostAddresses.at(i) != QHostAddress("127.0.0.1") && !hostAddresses.at(i).toString().contains(":"))
        {
pixhawk's avatar
pixhawk committed
629 630 631 632 633
            if(prevAddr) windowname.append("/");
            windowname.append(hostAddresses.at(i).toString());
            prevAddr = true;
        }
    }
634

pixhawk's avatar
pixhawk committed
635
    windowname.append(")");
636

pixhawk's avatar
pixhawk committed
637
    setWindowTitle(windowname);
638 639

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
640
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
641 642 643
#endif
}

pixhawk's avatar
pixhawk committed
644
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
645 646 647 648 649
{
    QString format = "bmp";
    QString initialPath = QDir::currentPath() + tr("/untitled.") + format;

    QString screenFileName = QFileDialog::getSaveFileName(this, tr("Save As"),
650 651 652 653
                             initialPath,
                             tr("%1 Files (*.%2);;All Files (*)")
                             .arg(format.toUpper())
                             .arg(format));
pixhawk's avatar
pixhawk committed
654 655
    delete videoTimer;
    videoTimer = new QTimer(this);
656 657 658
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
659 660
}

pixhawk's avatar
pixhawk committed
661
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
662 663 664 665 666 667
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
668
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
669 670 671 672
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

673 674
    if (!screenFileName.isEmpty())
    {
pixhawk's avatar
pixhawk committed
675 676 677 678
        window.save(screenFileName, format.toAscii());
    }
}

679
void MainWindow::enableAutoReconnect(bool enabled)
pixhawk's avatar
pixhawk committed
680
{
681 682
    autoReconnect = enabled;
}
683

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
void MainWindow::loadNativeStyle()
{
    loadStyle(QGC_MAINWINDOW_STYLE_NATIVE);
}

void MainWindow::loadIndoorStyle()
{
    loadStyle(QGC_MAINWINDOW_STYLE_INDOOR);
}

void MainWindow::loadOutdoorStyle()
{
    loadStyle(QGC_MAINWINDOW_STYLE_OUTDOOR);
}

void MainWindow::loadStyle(QGC_MAINWINDOW_STYLE style)
{
701 702 703 704 705 706 707 708 709
    switch (style) {
    case QGC_MAINWINDOW_STYLE_NATIVE: {
        // Native mode means setting no style
        // so if we were already in native mode
        // take no action
        // Only if a style was set, remove it.
        if (style != currentStyle) {
            qApp->setStyleSheet("");
            showInfoMessage(tr("Please restart QGroundControl"), tr("Please restart QGroundControl to switch to fully native look and feel. Currently you have loaded Qt's plastique style."));
710
        }
711 712
    }
    break;
713 714 715 716 717 718 719 720 721 722 723 724 725 726
    case QGC_MAINWINDOW_STYLE_INDOOR:
        qApp->setStyle("plastique");
        styleFileName = ":/images/style-mission.css";
        reloadStylesheet();
        break;
    case QGC_MAINWINDOW_STYLE_OUTDOOR:
        qApp->setStyle("plastique");
        styleFileName = ":/images/style-outdoor.css";
        reloadStylesheet();
        break;
    }
    currentStyle = style;
}

727
void MainWindow::selectStylesheet()
pixhawk's avatar
pixhawk committed
728
{
729
    // Let user select style sheet
730
    styleFileName = QFileDialog::getOpenFileName(this, tr("Specify stylesheet"), styleFileName, tr("CSS Stylesheet (*.css);;"));
731

732
    if (!styleFileName.endsWith(".css")) {
733 734 735 736 737 738 739 740 741 742
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(tr("QGroundControl did lot load a new style"));
        msgBox.setInformativeText(tr("No suitable .css file selected. Please select a valid .css file."));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

pixhawk's avatar
pixhawk committed
743
    // Load style sheet
744 745 746 747 748 749 750
    reloadStylesheet();
}

void MainWindow::reloadStylesheet()
{
    // Load style sheet
    QFile* styleSheet = new QFile(styleFileName);
751
    if (!styleSheet->exists()) {
752 753
        styleSheet = new QFile(":/images/style-mission.css");
    }
754
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text)) {
755 756
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
757
        qApp->setStyleSheet(style);
758
    } else {
759 760 761
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(tr("QGroundControl did lot load a new style"));
762
        msgBox.setInformativeText(tr("Stylesheet file %1 was not readable").arg(styleFileName));
763 764 765
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
pixhawk's avatar
pixhawk committed
766
    }
767
    delete styleSheet;
pixhawk's avatar
pixhawk committed
768 769
}

770 771 772 773 774 775
/**
 * The status message will be overwritten if a new message is posted to this function
 *
 * @param status message text
 * @param timeout how long the status should be displayed
 */
pixhawk's avatar
pixhawk committed
776
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
777
{
lm's avatar
lm committed
778
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
779 780
}

781 782 783 784 785 786
/**
 * The status message will be overwritten if a new message is posted to this function.
 * it will be automatically hidden after 5 seconds.
 *
 * @param status message text
 */
787
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
788
{
lm's avatar
lm committed
789
    statusBar()->showMessage(status, 20000);
790 791 792 793
}

void MainWindow::showCriticalMessage(const QString& title, const QString& message)
{
794
    QMessageBox msgBox(this);
795 796 797 798 799 800
    msgBox.setIcon(QMessageBox::Critical);
    msgBox.setText(title);
    msgBox.setInformativeText(message);
    msgBox.setStandardButtons(QMessageBox::Ok);
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();
pixhawk's avatar
pixhawk committed
801 802
}

lm's avatar
lm committed
803 804
void MainWindow::showInfoMessage(const QString& title, const QString& message)
{
805
    QMessageBox msgBox(this);
lm's avatar
lm committed
806 807 808 809 810 811 812 813
    msgBox.setIcon(QMessageBox::Information);
    msgBox.setText(title);
    msgBox.setInformativeText(message);
    msgBox.setStandardButtons(QMessageBox::Ok);
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();
}

pixhawk's avatar
pixhawk committed
814 815 816 817
/**
* @brief Create all actions associated to the main window
*
**/
818
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
819
{
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
    // Bind together the perspective actions
    QActionGroup* perspectives = new QActionGroup(ui.menuPerspectives);
    perspectives->addAction(ui.actionEngineersView);
    perspectives->addAction(ui.actionMavlinkView);
    perspectives->addAction(ui.actionPilotsView);
    perspectives->addAction(ui.actionOperatorsView);
    perspectives->addAction(ui.actionUnconnectedView);
    perspectives->setExclusive(true);

    // Mark the right one as selected
    if (currentView == VIEW_ENGINEER) ui.actionEngineersView->setChecked(true);
    if (currentView == VIEW_MAVLINK) ui.actionMavlinkView->setChecked(true);
    if (currentView == VIEW_PILOT) ui.actionPilotsView->setChecked(true);
    if (currentView == VIEW_OPERATOR) ui.actionOperatorsView->setChecked(true);
    if (currentView == VIEW_UNCONNECTED) ui.actionUnconnectedView->setChecked(true);

    // The UAS actions are not enabled without connection to system
    ui.actionLiftoff->setEnabled(false);
    ui.actionLand->setEnabled(false);
    ui.actionEmergency_Kill->setEnabled(false);
    ui.actionEmergency_Land->setEnabled(false);
    ui.actionShutdownMAV->setEnabled(false);

pixhawk's avatar
pixhawk committed
843 844 845 846 847
    // Connect actions from ui
    connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink()));

    // Connect internal actions
    connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
848
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
pixhawk's avatar
pixhawk committed
849

850
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
851 852 853 854
    connect(ui.actionLiftoff, SIGNAL(triggered()), UASManager::instance(), SLOT(launchActiveUAS()));
    connect(ui.actionLand, SIGNAL(triggered()), UASManager::instance(), SLOT(returnActiveUAS()));
    connect(ui.actionEmergency_Land, SIGNAL(triggered()), UASManager::instance(), SLOT(stopActiveUAS()));
    connect(ui.actionEmergency_Kill, SIGNAL(triggered()), UASManager::instance(), SLOT(killActiveUAS()));
855
    connect(ui.actionShutdownMAV, SIGNAL(triggered()), UASManager::instance(), SLOT(shutdownActiveUAS()));
pixhawk's avatar
pixhawk committed
856 857
    connect(ui.actionConfiguration, SIGNAL(triggered()), UASManager::instance(), SLOT(configureActiveUAS()));

858
    // Views actions
859
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
860
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
861
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
862
    connect(ui.actionUnconnectedView, SIGNAL(triggered()), this, SLOT(loadUnconnectedView()));
863

864
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
865 866
    connect(ui.actionReloadStylesheet, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
    connect(ui.actionSelectStylesheet, SIGNAL(triggered()), this, SLOT(selectStylesheet()));
867

868
    // Help Actions
869
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
870
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
871
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
872 873 874

    // Custom widget actions
    connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget()));
875
    connect(ui.actionLoadCustomWidgetFile, SIGNAL(triggered()), this, SLOT(loadCustomWidget()));
876 877 878

    // Audio output
    ui.actionMuteAudioOutput->setChecked(GAudioOutput::instance()->isMuted());
879
    connect(GAudioOutput::instance(), SIGNAL(mutedChanged(bool)), ui.actionMuteAudioOutput, SLOT(setChecked(bool)));
880
    connect(ui.actionMuteAudioOutput, SIGNAL(triggered(bool)), GAudioOutput::instance(), SLOT(mute(bool)));
881 882 883 884 885 886 887

    // User interaction
    // NOTE: Joystick thread is not started and
    // configuration widget is not instantiated
    // unless it is actually used
    // so no ressources spend on this.
    ui.actionJoystickSettings->setVisible(true);
888 889 890

    // Configuration
    // Joystick
891
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
892 893
    // Application Settings
    connect(ui.actionSettings, SIGNAL(triggered()), this, SLOT(showSettings()));
894 895
}

896 897
void MainWindow::showHelp()
{
lm's avatar
lm committed
898
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/start"))) {
899 900 901 902 903 904 905 906 907 908 909 910
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open help in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/user_guide in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

void MainWindow::showCredits()
{
911
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits"))) {
912 913 914 915 916 917 918 919 920 921 922 923
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open credits in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/credits in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

void MainWindow::showRoadMap()
{
lm's avatar
lm committed
924
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/dev/roadmap"))) {
925 926 927 928 929 930 931 932 933 934
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open roadmap in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/roadmap in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

pixhawk's avatar
pixhawk committed
935
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
936
{
937 938
    if (!joystickWidget) {
        if (!joystick->isRunning()) {
939 940 941 942 943
            joystick->start();
        }
        joystickWidget = new JoystickWidget(joystick);
    }
    joystickWidget->show();
pixhawk's avatar
pixhawk committed
944 945
}

946 947 948 949 950 951
void MainWindow::showSettings()
{
    QGCSettingsWidget* settings = new QGCSettingsWidget(this);
    settings->show();
}

pixhawk's avatar
pixhawk committed
952
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
953 954 955 956
{
    SerialLink* link = new SerialLink();
    // TODO This should be only done in the dialog itself

957
    LinkManager::instance()->add(link);
pixhawk's avatar
pixhawk committed
958 959
    LinkManager::instance()->addProtocol(link, mavlink);

960 961
    // Go fishing for this link's configuration window
    QList<QAction*> actions = ui.menuNetwork->actions();
pixhawk's avatar
pixhawk committed
962

lm's avatar
lm committed
963 964 965 966
    foreach (QAction* act, actions)
    {
        if (act->data().toInt() == LinkManager::instance()->getLinks().indexOf(link))
        {
967 968 969 970
            act->trigger();
            break;
        }
    }
pixhawk's avatar
pixhawk committed
971 972
}

pixhawk's avatar
pixhawk committed
973 974
void MainWindow::addLink(LinkInterface *link)
{
975 976 977 978
    // IMPORTANT! KEEP THESE TWO LINES
    // THEY MAKE SURE THE LINK IS PROPERLY REGISTERED
    // BEFORE LINKING THE UI AGAINST IT
    // Register (does nothing if already registered)
979
    LinkManager::instance()->add(link);
980
    LinkManager::instance()->addProtocol(link, mavlink);
981

982 983
    // Go fishing for this link's configuration window
    QList<QAction*> actions = ui.menuNetwork->actions();
pixhawk's avatar
pixhawk committed
984

985
    bool found = false;
986

987 988
    foreach (QAction* act, actions) {
        if (act->data().toInt() == LinkManager::instance()->getLinks().indexOf(link)) {
989 990 991 992 993
            found = true;
        }
    }

    UDPLink* udp = dynamic_cast<UDPLink*>(link);
994

995
    if (!found || udp) {
996 997 998 999 1000 1001 1002 1003
        CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
        QAction* action = commWidget->getAction();
        ui.menuNetwork->addAction(action);

        // Error handling
        connect(link, SIGNAL(communicationError(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
        // Special case for simulationlink
        MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
1004
        if (sim) {
1005 1006 1007
            //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)));
            connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool)));
        }
pixhawk's avatar
pixhawk committed
1008 1009 1010
    }
}

1011 1012 1013 1014 1015 1016 1017
void MainWindow::setActiveUAS(UASInterface* uas)
{
    // Enable and rename menu
    ui.menuUnmanned_System->setTitle(uas->getUASName());
    if (!ui.menuUnmanned_System->isEnabled()) ui.menuUnmanned_System->setEnabled(true);
}

1018 1019 1020
void MainWindow::UASSpecsChanged(int uas)
{
    UASInterface* activeUAS = UASManager::instance()->getActiveUAS();
1021 1022
    if (activeUAS) {
        if (activeUAS->getUASID() == uas) {
1023 1024 1025 1026 1027
            ui.menuUnmanned_System->setTitle(activeUAS->getUASName());
        }
    }
}

pixhawk's avatar
pixhawk committed
1028
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1029
{
1030

pixhawk's avatar
pixhawk committed
1031 1032
    // Connect the UAS to the full user interface

lm's avatar
lm committed
1033 1034
    if (uas != NULL)
    {
1035
        // The pilot, operator and engineer views were not available on startup, enable them now
1036
        ui.actionPilotsView->setEnabled(true);
1037 1038
        ui.actionOperatorsView->setEnabled(true);
        ui.actionEngineersView->setEnabled(true);
1039 1040 1041 1042 1043 1044
        // The UAS actions are not enabled without connection to system
        ui.actionLiftoff->setEnabled(true);
        ui.actionLand->setEnabled(true);
        ui.actionEmergency_Kill->setEnabled(true);
        ui.actionEmergency_Land->setEnabled(true);
        ui.actionShutdownMAV->setEnabled(true);
1045

1046 1047
        QIcon icon;
        // Set matching icon
1048
        switch (uas->getSystemType()) {
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
        case 0:
            icon = QIcon(":/images/mavs/generic.svg");
            break;
        case 1:
            icon = QIcon(":/images/mavs/fixed-wing.svg");
            break;
        case 2:
            icon = QIcon(":/images/mavs/quadrotor.svg");
            break;
        case 3:
            icon = QIcon(":/images/mavs/coaxial.svg");
            break;
        case 4:
            icon = QIcon(":/images/mavs/helicopter.svg");
            break;
        case 5:
            icon = QIcon(":/images/mavs/groundstation.svg");
            break;
        default:
            icon = QIcon(":/images/mavs/unknown.svg");
            break;
        }

1072 1073 1074
        QAction* uasAction = new QAction(icon, tr("Select %1 for control").arg(uas->getUASName()), ui.menuConnected_Systems);
        connect(uas, SIGNAL(systemRemoved()), uasAction, SLOT(deleteLater()));
        connect(uasAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
1075
        connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int)));
1076 1077

        ui.menuConnected_Systems->addAction(uasAction);
1078 1079

        // FIXME Should be not inside the mainwindow
1080
        if (debugConsoleDockWidget) {
pixhawk's avatar
pixhawk committed
1081
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
1082
            if (debugConsole) {
pixhawk's avatar
pixhawk committed
1083 1084 1085
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1086
        }
1087 1088

        // Health / System status indicator
1089
        if (infoDockWidget) {
pixhawk's avatar
pixhawk committed
1090
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
1091
            if (infoWidget) {
pixhawk's avatar
pixhawk committed
1092 1093
                infoWidget->addUAS(uas);
            }
1094
        }
1095 1096

        // UAS List
lm's avatar
lm committed
1097 1098
        if (listDockWidget)
        {
pixhawk's avatar
pixhawk committed
1099
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
lm's avatar
lm committed
1100 1101
            if (listWidget)
            {
pixhawk's avatar
pixhawk committed
1102 1103
                listWidget->addUAS(uas);
            }
1104
        }
1105

1106 1107
        // Line chart
        if (!linechartWidget)
lm's avatar
lm committed
1108
        {
1109
            // Center widgets
LM's avatar
LM committed
1110 1111
            linechartWidget = new Linecharts(this);
            //linechartWidget FIXME
1112
            addCentralWidget(linechartWidget, tr("Realtime Plot"));
1113
        }
1114

LM's avatar
LM committed
1115
        // Load default custom widgets for this autopilot type
lm's avatar
lm committed
1116
        loadCustomWidgetsFromDefaults(uas->getSystemTypeName(), uas->getAutopilotTypeName());
1117 1118


lm's avatar
lm committed
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
        if (uas->getAutopilotType() == MAV_AUTOPILOT_PIXHAWK)
        {
            // Dock widgets
            if (!detectionDockWidget)
            {
                detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
                detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
                detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
                addTool(detectionDockWidget, tr("Object Recognition"), Qt::RightDockWidgetArea);
            }

            if (!watchdogControlDockWidget) {
                watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
                watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
                watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
                addTool(watchdogControlDockWidget, tr("Process Control"), Qt::BottomDockWidgetArea);
            }
1136 1137 1138 1139 1140 1141
        }

        // Change the view only if this is the first UAS

        // If this is the first connected UAS, it is both created as well as
        // the currently active UAS
1142 1143
        if (UASManager::instance()->getUASList().size() == 1)
        {
1144
            // Load last view if setting is present
1145 1146
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
            {
1147
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1148
                switch (view) {
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
                case VIEW_ENGINEER:
                    loadEngineerView();
                    break;
                case VIEW_MAVLINK:
                    loadMAVLinkView();
                    break;
                case VIEW_PILOT:
                    loadPilotView();
                    break;
                case VIEW_UNCONNECTED:
                    loadUnconnectedView();
                    break;
                case VIEW_OPERATOR:
                default:
                    loadOperatorView();
                    break;
1165
                }
1166 1167 1168
            }
            else
            {
1169
                loadOperatorView();
1170
            }
1171
        }
1172

1173
    }
1174 1175

    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
lm's avatar
lm committed
1176

1177
    // Restore the mainwindow size
LM's avatar
LM committed
1178 1179
    if (settings.contains(getWindowGeometryKey()))
    {
lm's avatar