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

lm's avatar
lm committed
160 161 162 163 164
    // Connect flighgear test link
    // FIXME MOVE INTO UAV OBJECT
    fgLink = new QGCFlightGearLink();
    fgLink->connectSimulation();

165 166 167 168 169 170 171 172
    // 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
173 174
    // Enable and update view
    presentView();
175 176

    // Connect link
177
    if (autoReconnect) {
178 179 180 181 182 183
        SerialLink* link = new SerialLink();
        // Add to registry
        LinkManager::instance()->add(link);
        LinkManager::instance()->addProtocol(link, mavlink);
        link->connect();
    }
184

185 186 187
    // Set low power mode
    enableLowPowerMode(lowPowerMode);

188 189
    // Initialize window state
    windowStateVal = windowState();
pixhawk's avatar
pixhawk committed
190 191
}

pixhawk's avatar
pixhawk committed
192
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
193
{
194 195 196
    // Store settings
    storeSettings();

197
    delete mavlink;
198
    delete joystick;
lm's avatar
lm committed
199

200 201 202 203 204 205
    // Get and delete all dockwidgets and contained
    // widgets
    QObjectList childList( this->children() );

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

217 218 219 220 221 222 223 224 225
/**
 * 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);
226
    if (!settings.contains(centralKey)) {
227
        settings.setValue(centralKey,true);
228 229 230 231 232

        // 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);
233 234 235 236
    }

    // OPERATOR VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_MAP, VIEW_OPERATOR);
237
    if (!settings.contains(centralKey)) {
238 239 240 241
        settings.setValue(centralKey,true);

        // ENABLE UAS LIST
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_UAS_LIST,VIEW_OPERATOR), true);
242 243
        // ENABLE HUD TOOL WIDGET
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_HUD,VIEW_OPERATOR), true);
244 245
        // ENABLE WAYPOINTS
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_WAYPOINTS,VIEW_OPERATOR), true);
246 247 248 249
    }

    // ENGINEER VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_LINECHART, VIEW_ENGINEER);
250
    if (!settings.contains(centralKey)) {
251
        settings.setValue(centralKey,true);
252 253
        // Enable Parameter widget
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_PARAMETERS,VIEW_ENGINEER), true);
254 255 256 257
    }

    // MAVLINK VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_PROTOCOL, VIEW_MAVLINK);
258
    if (!settings.contains(centralKey)) {
259 260 261 262 263
        settings.setValue(centralKey,true);
    }

    // PILOT VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_HUD, VIEW_PILOT);
264
    if (!settings.contains(centralKey)) {
265
        settings.setValue(centralKey,true);
266 267
        // Enable Flight display
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_HDD_1,VIEW_PILOT), true);
268 269 270
    }
}

lm's avatar
lm committed
271 272 273
void MainWindow::resizeEvent(QResizeEvent * event)
{
    Q_UNUSED(event);
274
    if (height() < 800) {
lm's avatar
lm committed
275
        ui.statusBar->setVisible(false);
276
    } else {
lm's avatar
lm committed
277
        ui.statusBar->setVisible(true);
278
        ui.statusBar->setSizeGripEnabled(true);
lm's avatar
lm committed
279 280 281
    }
}

282 283
QString MainWindow::getWindowStateKey()
{
284
    return QString::number(currentView)+"_windowstate";
285 286 287 288
}

QString MainWindow::getWindowGeometryKey()
{
289 290
    //return QString::number(currentView)+"_geometry";
    return "_geometry";
291 292
}

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

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

303
        if (widgets.size() > 0) {
lm's avatar
lm committed
304 305 306
            ui.menuTools->addSeparator();
        }

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

                // 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
330 331 332 333 334
            }
        }
    }
}

335 336 337 338
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
339
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
340 341

    // Dock widgets
342
    if (!controlDockWidget) {
343
        controlDockWidget = new QDockWidget(tr("Control"), this);
344
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
345
        controlDockWidget->setWidget( new UASControlWidget(this) );
346
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget(bool)), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
347
    }
348

349
    if (!listDockWidget) {
350 351
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
352
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
353
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget(bool)), MENU_UAS_LIST, Qt::RightDockWidgetArea);
354
    }
355

356
    if (!waypointsDockWidget) {
357
        waypointsDockWidget = new QDockWidget(tr("Mission Plan"), this);
358
        waypointsDockWidget->setWidget( new QGCWaypointListMulti(this) );
359
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
360
        addToToolsMenu (waypointsDockWidget, tr("Mission Plan"), SLOT(showToolWidget(bool)), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
361
    }
362

363
    if (!infoDockWidget) {
364 365
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
366
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
367
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget(bool)), MENU_STATUS, Qt::RightDockWidgetArea);
368
    }
369

370
    if (!debugConsoleDockWidget) {
371 372
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
373
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
374
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget(bool)), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
375
    }
376

377
    if (!logPlayerDockWidget) {
378 379 380
        logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
        logPlayerDockWidget->setWidget( new QGCMAVLinkLogPlayer(mavlink, this) );
        logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
381
        addToToolsMenu(logPlayerDockWidget, tr("MAVLink Log Replay"), SLOT(showToolWidget(bool)), MENU_MAVLINK_LOG_PLAYER, Qt::RightDockWidgetArea);
382 383
    }

384
    // Center widgets
385 386
    if (!mapWidget)
    {
387
        mapWidget = new QGCMapTool(this);
388 389
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
390

391
    if (!protocolWidget) {
392 393 394
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
395

396
    if (!dataplotWidget) {
lm's avatar
lm committed
397
        dataplotWidget    = new QGCDataPlot2D(this);
398
        addToCentralWidgetsMenu (dataplotWidget, "Logfile Plot", SLOT(showCentralWidget()),CENTRAL_DATA_PLOT);
lm's avatar
lm committed
399
    }
400

401

402
}
403

404

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

pixhawk's avatar
pixhawk committed
413 414 415
    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");
416
    acceptList->append("0,airspeed,m/s,30");
417 418
    acceptList->append("0,groundspeed,m/s,30");
    acceptList->append("0,climbrate,m/s,30");
419
    acceptList->append("0,throttle,%,100");
420

pixhawk's avatar
pixhawk committed
421 422
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
423 424 425 426 427 428 429 430
    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
431
    acceptList2->append("0,abs pressure,hPa,65500");
432 433 434
    //acceptList2->append("-2048,accel. x,raw,2048,s");
    //acceptList2->append("-2048,accel. y,raw,2048,s");
    //acceptList2->append("-2048,accel. z,raw,2048,s");
435

436
    if (!linechartWidget) {
437 438
        // Center widgets
        linechartWidget   = new Linecharts(this);
439
        addToCentralWidgetsMenu(linechartWidget, tr("Realtime Plot"), SLOT(showCentralWidget()), CENTRAL_LINECHART);
440
    }
441 442


443
    if (!hudWidget) {
444
        hudWidget         = new HUD(320, 240, this);
445
        addToCentralWidgetsMenu(hudWidget, tr("Head Up Display"), SLOT(showCentralWidget()), CENTRAL_HUD);
446
    }
447

448
    if (!dataplotWidget) {
449
        dataplotWidget    = new QGCDataPlot2D(this);
450
        addToCentralWidgetsMenu(dataplotWidget, "Logfile Plot", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
451
    }
452

453
#ifdef QGC_OSG_ENABLED
454
    if (!_3DWidget) {
455
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
456
        addToCentralWidgetsMenu(_3DWidget, tr("Local 3D"), SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
457
    }
458
#endif
459

460
#ifdef QGC_OSGEARTH_ENABLED
461
    if (!_3DMapWidget) {
462
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
463
        addToCentralWidgetsMenu(_3DMapWidget, tr("OSG Earth 3D"), SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
464
    }
465
#endif
lm's avatar
lm committed
466

467
#if (defined _MSC_VER) | (defined Q_OS_MAC)
468
    if (!gEarthWidget) {
469
        gEarthWidget = new QGCGoogleEarthView(this);
470
        addToCentralWidgetsMenu(gEarthWidget, tr("Google Earth"), SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
471
    }
472

473
#endif
474

pixhawk's avatar
pixhawk committed
475
    // Dock widgets
476

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

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

491
    if (!watchdogControlDockWidget) {
492 493
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
pixhawk's avatar
pixhawk committed
494
        watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
495
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget(bool)), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
496
    }
497

498
    if (!hsiDockWidget) {
499 500
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
501
        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
502
        addToToolsMenu (hsiDockWidget, tr("Horizontal Situation"), SLOT(showToolWidget(bool)), MENU_HSI, Qt::BottomDockWidgetArea);
503
    }
504

505
    if (!headDown1DockWidget) {
506 507
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
508
        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
509
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget(bool)), MENU_HDD_1, Qt::RightDockWidgetArea);
510
    }
511

512
    if (!headDown2DockWidget) {
513 514
        headDown2DockWidget = new QDockWidget(tr("Actuator Status"), this);
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Actuator Status", this) );
515
        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
516
        addToToolsMenu (headDown2DockWidget, tr("Actuator Status"), SLOT(showToolWidget(bool)), MENU_HDD_2, Qt::RightDockWidgetArea);
517
    }
518

519
    if (!rcViewDockWidget) {
520 521
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
522
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
523
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget(bool)), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
524
    }
525

526
    if (!headUpDockWidget) {
527 528
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
529
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
530
        addToToolsMenu (headUpDockWidget, tr("Head Up Display"), SLOT(showToolWidget(bool)), MENU_HUD, Qt::RightDockWidgetArea);
531
    }
532

533
    if (!video1DockWidget) {
pixhawk's avatar
pixhawk committed
534 535 536 537 538 539 540
        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");
541
        addToToolsMenu (video1DockWidget, tr("Video Stream 1"), SLOT(showToolWidget(bool)), MENU_VIDEO_STREAM_1, Qt::LeftDockWidgetArea);
pixhawk's avatar
pixhawk committed
542 543
    }

544
    if (!video2DockWidget) {
pixhawk's avatar
pixhawk committed
545 546 547 548 549 550 551
        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");
552
        addToToolsMenu (video2DockWidget, tr("Video Stream 2"), SLOT(showToolWidget(bool)), MENU_VIDEO_STREAM_2, Qt::LeftDockWidgetArea);
553
    }
554

pixhawk's avatar
pixhawk committed
555 556
    // Dialogue widgets
    //FIXME: free memory in destructor
557 558 559 560
}

void MainWindow::buildSlugsWidgets()
{
561
    if (!linechartWidget) {
562 563
        // Center widgets
        linechartWidget   = new Linecharts(this);
564
        addToCentralWidgetsMenu(linechartWidget, tr("Realtime Plot"), SLOT(showCentralWidget()), CENTRAL_LINECHART);
565
    }
566

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

575
    if (!rcViewDockWidget) {
576 577
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
pixhawk's avatar
pixhawk committed
578
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
579
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget(bool)), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
580
    }
581

582
#if (defined _MSC_VER) | (defined Q_OS_MAC)
583
    if (!gEarthWidget) {
584 585 586 587 588 589
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, tr("Google Earth"), SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }

#endif

590
    if (!slugsDataWidget) {
591 592 593 594 595 596
        // 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);
    }
597

598

599
    if (!slugsHilSimWidget) {
600 601 602 603 604
        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);
    }
605

606 607
    if (!controlParameterWidget) {
        controlParameterWidget = new QDockWidget(tr("Control Parameters"), this);
608 609 610
        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);
611
    }
612

613
    if (!parametersDockWidget) {
614 615 616 617 618 619
        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);
    }

620
    if (!slugsCamControlWidget) {
621 622 623 624 625
        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);
    }
626

627
}
628 629 630


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
631 632 633
        const QString title,
        const char * slotName,
        TOOLS_WIDGET_NAMES centralWidget)
634
{
635
    QAction* tempAction;
636

637

638
// Not needed any more - separate menu now available
639

640 641 642 643 644 645 646
//    // 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);
//    }
647

648
    tempAction = ui.menuMain->addAction(title);
649

650 651
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
652

653 654 655
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
656

657
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
658

659
    if (!settings.contains(chKey)) {
660 661
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
662
    } else {
663 664
        tempAction->setChecked(settings.value(chKey).toBool());
    }
665

666
    // connect the action
667
    connect(tempAction,SIGNAL(triggered(bool)),this, slotName);
668 669 670
}


lm's avatar
lm committed
671 672
void MainWindow::showCentralWidget()
{
673
    QAction* senderAction = qobject_cast<QAction *>(sender());
674 675 676 677

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

678 679
    int tool = senderAction->data().toInt();
    QString chKey;
680

681
    // check the current action
682

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

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

702
        // check the current action
703
        //qDebug() << senderAction->text();
704
        senderAction->setChecked(true);
705

706 707
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
708

709 710 711
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
712

713 714 715
        // Unblock sender action
        senderAction->blockSignals(false);

716 717
        presentView();
    }
718
}
719

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

733

734
    if (toolsMenuActions[CENTRAL_SEPARATOR]) {
735 736 737
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
738
    } else {
739 740
        tempAction = ui.menuTools->addAction(title);
    }
741

742 743
    tempAction->setCheckable(true);
    tempAction->setData(tool);
744

745 746 747
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
748
    //qDebug() << widget;
749

750
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
751

752
    if (!settings.contains(posKey)) {
753 754
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
755
    } else {
756
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
757
    }
758

759
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
760

761
    if (!settings.contains(chKey)) {
762 763
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
764
        widget->setVisible(false);
765
    } else {
766
        tempAction->setChecked(settings.value(chKey, false).toBool());
767
        widget->setVisible(settings.value(chKey, false).toBool());
768
    }
769

770
    // connect the action
771 772 773
    connect(tempAction,SIGNAL(toggled(bool)),this, slotName);

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

776 777
    //  connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
    //          SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
778

779 780
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
781 782
}

783
void MainWindow::showToolWidget(bool visible)
784
{
785
    if (!aboutToCloseFlag && !changingViewsFlag) {
786 787
        QAction* action = qobject_cast<QAction *>(sender());

788
        // Prevent this to fire if undocked
789
        if (action) {
790
            int tool = action->data().toInt();
791

792
            QDockWidget* dockWidget = qobject_cast<QDockWidget *> (dockWidgets[tool]);
793

794 795
            if (dockWidget && dockWidget->isVisible() != visible) {
                if (visible) {
796 797
                    addDockWidget(dockWidgetLocations[tool], dockWidget);
                    dockWidget->show();
798
                } else {
799 800
                    removeDockWidget(dockWidget);
                }
801 802

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

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

817
        //qDebug() << "Trying to cast dockwidget" << dockWidget << "isvisible" << visible;
818

819
        if (dockWidget) {
820 821 822
            // Get action
            int tool = dockWidgets.key(dockWidget);

823
            //qDebug() << "Updating widget setting" << tool << "to" << visible;
824 825 826 827 828 829 830

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

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


845 846 847 848 849
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
850

851
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
852

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

855
    if (tempWidget) {
856 857
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
858 859


860
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
861

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

864 865
    if (tempWidget != NULL) {
        if (tempVisible) {
866 867 868
            addDockWidget(tempLocation, tempWidget);
            tempWidget->show();
        }
869 870
    }
}
871

872 873 874 875 876
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;

877 878 879 880 881
//    apType = (UASManager::instance() && UASManager::instance()->silentGetActiveUAS())?
//             UASManager::instance()->getActiveUAS()->getAutopilotType():
//             -1;

    apType = 1;
882

883 884 885 886 887
    return (QString::number(apType) + "_" +
            QString::number(SECTION_MENU) + "_" +
            QString::number(view) + "_" +
            QString::number(tool) + "_" +
            QString::number(section) + "_" );
888 889
}

890 891
void MainWindow::closeEvent(QCloseEvent *event)
{
892
    storeSettings();
893
    aboutToCloseFlag = true;
894
    mavlink->storeSettings();
895
    UASManager::instance()->storeSettings();
896 897
    QMainWindow::closeEvent(event);
}
898

899 900
void MainWindow::showDockWidget (bool vis)
{
901
    if (!aboutToCloseFlag && !changingViewsFlag) {
902 903
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

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

919 920
void MainWindow::updateVisibilitySettings (bool vis)
{
921
    if (!aboutToCloseFlag && !changingViewsFlag) {
922 923
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

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

939 940 941
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
942

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

954

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

971 972
void MainWindow::createCustomWidget()
{
973 974
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", dock);
lm's avatar
lm committed
975

976
    if (QGCToolWidget::instances()->size() < 2) {
lm's avatar
lm committed
977 978 979 980 981
        // This is the first widget
        ui.menuTools->addSeparator();
    }

    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater