MainWindow.cc 69.6 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"
52

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

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

pixhawk's avatar
pixhawk committed
61

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

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

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

pixhawk's avatar
pixhawk committed
77 78 79 80 81 82 83
/**
* 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()
**/
84
MainWindow::MainWindow(QWidget *parent):
85 86 87 88 89 90 91
    QMainWindow(parent),
    toolsMenuActions(),
    currentView(VIEW_UNCONNECTED),
    aboutToCloseFlag(false),
    changingViewsFlag(false),
    styleFileName(QCoreApplication::applicationDirPath() + "/style-indoor.css"),
    autoReconnect(false),
92 93
    currentStyle(QGC_MAINWINDOW_STYLE_INDOOR),
    lowPowerMode(false)
pixhawk's avatar
pixhawk committed
94
{
95
    loadSettings();
96
    if (!settings.contains("CURRENT_VIEW")) {
97 98
        // Set this view as default view
        settings.setValue("CURRENT_VIEW", currentView);
99
    } else {
100 101 102
        // LOAD THE LAST VIEW
        VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
        if (currentViewCandidate != VIEW_ENGINEER &&
103 104
                currentViewCandidate != VIEW_OPERATOR &&
                currentViewCandidate != VIEW_PILOT) {
105
            currentView = currentViewCandidate;
106
        }
107 108
    }

109
    setDefaultSettingsForAp();
110

111 112
    settings.sync();

pixhawk's avatar
pixhawk committed
113 114 115
    // Setup user interface
    ui.setupUi(this);

116 117
    setVisible(false);

118
    buildCommonWidgets();
119

120
    connectCommonWidgets();
121

122
    arrangeCommonCenterStack();
123 124

    configureWindowName();
pixhawk's avatar
pixhawk committed
125

126
    loadStyle(currentStyle);
127

128
    // Create actions
129
    connectCommonActions();
130

131 132 133
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

134
    // Load mavlink view as default widget set
135
    //loadMAVLinkView();
136

lm's avatar
lm committed
137 138
    statusBar()->setSizeGripEnabled(true);

139
    // Restore the window position and size
140
    if (settings.contains(getWindowGeometryKey())) {
141
        // Restore the window geometry
142
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
143
    } else {
144 145 146
        // Adjust the size
        adjustSize();
    }
pixhawk's avatar
pixhawk committed
147

148 149
    // Populate link menu
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
150
    foreach(LinkInterface* link, links) {
151 152
        this->addLink(link);
    }
153

154 155
    connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));

156
    // Connect user interface devices
157 158
    joystickWidget = 0;
    joystick = new JoystickInput();
159

160 161 162 163 164 165 166 167
    // Load Toolbar
    toolBar = new QGCToolBar(this);
    this->addToolBar(toolBar);
    // Add actions
    toolBar->addPerspectiveChangeAction(ui.actionOperatorsView);
    toolBar->addPerspectiveChangeAction(ui.actionEngineersView);
    toolBar->addPerspectiveChangeAction(ui.actionPilotsView);

lm's avatar
lm committed
168 169
    // Enable and update view
    presentView();
170 171

    // Connect link
172
    if (autoReconnect) {
173 174 175 176 177 178
        SerialLink* link = new SerialLink();
        // Add to registry
        LinkManager::instance()->add(link);
        LinkManager::instance()->addProtocol(link, mavlink);
        link->connect();
    }
179

180 181 182
    // Set low power mode
    enableLowPowerMode(lowPowerMode);

183 184
    // Initialize window state
    windowStateVal = windowState();
pixhawk's avatar
pixhawk committed
185 186
}

pixhawk's avatar
pixhawk committed
187
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
188
{
189 190 191
    // Store settings
    storeSettings();

192
    delete mavlink;
193
    delete joystick;
lm's avatar
lm committed
194

195 196 197 198 199 200
    // Get and delete all dockwidgets and contained
    // widgets
    QObjectList childList( this->children() );

    QObjectList::iterator i;
    QDockWidget* dockWidget;
201
    for (i = childList.begin(); i != childList.end(); ++i) {
202
        dockWidget = dynamic_cast<QDockWidget*>(*i);
203
        if (dockWidget) {
204 205 206 207 208 209
            // Remove dock widget from main window
            removeDockWidget(dockWidget);
            delete dockWidget->widget();
            delete dockWidget;
        }
    }
pixhawk's avatar
pixhawk committed
210 211
}

212 213 214 215 216 217 218 219 220
/**
 * Set default settings for this AP type.
 */
void MainWindow::setDefaultSettingsForAp()
{
    // Check if the settings exist, instantiate defaults if necessary

    // UNCONNECTED VIEW DEFAULT
    QString centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_MAP, VIEW_UNCONNECTED);
221
    if (!settings.contains(centralKey)) {
222
        settings.setValue(centralKey,true);
223 224 225 226 227

        // ENABLE UAS LIST
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_UAS_LIST, VIEW_UNCONNECTED), true);
        // ENABLE COMMUNICATION CONSOLE
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_DEBUG_CONSOLE, VIEW_UNCONNECTED), true);
228 229 230 231
    }

    // OPERATOR VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_MAP, VIEW_OPERATOR);
232
    if (!settings.contains(centralKey)) {
233 234 235 236
        settings.setValue(centralKey,true);

        // ENABLE UAS LIST
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_UAS_LIST,VIEW_OPERATOR), true);
237 238
        // ENABLE HUD TOOL WIDGET
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_HUD,VIEW_OPERATOR), true);
239 240
        // ENABLE WAYPOINTS
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_WAYPOINTS,VIEW_OPERATOR), true);
241 242 243 244
    }

    // ENGINEER VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_LINECHART, VIEW_ENGINEER);
245
    if (!settings.contains(centralKey)) {
246
        settings.setValue(centralKey,true);
247 248
        // Enable Parameter widget
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_PARAMETERS,VIEW_ENGINEER), true);
249 250 251 252
    }

    // MAVLINK VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_PROTOCOL, VIEW_MAVLINK);
253
    if (!settings.contains(centralKey)) {
254 255 256 257 258
        settings.setValue(centralKey,true);
    }

    // PILOT VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_HUD, VIEW_PILOT);
259
    if (!settings.contains(centralKey)) {
260
        settings.setValue(centralKey,true);
261 262
        // Enable Flight display
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_HDD_1,VIEW_PILOT), true);
263 264 265
    }
}

lm's avatar
lm committed
266 267 268
void MainWindow::resizeEvent(QResizeEvent * event)
{
    Q_UNUSED(event);
269
    if (height() < 800) {
lm's avatar
lm committed
270
        ui.statusBar->setVisible(false);
271
    } else {
lm's avatar
lm committed
272
        ui.statusBar->setVisible(true);
273
        ui.statusBar->setSizeGripEnabled(true);
lm's avatar
lm committed
274 275 276
    }
}

277 278
QString MainWindow::getWindowStateKey()
{
279
    return QString::number(currentView)+"_windowstate";
280 281 282 283
}

QString MainWindow::getWindowGeometryKey()
{
284 285
    //return QString::number(currentView)+"_geometry";
    return "_geometry";
286 287
}

lm's avatar
lm committed
288 289 290
void MainWindow::buildCustomWidget()
{
    // Show custom widgets only if UAS is connected
291
    if (UASManager::instance()->getActiveUAS() != NULL) {
lm's avatar
lm committed
292 293 294 295 296 297
        // Enable custom widgets
        ui.actionNewCustomWidget->setEnabled(true);

        // Create custom widgets
        QList<QGCToolWidget*> widgets = QGCToolWidget::createWidgetsFromSettings(this);

298
        if (widgets.size() > 0) {
lm's avatar
lm committed
299 300 301
            ui.menuTools->addSeparator();
        }

302
        for(int i = 0; i < widgets.size(); ++i) {
lm's avatar
lm committed
303
            // Check if this widget already has a parent, do not create it in this case
304 305
            QGCToolWidget* tool = widgets.at(i);
            QDockWidget* dock = dynamic_cast<QDockWidget*>(tool->parentWidget());
306
            if (!dock) {
307 308 309 310
                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
311
                QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this);
312
                showAction->setCheckable(true);
lm's avatar
lm committed
313 314 315 316
                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);
317 318 319 320 321 322 323 324

                // Load visibility for view (default is off)
                dock->setVisible(tool->isVisible(currentView));

                // 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
325 326 327 328 329
            }
        }
    }
}

330 331 332 333
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
334
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
335 336

    // Dock widgets
337
    if (!controlDockWidget) {
338
        controlDockWidget = new QDockWidget(tr("Control"), this);
339
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
340
        controlDockWidget->setWidget( new UASControlWidget(this) );
341
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget(bool)), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
342
    }
343

344
    if (!listDockWidget) {
345 346
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
347
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
348
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget(bool)), MENU_UAS_LIST, Qt::RightDockWidgetArea);
349
    }
350

351
    if (!waypointsDockWidget) {
352
        waypointsDockWidget = new QDockWidget(tr("Mission Plan"), this);
353
        waypointsDockWidget->setWidget( new QGCWaypointListMulti(this) );
354
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
355
        addToToolsMenu (waypointsDockWidget, tr("Mission Plan"), SLOT(showToolWidget(bool)), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
356
    }
357

358
    if (!infoDockWidget) {
359 360
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
361
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
362
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget(bool)), MENU_STATUS, Qt::RightDockWidgetArea);
363
    }
364

365
    if (!debugConsoleDockWidget) {
366 367
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
368
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
369
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget(bool)), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
370
    }
371

372
    if (!logPlayerDockWidget) {
373 374 375
        logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
        logPlayerDockWidget->setWidget( new QGCMAVLinkLogPlayer(mavlink, this) );
        logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
376
        addToToolsMenu(logPlayerDockWidget, tr("MAVLink Log Replay"), SLOT(showToolWidget(bool)), MENU_MAVLINK_LOG_PLAYER, Qt::RightDockWidgetArea);
377 378
    }

379
    // Center widgets
380 381
    if (!mapWidget)
    {
382
        mapWidget = new QGCMapTool(this);
383 384
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
385

386
    if (!protocolWidget) {
387 388 389
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
390

391
    if (!dataplotWidget) {
lm's avatar
lm committed
392
        dataplotWidget    = new QGCDataPlot2D(this);
393
        addToCentralWidgetsMenu (dataplotWidget, "Logfile Plot", SLOT(showCentralWidget()),CENTRAL_DATA_PLOT);
lm's avatar
lm committed
394
    }
395

396

397
}
398

399

400
void MainWindow::buildPxWidgets()
401
{
pixhawk's avatar
pixhawk committed
402 403
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
pixhawk's avatar
pixhawk committed
404 405 406
    acceptList->append("-105,roll deg,deg,+105,s");
    acceptList->append("-105,pitch deg,deg,+105,s");
    acceptList->append("-105,heading deg,deg,+105,s");
407

pixhawk's avatar
pixhawk committed
408 409 410
    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");
411
    acceptList->append("0,airspeed,m/s,30");
412 413
    acceptList->append("0,groundspeed,m/s,30");
    acceptList->append("0,climbrate,m/s,30");
414
    acceptList->append("0,throttle,%,100");
415

pixhawk's avatar
pixhawk committed
416 417
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
418 419 420 421 422 423 424 425
    acceptList2->append("900,servo #1,us,2100,s");
    acceptList2->append("900,servo #2,us,2100,s");
    acceptList2->append("900,servo #3,us,2100,s");
    acceptList2->append("900,servo #4,us,2100,s");
    acceptList2->append("900,servo #5,us,2100,s");
    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
426
    acceptList2->append("0,abs pressure,hPa,65500");
427 428 429
    //acceptList2->append("-2048,accel. x,raw,2048,s");
    //acceptList2->append("-2048,accel. y,raw,2048,s");
    //acceptList2->append("-2048,accel. z,raw,2048,s");
430

431
    if (!linechartWidget) {
432 433
        // Center widgets
        linechartWidget   = new Linecharts(this);
434
        addToCentralWidgetsMenu(linechartWidget, tr("Realtime Plot"), SLOT(showCentralWidget()), CENTRAL_LINECHART);
435
    }
436 437


438
    if (!hudWidget) {
439
        hudWidget         = new HUD(320, 240, this);
440
        addToCentralWidgetsMenu(hudWidget, tr("Head Up Display"), SLOT(showCentralWidget()), CENTRAL_HUD);
441
    }
442

443
    if (!dataplotWidget) {
444
        dataplotWidget    = new QGCDataPlot2D(this);
445
        addToCentralWidgetsMenu(dataplotWidget, "Logfile Plot", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
446
    }
447

448
#ifdef QGC_OSG_ENABLED
449
    if (!_3DWidget) {
450
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
451
        addToCentralWidgetsMenu(_3DWidget, tr("Local 3D"), SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
452
    }
453
#endif
454

455
#ifdef QGC_OSGEARTH_ENABLED
456
    if (!_3DMapWidget) {
457
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
458
        addToCentralWidgetsMenu(_3DMapWidget, tr("OSG Earth 3D"), SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
459
    }
460
#endif
lm's avatar
lm committed
461

462
#if (defined _MSC_VER) | (defined Q_OS_MAC)
463
    if (!gEarthWidget) {
464
        gEarthWidget = new QGCGoogleEarthView(this);
465
        addToCentralWidgetsMenu(gEarthWidget, tr("Google Earth"), SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
466
    }
467

468
#endif
469

pixhawk's avatar
pixhawk committed
470
    // Dock widgets
471

472
    if (!detectionDockWidget) {
473 474
        detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
        detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
pixhawk's avatar
pixhawk committed
475
        detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
476
        addToToolsMenu (detectionDockWidget, tr("Object Recognition"), SLOT(showToolWidget(bool)), MENU_DETECTION, Qt::RightDockWidgetArea);
477
    }
478

479
    if (!parametersDockWidget) {
480
        parametersDockWidget = new QDockWidget(tr("Calibration and Onboard Parameters"), this);
481
        parametersDockWidget->setWidget( new ParameterInterface(this) );
pixhawk's avatar
pixhawk committed
482
        parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
483
        addToToolsMenu (parametersDockWidget, tr("Calibration and Parameters"), SLOT(showToolWidget(bool)), MENU_PARAMETERS, Qt::RightDockWidgetArea);
484
    }
485

486
    if (!watchdogControlDockWidget) {
487 488
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
pixhawk's avatar
pixhawk committed
489
        watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
490
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget(bool)), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
491
    }
492

493
    if (!hsiDockWidget) {
494 495
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
496
        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
497
        addToToolsMenu (hsiDockWidget, tr("Horizontal Situation"), SLOT(showToolWidget(bool)), MENU_HSI, Qt::BottomDockWidgetArea);
498
    }
499

500
    if (!headDown1DockWidget) {
501 502
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
503
        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
504
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget(bool)), MENU_HDD_1, Qt::RightDockWidgetArea);
505
    }
506

507
    if (!headDown2DockWidget) {
508 509
        headDown2DockWidget = new QDockWidget(tr("Actuator Status"), this);
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Actuator Status", this) );
510
        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
511
        addToToolsMenu (headDown2DockWidget, tr("Actuator Status"), SLOT(showToolWidget(bool)), MENU_HDD_2, Qt::RightDockWidgetArea);
512
    }
513

514
    if (!rcViewDockWidget) {
515 516
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
517
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
518
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget(bool)), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
519
    }
520

521
    if (!headUpDockWidget) {
522 523
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
524
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
525
        addToToolsMenu (headUpDockWidget, tr("Head Up Display"), SLOT(showToolWidget(bool)), MENU_HUD, Qt::RightDockWidgetArea);
526
    }
527

528
    if (!video1DockWidget) {
pixhawk's avatar
pixhawk committed
529 530 531 532 533 534 535
        video1DockWidget = new QDockWidget(tr("Video Stream 1"), this);
        HUD* video1 =  new HUD(160, 120, this);
        video1->enableHUDInstruments(false);
        video1->enableVideo(true);
        // FIXME select video stream as well
        video1DockWidget->setWidget(video1);
        video1DockWidget->setObjectName("VIDEO_STREAM_1_DOCK_WIDGET");
536
        addToToolsMenu (video1DockWidget, tr("Video Stream 1"), SLOT(showToolWidget(bool)), MENU_VIDEO_STREAM_1, Qt::LeftDockWidgetArea);
pixhawk's avatar
pixhawk committed
537 538
    }

539
    if (!video2DockWidget) {
pixhawk's avatar
pixhawk committed
540 541 542 543 544 545 546
        video2DockWidget = new QDockWidget(tr("Video Stream 2"), this);
        HUD* video2 =  new HUD(160, 120, this);
        video2->enableHUDInstruments(false);
        video2->enableVideo(true);
        // FIXME select video stream as well
        video2DockWidget->setWidget(video2);
        video2DockWidget->setObjectName("VIDEO_STREAM_2_DOCK_WIDGET");
547
        addToToolsMenu (video2DockWidget, tr("Video Stream 2"), SLOT(showToolWidget(bool)), MENU_VIDEO_STREAM_2, Qt::LeftDockWidgetArea);
548
    }
549

pixhawk's avatar
pixhawk committed
550 551
    // Dialogue widgets
    //FIXME: free memory in destructor
552 553 554 555
}

void MainWindow::buildSlugsWidgets()
{
556
    if (!linechartWidget) {
557 558
        // Center widgets
        linechartWidget   = new Linecharts(this);
559
        addToCentralWidgetsMenu(linechartWidget, tr("Realtime Plot"), SLOT(showCentralWidget()), CENTRAL_LINECHART);
560
    }
561

562
    if (!headUpDockWidget) {
563 564 565
        // Dock widgets
        headUpDockWidget = new QDockWidget(tr("Control Indicator"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
pixhawk's avatar
pixhawk committed
566
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
567
        addToToolsMenu (headUpDockWidget, tr("Head Up Display"), SLOT(showToolWidget(bool)), MENU_HUD, Qt::LeftDockWidgetArea);
568
    }
569

570
    if (!rcViewDockWidget) {
571 572
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
pixhawk's avatar
pixhawk committed
573
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
574
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget(bool)), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
575
    }
576

577
#if (defined _MSC_VER) | (defined Q_OS_MAC)
578
    if (!gEarthWidget) {
579 580 581 582 583 584
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, tr("Google Earth"), SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }

#endif

585
    if (!slugsDataWidget) {
586 587 588 589 590 591
        // Dialog widgets
        slugsDataWidget = new QDockWidget(tr("Slugs Data"), this);
        slugsDataWidget->setWidget( new SlugsDataSensorView(this));
        slugsDataWidget->setObjectName("SLUGS_DATA_DOCK_WIDGET");
        addToToolsMenu (slugsDataWidget, tr("Telemetry Data"), SLOT(showToolWidget(bool)), MENU_SLUGS_DATA, Qt::RightDockWidgetArea);
    }
592

593

594
    if (!slugsHilSimWidget) {
595 596 597 598 599
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
        slugsHilSimWidget->setObjectName("SLUGS_HIL_SIM_DOCK_WIDGET");
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget(bool)), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }
600

601 602
    if (!controlParameterWidget) {
        controlParameterWidget = new QDockWidget(tr("Control Parameters"), this);
603 604 605
        controlParameterWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_PARAMETERWIDGET");
        controlParameterWidget->setWidget( new UASControlParameters(this) );
        addToToolsMenu (controlParameterWidget, tr("Control Parameters"), SLOT(showToolWidget(bool)), MENU_UAS_CONTROL_PARAM, Qt::LeftDockWidgetArea);
606
    }
607

608
    if (!parametersDockWidget) {
609 610 611 612 613 614
        parametersDockWidget = new QDockWidget(tr("Calibration and Onboard Parameters"), this);
        parametersDockWidget->setWidget( new ParameterInterface(this) );
        parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
        addToToolsMenu (parametersDockWidget, tr("Calibration and Parameters"), SLOT(showToolWidget(bool)), MENU_PARAMETERS, Qt::RightDockWidgetArea);
    }

615
    if (!slugsCamControlWidget) {
616 617 618 619 620
        slugsCamControlWidget = new QDockWidget(tr("Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsPadCameraControl(this));
        slugsCamControlWidget->setObjectName("SLUGS_CAM_CONTROL_DOCK_WIDGET");
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget(bool)), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
621

622
}
623 624 625


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
626 627 628
        const QString title,
        const char * slotName,
        TOOLS_WIDGET_NAMES centralWidget)
629
{
630
    QAction* tempAction;
631

632

633
// Not needed any more - separate menu now available
634

635 636 637 638 639 640 641
//    // Add the separator that will separate tools from central Widgets
//    if (!toolsMenuActions[CENTRAL_SEPARATOR])
//    {
//        tempAction = ui.menuTools->addSeparator();
//        toolsMenuActions[CENTRAL_SEPARATOR] = tempAction;
//        tempAction->setData(CENTRAL_SEPARATOR);
//    }
642

643
    tempAction = ui.menuMain->addAction(title);
644

645 646
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
647

648 649 650
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
651

652
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
653

654
    if (!settings.contains(chKey)) {
655 656
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
657
    } else {
658 659
        tempAction->setChecked(settings.value(chKey).toBool());
    }
660

661
    // connect the action
662
    connect(tempAction,SIGNAL(triggered(bool)),this, slotName);
663 664 665
}


lm's avatar
lm committed
666 667
void MainWindow::showCentralWidget()
{
668
    QAction* senderAction = qobject_cast<QAction *>(sender());
669 670 671 672

    // Block sender action while manipulating state
    senderAction->blockSignals(true);

673 674
    int tool = senderAction->data().toInt();
    QString chKey;
675

676
    // check the current action
677

678
    if (senderAction && dockWidgets[tool]) {
679 680
        // uncheck all central widget actions
        QHashIterator<int, QAction*> i(toolsMenuActions);
681
        while (i.hasNext()) {
682
            i.next();
683
            //qDebug() << "shCW" << i.key() << "read";
684
            if (i.value() && i.value()->data().toInt() > 255) {
685 686 687
                // Block signals and uncheck action
                // firing would be unneccesary
                i.value()->blockSignals(true);
688
                i.value()->setChecked(false);
689
                i.value()->blockSignals(false);
690 691 692 693 694 695

                // update the settings
                chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.value()->data().toInt()), currentView);
                settings.setValue(chKey,false);
            }
        }
696

697
        // check the current action
698
        //qDebug() << senderAction->text();
699
        senderAction->setChecked(true);
700

701 702
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
703

704 705 706
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
707

708 709 710
        // Unblock sender action
        senderAction->blockSignals(false);

711 712
        presentView();
    }
713
}
714

lm's avatar
lm committed
715 716 717 718
/**
 * Adds a widget to the tools menu and sets it visible if it was
 * enabled last time.
 */
719
void MainWindow::addToToolsMenu ( QWidget* widget,
720 721 722 723
                                  const QString title,
                                  const char * slotName,
                                  TOOLS_WIDGET_NAMES tool,
                                  Qt::DockWidgetArea location)
lm's avatar
lm committed
724
{
725 726
    QAction* tempAction;
    QString posKey, chKey;
727

728

729
    if (toolsMenuActions[CENTRAL_SEPARATOR]) {
730 731 732
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
733
    } else {
734 735
        tempAction = ui.menuTools->addAction(title);
    }
736

737 738
    tempAction->setCheckable(true);
    tempAction->setData(tool);
739

740 741 742
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
743
    //qDebug() << widget;
744

745
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
746

747
    if (!settings.contains(posKey)) {
748 749
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
750
    } else {
751
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
752
    }
753

754
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
755

756
    if (!settings.contains(chKey)) {
757 758
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
759
        widget->setVisible(false);
760
    } else {
761
        tempAction->setChecked(settings.value(chKey, false).toBool());
762
        widget->setVisible(settings.value(chKey, false).toBool());
763
    }
764

765
    // connect the action
766 767 768
    connect(tempAction,SIGNAL(toggled(bool)),this, slotName);

    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
769
            SIGNAL(visibilityChanged(bool)), this, SLOT(showToolWidget(bool)));
770

771 772
    //  connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
    //          SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
773

774 775
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
776 777
}

778
void MainWindow::showToolWidget(bool visible)
779
{
780
    if (!aboutToCloseFlag && !changingViewsFlag) {
781 782
        QAction* action = qobject_cast<QAction *>(sender());

783
        // Prevent this to fire if undocked
784
        if (action) {
785
            int tool = action->data().toInt();
786

787
            QDockWidget* dockWidget = qobject_cast<QDockWidget *> (dockWidgets[tool]);
788

789 790
            if (dockWidget && dockWidget->isVisible() != visible) {
                if (visible) {
791 792
                    addDockWidget(dockWidgetLocations[tool], dockWidget);
                    dockWidget->show();
793
                } else {
794 795
                    removeDockWidget(dockWidget);
                }
796 797

                QHashIterator<int, QWidget*> i(dockWidgets);
798
                while (i.hasNext()) {
799
                    i.next();
800
                    if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == dockWidget) {
801 802
                        QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                        settings.setValue(chKey,visible);
803
                        //qDebug() << "showToolWidget(): Set key" << chKey << "to" << visible;
804 805 806
                        break;
                    }
                }
807
            }
808
        }
809 810 811

        QDockWidget* dockWidget = qobject_cast<QDockWidget*>(QObject::sender());

812
        //qDebug() << "Trying to cast dockwidget" << dockWidget << "isvisible" << visible;
813

814
        if (dockWidget) {
815 816 817
            // Get action
            int tool = dockWidgets.key(dockWidget);

818
            //qDebug() << "Updating widget setting" << tool << "to" << visible;
819 820 821 822 823 824 825

            QAction* action = toolsMenuActions[tool];
            action->blockSignals(true);
            action->setChecked(visible);
            action->blockSignals(false);

            QHashIterator<int, QWidget*> i(dockWidgets);
826
            while (i.hasNext()) {
827
                i.next();
828
                if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == dockWidget) {
829 830
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,visible);
831
                    // qDebug() << "showToolWidget(): Set key" << chKey << "to" << visible;
832 833 834
                    break;
                }
            }
835
        }
836 837 838 839
    }
}


840 841 842 843 844
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
845

846
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
847

848
    //qDebug() << "showTheWidget(): Set key" << buildMenuKey(SUB_SECTION_CHECKED,widget,view) << "to" << tempVisible;
849

850
    if (tempWidget) {
851 852
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
853 854


855
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
856

857 858
    tempLocation = static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,widget, view), QVariant(Qt::RightDockWidgetArea)).toInt());

859 860
    if (tempWidget != NULL) {
        if (tempVisible) {
861 862 863
            addDockWidget(tempLocation, tempWidget);
            tempWidget->show();
        }
864 865
    }
}
866

867 868 869 870 871
QString MainWindow::buildMenuKey(SETTINGS_SECTIONS section, TOOLS_WIDGET_NAMES tool, VIEW_SECTIONS view)
{
    // Key is built as follows: autopilot_type/section_menu/view/tool/section
    int apType;

872 873 874 875 876
//    apType = (UASManager::instance() && UASManager::instance()->silentGetActiveUAS())?
//             UASManager::instance()->getActiveUAS()->getAutopilotType():
//             -1;

    apType = 1;
877

878 879 880 881 882
    return (QString::number(apType) + "_" +
            QString::number(SECTION_MENU) + "_" +
            QString::number(view) + "_" +
            QString::number(tool) + "_" +
            QString::number(section) + "_" );
883 884
}

885 886
void MainWindow::closeEvent(QCloseEvent *event)
{
887
    storeSettings();
888
    aboutToCloseFlag = true;
889
    mavlink->storeSettings();
890
    UASManager::instance()->storeSettings();
891 892
    QMainWindow::closeEvent(event);
}
893

894 895
void MainWindow::showDockWidget (bool vis)
{
896
    if (!aboutToCloseFlag && !changingViewsFlag) {
897 898
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

899
        if (temp) {
900
            QHashIterator<int, QWidget*> i(dockWidgets);
901
            while (i.hasNext()) {
902
                i.next();
903
                if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp) {
904 905 906 907 908 909 910 911 912
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
}
913

914 915
void MainWindow::updateVisibilitySettings (bool vis)
{
916
    if (!aboutToCloseFlag && !changingViewsFlag) {
917 918
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

919
        if (temp) {
920
            QHashIterator<int, QWidget*> i(dockWidgets);
921
            while (i.hasNext()) {
922
                i.next();
923
                if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp) {
924 925
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
926 927 928 929 930 931
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
932 933
}

934 935 936
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
937

938
    QHashIterator<int, QWidget*> i(dockWidgets);
939
    while (i.hasNext()) {
940
        i.next();
941
        if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp) {
942 943 944 945 946
            QString posKey = buildMenuKey (SUB_SECTION_LOCATION,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
            settings.setValue(posKey,location);
            break;
        }
    }
947 948
}

949

950 951 952
/**
 * Connect the signals and slots of the common window widgets
 */
953
void MainWindow::connectCommonWidgets()
954
{
955
    if (infoDockWidget && infoDockWidget->widget()) {
pixhawk's avatar
pixhawk committed
956 957 958
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
lm's avatar
lm committed
959 960 961 962 963
//    //TODO temporaly debug
//    if (slugsHilSimWidget && slugsHilSimWidget->widget()) {
//        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
//                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
//    }
964
}
965

966 967
void MainWindow::createCustomWidget()
{
968 969
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", dock);
lm's avatar
lm committed
970

971
    if (QGCToolWidget::instances()->size() < 2) {
lm's avatar
lm committed
972 973 974 975 976
        // This is the first widget
        ui.menuTools->addSeparator();
    }

    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
977
    dock->setWidget(tool);
978

979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    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));
    QGCToolWidget* tool = new QGCToolWidget("", this);
    tool->loadSettings(fileName);

    if (QGCToolWidget::instances()->size() < 2) {
        // This is the first widget
        ui.menuTools->addSeparator();
    }

    // Add widget to UI
    QDockWidget* dock = new QDockWidget(tool->getTitle(), this);
    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
    dock->setWidget(tool);
    tool->setParent(dock);

lm's avatar
lm committed
1007
    QAction* showAction = new QAction("Show Unnamed Tool", this);
1008
    showAction->setCheckable(true);
lm's avatar
lm committed
1009 1010 1011 1012 1013
    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);
1014
    dock->setVisible(true);
1015 1016 1017 1018
}

void MainWindow::connectPxWidgets()
{
1019
    // No special connections necessary at this point
1020 1021 1022 1023
}

void MainWindow::connectSlugsWidgets()
{
1024
    if (slugsHilSimWidget && slugsHilSimWidget->widget()) {
1025 1026
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
1027 1028
    }

1029
    if (slugsDataWidget && slugsDataWidget->widget()) {
1030 1031
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsDataWidget->widget(), SLOT(setActiveUAS(UASInterface*)));
1032 1033
    }

1034
    if (controlParameterWidget && controlParameterWidget->widget()) {
1035 1036 1037
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                controlParameterWidget->widget(), SLOT(activeUasSet(UASInterface*)));
    }
1038

1039 1040
    if(controlDockWidget && controlParameterWidget) {
        connect(controlDockWidget->widget(), SIGNAL(changedMode(int)), controlParameterWidget->widget(), SLOT(changedMode(int)));
1041
    }
1042 1043
}

1044
void MainWindow::arrangeCommonCenterStack()
1045
{
1046
    centerStack = new QStackedWidget(this);
1047
    centerStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1048

pixhawk's avatar
pixhawk committed
1049
    if (!centerStack) return;
1050

1051
    if (mapWidget && (centerStack->indexOf(mapWidget) == -1)) centerStack->addWidget(mapWidget);
lm's avatar
lm committed
1052
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
1053
    if (protocolWidget && (centerStack->indexOf(protocolWidget) == -1)) centerStack->addWidget(protocolWidget);
1054 1055 1056 1057 1058 1059 1060

    setCentralWidget(centerStack);
}

void MainWindow::arrangePxCenterStack()
{

1061 1062 1063 1064
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
1065

1066 1067

    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
1068

1069
#ifdef QGC_OSG_ENABLED
1070
    if (_3DWidget && (centerStack->indexOf(_3DWidget) == -1)) centerStack->addWidget(_3DWidget);
1071
#endif
1072
#ifdef QGC_OSGEARTH_ENABLED
1073
    if (_3DMapWidget && (centerStack->indexOf(_3DMapWidget) == -1)) centerStack->addWidget(_3DMapWidget);
1074
#endif
1075
#if (defined _MSC_VER) | (defined Q_OS_MAC)
1076
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
1077
#endif
1078 1079
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
1080 1081 1082 1083 1084
}

void MainWindow::arrangeSlugsCenterStack()
{

1085 1086 1087 1088
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
1089

1090 1091
    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
1092

1093 1094 1095 1096
#if (defined _MSC_VER) | (defined Q_OS_MAC)
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
#endif

1097 1098
}

1099 1100 1101 1102 1103 1104
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();
1105
    lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool();
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
    settings.endGroup();
}

void MainWindow::storeSettings()
{
    QSettings settings;
    settings.beginGroup("QGC_MAINWINDOW");
    settings.setValue("AUTO_RECONNECT", autoReconnect);
    settings.setValue("CURRENT_STYLE", currentStyle);
    settings.endGroup();
    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);
1123 1124
    // Save the current power mode
    settings.setValue("LOW_POWER_MODE", lowPowerMode);
1125 1126 1127
    settings.sync();
}

1128 1129
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
1130 1131 1132
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
1133

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

1136
    for (int i = 0; i < hostAddresses.size(); i++) {
pixhawk's avatar
pixhawk committed
1137
        // Exclude loopback IPv4 and all IPv6 addresses
1138
        if (hostAddresses.at(i) != QHostAddress("127.0.0.1") && !hostAddresses.at(i).toString().contains(":")) {
pixhawk's avatar
pixhawk committed
1139 1140 1141 1142 1143
            if(prevAddr) windowname.append("/");
            windowname.append(hostAddresses.at(i).toString());
            prevAddr = true;
        }
    }
1144

pixhawk's avatar
pixhawk committed
1145
    windowname.append(")");
1146

pixhawk's avatar
pixhawk committed
1147
    setWindowTitle(windowname);
1148 1149

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
1150
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
1151 1152 1153
#endif
}

pixhawk's avatar
pixhawk committed
1154
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
1155 1156 1157 1158 1159
{
    QString format = "bmp";
    QString initialPath = QDir::currentPath() + tr("/untitled.") + format;

    QString screenFileName = QFileDialog::getSaveFileName(this, tr("Save As"),
1160 1161 1162 1163
                             initialPath,
                             tr("%1 Files (*.%2);;All Files (*)")
                             .arg(format.toUpper())
                             .arg(format));
pixhawk's avatar
pixhawk committed
1164 1165
    delete videoTimer;
    videoTimer = new QTimer(this);
1166 1167 1168
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
1169 1170
}

pixhawk's avatar
pixhawk committed
1171
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
1172 1173 1174 1175 1176 1177
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
1178
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
1179 1180 1181 1182
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

1183
    if (!screenFileName.isEmpty()) {
pixhawk's avatar
pixhawk committed
1184 1185 1186 1187
        window.save(screenFileName, format.toAscii());
    }
}

1188
void MainWindow::enableAutoReconnect(bool enabled)
pixhawk's avatar
pixhawk committed
1189
{
1190 1191
    autoReconnect = enabled;
}
1192

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
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)
{
1210 1211 1212 1213 1214 1215 1216 1217 1218
    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."));
1219
        }
1220 1221
    }
    break;
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
    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;
}

1236
void MainWindow::selectStylesheet()
pixhawk's avatar
pixhawk committed
1237
{
1238
    // Let user select style sheet
1239
    styleFileName = QFileDialog::getOpenFileName(this, tr("Specify stylesheet"), styleFileName, tr("CSS Stylesheet (*.css);;"));
1240

1241
    if (!styleFileName.endsWith(".css")) {
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
        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
1252
    // Load style sheet
1253 1254 1255 1256 1257 1258 1259
    reloadStylesheet();
}

void MainWindow::reloadStylesheet()
{
    // Load style sheet
    QFile* styleSheet = new QFile(styleFileName);
1260
    if (!styleSheet->exists()) {
1261 1262
        styleSheet = new QFile(":/images/style-mission.css");
    }
1263
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text)) {
1264 1265
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
1266
        qApp->setStyleSheet(style);
1267
    } else {
1268 1269 1270
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(tr("QGroundControl did lot load a new style"));
1271
        msgBox.setInformativeText(tr("Stylesheet file %1 was not readable").arg(styleFileName));
1272 1273 1274
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
pixhawk's avatar
pixhawk committed
1275
    }
1276
    delete styleSheet;
pixhawk's avatar
pixhawk committed
1277 1278
}

1279 1280 1281 1282 1283 1284
/**
 * 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
1285
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
1286
{
lm's avatar
lm committed
1287
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
1288 1289
}

1290 1291 1292 1293 1294 1295
/**
 * 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
 */
1296
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
1297
{
lm's avatar
lm committed
1298
    statusBar()->showMessage(status, 20000);
1299 1300 1301 1302
}

void MainWindow::showCriticalMessage(const QString& title, const QString& message)
{
1303
    QMessageBox msgBox(this);
1304 1305 1306 1307 1308 1309
    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
1310 1311
}

lm's avatar
lm committed
1312 1313
void MainWindow::showInfoMessage(const QString& title, const QString& message)
{
1314
    QMessageBox msgBox(this);
lm's avatar
lm committed
1315 1316 1317 1318 1319 1320 1321 1322
    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
1323 1324 1325 1326
/**
* @brief Create all actions associated to the main window
*
**/
1327
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
1328
{
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
    ui.actionNewCustomWidget->setEnabled(false);

    // 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 pilot, engineer and operator view are not available on startup
    // since they only make sense with a system connected.
    ui.actionPilotsView->setEnabled(false);
    ui.actionOperatorsView->setEnabled(false);
    ui.actionEngineersView->setEnabled(false);
    // 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
1359 1360 1361 1362 1363
    // 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*)));
1364
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
pixhawk's avatar
pixhawk committed
1365

1366
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
1367 1368 1369 1370
    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()));
1371
    connect(ui.actionShutdownMAV, SIGNAL(triggered()), UASManager::instance(), SLOT(shutdownActiveUAS()));
pixhawk's avatar
pixhawk committed
1372 1373
    connect(ui.actionConfiguration, SIGNAL(triggered()), UASManager::instance(), SLOT(configureActiveUAS()));

1374
    // Views actions
1375
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
1376
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
1377
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
1378
    connect(ui.actionUnconnectedView, SIGNAL(triggered()), this, SLOT(loadUnconnectedView()));
1379

1380
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
1381 1382
    connect(ui.actionReloadStylesheet, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
    connect(ui.actionSelectStylesheet, SIGNAL(triggered()), this, SLOT(selectStylesheet()));
1383

1384
    // Help Actions
1385
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
1386
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
1387
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
1388 1389 1390

    // Custom widget actions
    connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget()));
1391
    connect(ui.actionLoadCustomWidgetFile, SIGNAL(triggered()), this, SLOT(loadCustomWidget()));
1392 1393 1394

    // Audio output
    ui.actionMuteAudioOutput->setChecked(GAudioOutput::instance()->isMuted());
1395
    connect(GAudioOutput::instance(), SIGNAL(mutedChanged(bool)), ui.actionMuteAudioOutput, SLOT(setChecked(bool)));
1396
    connect(ui.actionMuteAudioOutput, SIGNAL(triggered(bool)), GAudioOutput::instance(), SLOT(mute(bool)));
1397 1398 1399 1400 1401 1402 1403

    // 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);
1404 1405 1406

    // Configuration
    // Joystick
1407
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
1408 1409
    // Application Settings
    connect(ui.actionSettings, SIGNAL(triggered()), this, SLOT(showSettings()));
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
}

void MainWindow::connectPxActions()
{


}

void MainWindow::connectSlugsActions()
{
1420

pixhawk's avatar
pixhawk committed
1421 1422
}

1423 1424
void MainWindow::showHelp()
{
1425
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/"))) {
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
        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()
{
1438
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits/"))) {
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
        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()
{
1451
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap/"))) {
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
        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
1462
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
1463
{
1464 1465
    if (!joystickWidget) {
        if (!joystick->isRunning()) {
1466 1467 1468 1469 1470
            joystick->start();
        }
        joystickWidget = new JoystickWidget(joystick);
    }
    joystickWidget->show();
pixhawk's avatar
pixhawk committed
1471 1472
}

1473 1474 1475 1476 1477 1478
void MainWindow::showSettings()
{
    QGCSettingsWidget* settings = new QGCSettingsWidget(this);
    settings->show();
}

pixhawk's avatar
pixhawk committed
1479
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
1480 1481 1482 1483
{
    SerialLink* link = new SerialLink();
    // TODO This should be only done in the dialog itself

1484
    LinkManager::instance()->add(link);
pixhawk's avatar
pixhawk committed
1485 1486
    LinkManager::instance()->addProtocol(link, mavlink);

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

1490 1491
    foreach (QAction* act, actions) {
        if (act->data().toInt() == LinkManager::instance()->getLinks().indexOf(link)) {
1492 1493 1494 1495
            act->trigger();
            break;
        }
    }
pixhawk's avatar
pixhawk committed
1496 1497
}

pixhawk's avatar
pixhawk committed
1498 1499
void MainWindow::addLink(LinkInterface *link)
{
1500 1501 1502 1503
    // 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)
1504
    LinkManager::instance()->add(link);
1505
    LinkManager::instance()->addProtocol(link, mavlink);
1506

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

1510
    bool found = false;
1511

1512 1513
    foreach (QAction* act, actions) {
        if (act->data().toInt() == LinkManager::instance()->getLinks().indexOf(link)) {
1514 1515 1516 1517 1518
            found = true;
        }
    }

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

1520
    if (!found || udp) {
1521 1522 1523 1524 1525 1526 1527 1528
        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);
1529
        if (sim) {
1530 1531 1532
            //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
1533 1534 1535
    }
}

1536 1537 1538 1539 1540 1541 1542
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);
}

1543 1544 1545
void MainWindow::UASSpecsChanged(int uas)
{
    UASInterface* activeUAS = UASManager::instance()->getActiveUAS();
1546 1547
    if (activeUAS) {
        if (activeUAS->getUASID() == uas) {
1548 1549 1550 1551 1552
            ui.menuUnmanned_System->setTitle(activeUAS->getUASName());
        }
    }
}

pixhawk's avatar
pixhawk committed
1553
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1554
{
1555

pixhawk's avatar
pixhawk committed
1556 1557
    // Connect the UAS to the full user interface

1558
    if (uas != NULL) {
1559 1560 1561 1562
        // Set default settings
        setDefaultSettingsForAp();

        // The pilot, operator and engineer views were not available on startup, enable them now
1563
        ui.actionPilotsView->setEnabled(true);
1564 1565
        ui.actionOperatorsView->setEnabled(true);
        ui.actionEngineersView->setEnabled(true);
1566 1567 1568 1569 1570 1571
        // 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);
1572

1573 1574
        QIcon icon;
        // Set matching icon
1575
        switch (uas->getSystemType()) {
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
        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;
        }

1599 1600 1601
        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()));
1602
        connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int)));
1603 1604

        ui.menuConnected_Systems->addAction(uasAction);
1605 1606

        // FIXME Should be not inside the mainwindow
1607
        if (debugConsoleDockWidget) {
pixhawk's avatar
pixhawk committed
1608
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
1609
            if (debugConsole) {
pixhawk's avatar
pixhawk committed
1610 1611 1612
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1613
        }
1614 1615

        // Health / System status indicator
1616
        if (infoDockWidget) {
pixhawk's avatar
pixhawk committed
1617
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
1618
            if (infoWidget) {
pixhawk's avatar
pixhawk committed
1619 1620
                infoWidget->addUAS(uas);
            }
1621
        }
1622 1623

        // UAS List
1624
        if (listDockWidget) {
pixhawk's avatar
pixhawk committed
1625
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
1626
            if (listWidget) {
pixhawk's avatar
pixhawk committed
1627 1628
                listWidget->addUAS(uas);
            }
1629
        }
1630

1631 1632 1633 1634
        switch (uas->getAutopilotType()) {
        case (MAV_AUTOPILOT_SLUGS): {
            // Build Slugs Widgets
            buildSlugsWidgets();
1635

1636 1637
            // Connect Slugs Widgets
            connectSlugsWidgets();
1638

1639 1640
            // Arrange Slugs Centerstack
            arrangeSlugsCenterStack();
1641

1642 1643
            // Connect Slugs Actions
            connectSlugsActions();
1644

1645 1646 1647 1648 1649 1650 1651 1652 1653
//                if(slugsDataWidget)
//                {
//                    SlugsDataSensorView *mm = dynamic_cast<SlugsDataSensorView*>(slugsDataWidget->widget());
//                    if(mm)
//                    {
//                        mm->addUAS(uas);
//                    }
//                }

1654
            // FIXME: This type checking might be redundant
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
//                //            if (slugsDataWidget) {
//                //              SlugsDataSensorView* dataWidget = dynamic_cast<SlugsDataSensorView*>(slugsDataWidget->widget());
//                //              if (dataWidget) {
//                //                SlugsMAV* mav2 = dynamic_cast<SlugsMAV*>(uas);
//                //                if (mav2) {
//                (dynamic_cast<SlugsDataSensorView*>(slugsDataWidget->widget()))->addUAS(uas);
//                //                  //loadSlugsView();
//                //                  loadGlobalOperatorView();
//                //                }
//                //              }
//                //            }
1666

1667 1668
        }
        break;
1669 1670 1671
        default:
        case (MAV_AUTOPILOT_GENERIC):
        case (MAV_AUTOPILOT_ARDUPILOTMEGA):
1672 1673 1674
        case (MAV_AUTOPILOT_PIXHAWK): {
            // Build Pixhawk Widgets
            buildPxWidgets();
1675

1676 1677
            // Connect Pixhawk Widgets
            connectPxWidgets();
1678

1679 1680
            // Arrange Pixhawk Centerstack
            arrangePxCenterStack();
1681

1682 1683 1684 1685
            // Connect Pixhawk Actions
            connectPxActions();
        }
        break;
1686 1687 1688 1689 1690 1691
        }

        // 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
1692
        if (UASManager::instance()->getUASList().size() == 1) {
1693
            // Load last view if setting is present
1694
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED")) {
1695
                clearView();
1696
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1697
                switch (view) {
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
                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;
1714
                }
1715
            } else {
1716
                loadOperatorView();
1717
            }
1718
        }
1719

1720
    }
1721 1722

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

    // Custom widgets, added last to all menus and layouts
    buildCustomWidget();
1726
    // Restore the mainwindow size
1727
    if (settings.contains(getWindowGeometryKey())) {
1728 1729
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
    }
pixhawk's avatar
pixhawk committed
1730 1731
}

1732 1733 1734
/**
 * Clears the current view completely
 */
pixhawk's avatar
pixhawk committed
1735
void MainWindow::clearView()
1736
{
1737
    // Save current state
1738
    if (UASManager::instance()->getUASList().count() > 0) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
1739 1740 1741 1742
    // Although we want save the state of the window, we do not want to change the top-leve state (minimized, maximized, etc)
    // therefore this state is stored here and restored after applying the rest of the settings in the new
    // perspective.
    windowStateVal = this->windowState();
1743
    settings.setValue(getWindowGeometryKey(), saveGeometry());
1744 1745 1746 1747

    QAction* temp;

    // Set tool widget visibility settings for this view
1748
    foreach (int key, toolsMenuActions.keys()) {
1749 1750 1751
        temp = toolsMenuActions[key];
        QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(key), currentView);

1752
        if (temp) {
1753
            //qDebug() << "TOOL:" << chKey << "IS:" << temp->isChecked();
1754
            settings.setValue(chKey,temp->isChecked());
1755
        } else {
1756
            //qDebug() << "TOOL:" << chKey << "IS DEFAULT AND UNCHECKED";
1757 1758 1759 1760
            settings.setValue(chKey,false);
        }
    }

1761
    changingViewsFlag = true;
1762 1763
    // Remove all dock widgets from main window
    QObjectList childList( this->children() );
pixhawk's avatar
pixhawk committed
1764

1765 1766
    QObjectList::iterator i;
    QDockWidget* dockWidget;
1767
    for (i = childList.begin(); i != childList.end(); ++i) {
1768
        dockWidget = dynamic_cast<QDockWidget*>(*i);
1769
        if (dockWidget) {
1770
            // Remove dock widget from main window
1771
            removeDockWidget(dockWidget);
1772
            dockWidget->hide();
1773
            //dockWidget->setVisible(false);
pixhawk's avatar
pixhawk committed
1774 1775
        }
    }
1776
    changingViewsFlag = false;
pixhawk's avatar
pixhawk committed
1777 1778
}

1779
void MainWindow::loadEngineerView()
lm's avatar
lm committed
1780
{
1781
    if (currentView != VIEW_ENGINEER) {
1782 1783 1784 1785
        clearView();
        currentView = VIEW_ENGINEER;
        ui.actionEngineersView->setChecked(true);
        presentView();
1786
    }
lm's avatar
lm committed
1787 1788
}

1789
void MainWindow::loadOperatorView()
lm's avatar
lm committed
1790
{
1791
    if (currentView != VIEW_OPERATOR) {
1792 1793 1794 1795 1796 1797
        clearView();
        currentView = VIEW_OPERATOR;
        ui.actionOperatorsView->setChecked(true);
        presentView();
    }
}
lm's avatar
lm committed
1798

1799 1800
void MainWindow::loadUnconnectedView()
{
1801
    if (currentView != VIEW_UNCONNECTED) {
1802 1803 1804 1805
        clearView();
        currentView = VIEW_UNCONNECTED;
        ui.actionUnconnectedView->setChecked(true);
        presentView();
1806
    }
lm's avatar
lm committed
1807 1808
}

1809
void MainWindow::loadPilotView()
1810
{
1811
    if (currentView != VIEW_PILOT) {
1812 1813 1814 1815
        clearView();
        currentView = VIEW_PILOT;
        ui.actionPilotsView->setChecked(true);
        presentView();
1816
    }
1817 1818
}

1819
void MainWindow::loadMAVLinkView()
1820
{
1821
    if (currentView != VIEW_MAVLINK) {
1822 1823 1824 1825
        clearView();
        currentView = VIEW_MAVLINK;
        ui.actionMavlinkView->setChecked(true);
        presentView();
1826
    }
1827 1828
}

lm's avatar
lm committed
1829 1830
void MainWindow::presentView()
{
1831
    // LINE CHART
1832
    showTheCentralWidget(CENTRAL_LINECHART, currentView);
1833

1834 1835
    // MAP
    showTheCentralWidget(CENTRAL_MAP, currentView);
pixhawk's avatar
pixhawk committed
1836

1837 1838
    // PROTOCOL
    showTheCentralWidget(CENTRAL_PROTOCOL, currentView);
pixhawk's avatar
pixhawk committed
1839

1840 1841
    // HEAD UP DISPLAY
    showTheCentralWidget(CENTRAL_HUD, currentView);
pixhawk's avatar
pixhawk committed
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851

    // GOOGLE EARTH
    showTheCentralWidget(CENTRAL_GOOGLE_EARTH, currentView);

    // LOCAL 3D VIEW
    showTheCentralWidget(CENTRAL_3D_LOCAL, currentView);

    // GLOBAL 3D VIEW
    showTheCentralWidget(CENTRAL_3D_MAP, currentView);

1852 1853 1854
    // DATA PLOT
    showTheCentralWidget(CENTRAL_DATA_PLOT, currentView);

pixhawk's avatar
pixhawk committed
1855

1856
    // Show docked widgets based on current view and autopilot type
1857

1858 1859
    // UAS CONTROL
    showTheWidget(MENU_UAS_CONTROL, currentView);
1860

1861 1862
    showTheWidget(MENU_UAS_CONTROL_PARAM, currentView);

1863 1864
    // UAS LIST
    showTheWidget(MENU_UAS_LIST, currentView);
1865

1866 1867
    // WAYPOINT LIST
    showTheWidget(MENU_WAYPOINTS, currentView);
pixhawk's avatar
pixhawk committed
1868

1869 1870
    // UAS STATUS
    showTheWidget(MENU_STATUS, currentView);
1871

1872 1873
    // DETECTION
    showTheWidget(MENU_DETECTION, currentView);
1874

1875 1876
    // DEBUG CONSOLE
    showTheWidget(MENU_DEBUG_CONSOLE, currentView);
1877

1878 1879
    // ONBOARD PARAMETERS
    showTheWidget(MENU_PARAMETERS, currentView);
1880

1881 1882
    // WATCHDOG
    showTheWidget(MENU_WATCHDOG, currentView);
1883

1884 1885
    // HUD
    showTheWidget(MENU_HUD, currentView);
1886
    if (headUpDockWidget) {
1887
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1888 1889
        if (tmpHud) {
            if (settings.value(buildMenuKey (SUB_SECTION_CHECKED,MENU_HUD,currentView)).toBool()) {
1890
                addDockWidget(static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,MENU_HUD, currentView)).toInt()),
1891
                              headUpDockWidget);
1892
                headUpDockWidget->show();
1893
            } else {
1894 1895
                headUpDockWidget->hide();
            }
1896
        }
1897
    }
1898

1899

1900 1901
    // RC View
    showTheWidget(MENU_RC_VIEW, currentView);
1902

1903 1904
    // SLUGS DATA
    showTheWidget(MENU_SLUGS_DATA, currentView);
1905

1906 1907
    // SLUGS PID
    showTheWidget(MENU_SLUGS_PID, currentView);
1908

1909 1910
    // SLUGS HIL
    showTheWidget(MENU_SLUGS_HIL, currentView);
1911

1912 1913
    // SLUGS CAMERA
    showTheWidget(MENU_SLUGS_CAMERA, currentView);
1914

1915 1916
    // HORIZONTAL SITUATION INDICATOR
    showTheWidget(MENU_HSI, currentView);
1917

1918 1919 1920 1921 1922
    // HEAD DOWN 1
    showTheWidget(MENU_HDD_1, currentView);

    // HEAD DOWN 2
    showTheWidget(MENU_HDD_2, currentView);
1923

1924 1925 1926
    // MAVLINK LOG PLAYER
    showTheWidget(MENU_MAVLINK_LOG_PLAYER, currentView);

1927 1928 1929 1930 1931 1932 1933
    // VIDEO 1
    showTheWidget(MENU_VIDEO_STREAM_1, currentView);

    // VIDEO 2
    showTheWidget(MENU_VIDEO_STREAM_2, currentView);

    // Restore window state
1934
    if (UASManager::instance()->getUASList().count() > 0) {
1935 1936 1937 1938 1939
//        // Restore the mainwindow size
//        if (settings.contains(getWindowGeometryKey()))
//        {
//            restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
//        }
1940 1941

        // Restore the widget positions and size
1942
        if (settings.contains(getWindowStateKey())) {
1943 1944 1945
            restoreState(settings.value(getWindowStateKey()).toByteArray(), QGC::applicationVersion());
        }
    }
lm's avatar
lm committed
1946

1947
    // ACTIVATE HUD WIDGET
1948
    if (headUpDockWidget) {
lm's avatar
lm committed
1949
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1950
        if (tmpHud) {
lm's avatar
lm committed
1951 1952 1953 1954

        }
    }

1955
    this->setWindowState(windowStateVal);
lm's avatar
lm committed
1956
    this->show();
1957
}
1958

1959 1960 1961 1962
void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SECTIONS view)
{
    bool tempVisible;
    QWidget* tempWidget = dockWidgets[centralWidget];
1963

1964
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
1965
    //qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
1966
    if (toolsMenuActions[centralWidget]) {
1967
        //qDebug() << "SETTING TO:" << tempVisible;
1968
        toolsMenuActions[centralWidget]->setChecked(tempVisible);
1969
    }
1970

1971
    if (centerStack && tempWidget && tempVisible) {
1972
        //qDebug() << "ACTIVATING MAIN WIDGET";
1973
        centerStack->setCurrentWidget(tempWidget);
1974
    }
1975 1976
}

1977 1978
void MainWindow::loadDataView(QString fileName)
{
1979
    clearView();
1980 1981 1982 1983 1984

    // Unload line chart
    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(CENTRAL_LINECHART), currentView);
    settings.setValue(chKey,false);

1985
    // Set data plot in settings as current widget and then run usual update procedure
1986
    chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(CENTRAL_DATA_PLOT), currentView);
1987
    settings.setValue(chKey,true);
1988

1989
    presentView();
1990

1991
    // Plot is now selected, now load data from file
1992
    if (dataplotWidget) {
1993
        dataplotWidget->loadFile(fileName);
1994
    }
1995 1996 1997 1998 1999 2000 2001
//        QStackedWidget *centerStack = dynamic_cast<QStackedWidget*>(centralWidget());
//        if (centerStack)
//        {
//            centerStack->setCurrentWidget(dataplotWidget);
//            dataplotWidget->loadFile(fileName);
//        }
//    }
2002 2003 2004
}


oberion's avatar
oberion committed
2005 2006 2007 2008
QList<QAction*> MainWindow::listLinkMenuActions(void)
{
	return ui.menuNetwork->actions();
}