MainWindow.cc 80 KB
Newer Older
1
2
3
4
/*=====================================================================

QGroundControl Open Source Ground Control Station

Lorenz Meier's avatar
Lorenz Meier committed
5
(c) 2009 - 2013 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

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/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of class MainWindow
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
 */

#include <QSettings>
#include <QDockWidget>
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>
#include <QHostInfo>
#include <QSplashScreen>
#include <QGCHilLink.h>
#include <QGCHilConfiguration.h>
#include <QGCHilFlightGearConfiguration.h>
41
#include <QDeclarativeView>
42
#include "dockwidgettitlebareventfilter.h"
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "QGC.h"
#include "MAVLinkSimulationLink.h"
#include "SerialLink.h"
#include "UDPLink.h"
#include "MAVLinkProtocol.h"
#include "CommConfigurationWindow.h"
#include "QGCWaypointListMulti.h"
#include "MainWindow.h"
#include "JoystickWidget.h"
#include "GAudioOutput.h"
#include "QGCToolWidget.h"
#include "QGCMAVLinkLogPlayer.h"
#include "QGCSettingsWidget.h"
#include "QGCMapTool.h"
#include "MAVLinkDecoder.h"
#include "QGCMAVLinkMessageSender.h"
#include "QGCRGBDView.h"
#include "QGCFirmwareUpdate.h"
61
#include "QGCStatusBar.h"
62
#include "UASQuickView.h"
63
64
#include "QGCDataPlot2D.h"
#include "Linecharts.h"
65
66
67
#include "UASActionsWidget.h"
#include "QGCTabbedInfoView.h"
#include "UASRawStatusView.h"
68
#include "PrimaryFlightDisplay.h"
69
70
71
#include <apmtoolbar.h>
#include <ApmHardwareConfig.h>
#include <ApmSoftwareConfig.h>
72
#include <QGCConfigView.h>
73
74
75
76
77
78
79
80
81
82
83

#ifdef QGC_OSG_ENABLED
#include "Q3DWidgetFactory.h"
#endif

// FIXME Move
#include "PxQuadMAV.h"
#include "SlugsMAV.h"

#include "LogCompressor.h"

84
85
86
87
// Set up some constants
const QString MainWindow::defaultDarkStyle = ":files/styles/style-dark.css";
const QString MainWindow::defaultLightStyle = ":files/styles/style-light.css";

88
89
90
MainWindow* MainWindow::instance(QSplashScreen* screen)
{
    static MainWindow* _instance = 0;
91
    if (_instance == 0)
92
93
    {
        _instance = new MainWindow();
94
95
96
97
98
99
        if (screen)
        {
            connect(_instance, SIGNAL(initStatusChanged(QString,int,QColor)),
                    screen, SLOT(showMessage(QString,int,QColor)));
        }
        _instance->init();
100
101
102
103
104
105
106
107
108
109
110
111
112
    }
    return _instance;
}

/**
* 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()
**/
MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
113
    currentView(VIEW_FLIGHT),
114
    currentStyle(QGC_MAINWINDOW_STYLE_DARK),
115
116
117
    aboutToCloseFlag(false),
    changingViewsFlag(false),
    centerStackActionGroup(new QActionGroup(this)),
118
119
    darkStyleFileName(defaultDarkStyle),
    lightStyleFileName(defaultLightStyle),
120
    autoReconnect(false),
121
122
123
124
125
    #ifdef APM_TOOLBAR_DEFAULT
    apmToolBarEnabled(true),
    #else
    apmToolBarEnabled(false),
    #endif
126
    lowPowerMode(false),
127
128
    isAdvancedMode(false),
    dockWidgetTitleBarEnabled(true)
129
{
130
    this->setAttribute(Qt::WA_DeleteOnClose);
131
    hide();
132
133
134
135
136
}

void MainWindow::init()
{
    emit initStatusChanged(tr("Loading settings"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
137
    loadSettings();
Lorenz Meier's avatar
Lorenz Meier committed
138

139
    emit initStatusChanged(tr("Loading style"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
140
    qApp->setStyle("plastique");
141
142
143
144
145
146
147
148
    if (currentStyle == QGC_MAINWINDOW_STYLE_LIGHT)
    {
        loadStyle(currentStyle, lightStyleFileName);
    }
    else
    {
        loadStyle(currentStyle, darkStyleFileName);
    }
Lorenz Meier's avatar
Lorenz Meier committed
149

150
151
152
153
154
    if (settings.contains("ADVANCED_MODE"))
    {
        isAdvancedMode = settings.value("ADVANCED_MODE").toBool();
    }

155
156
157
158
159
160
161
162
163
164
    if (!settings.contains("CURRENT_VIEW"))
    {
        // Set this view as default view
        settings.setValue("CURRENT_VIEW", currentView);
    }
    else
    {
        // LOAD THE LAST VIEW
        VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
        if (currentViewCandidate != VIEW_ENGINEER &&
165
166
                currentViewCandidate != VIEW_MISSION &&
                currentViewCandidate != VIEW_FLIGHT &&
167
168
169
170
171
172
173
                currentViewCandidate != VIEW_FULL)
        {
            currentView = currentViewCandidate;
        }
    }

    settings.sync();
174
    emit initStatusChanged(tr("Setting up user interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
175
176
177
178
179

    // Setup user interface
    ui.setupUi(this);
    hide();

Lorenz Meier's avatar
Lorenz Meier committed
180
    // We only need this menu if we have more than one system
181
    //    ui.menuConnected_Systems->setEnabled(false);
Lorenz Meier's avatar
Lorenz Meier committed
182

183
184
185
186
187
188
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

    configureWindowName();

    // Setup corners
189
    setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
190
191

    // Setup UI state machines
192
    centerStackActionGroup->setExclusive(true);
193
194
195
196

    centerStack = new QStackedWidget(this);
    setCentralWidget(centerStack);

197

198
    // Load Toolbar
199
200
201
202
    if (!apmToolBarEnabled) {
        toolBar = new QGCToolBar(this);
        this->addToolBar(toolBar);

203
204
        ui.actionHardwareConfig->setText(tr("Config"));

205
206
207
208
209
210
211
212
213
214
215
216
217
218
        // Add actions for average users (displayed next to each other)
        QList<QAction*> actions;
        actions << ui.actionFlightView;
        actions << ui.actionMissionView;
        actions << ui.actionHardwareConfig;
        toolBar->setPerspectiveChangeActions(actions);

        // Add actions for advanced users (displayed in dropdown under "advanced")
        QList<QAction*> advancedActions;
        advancedActions << ui.actionSimulation_View;
        advancedActions << ui.actionEngineersView;

        toolBar->setPerspectiveChangeAdvancedActions(advancedActions);
    }
219

220
    customStatusBar = new QGCStatusBar(this);
221
222
    setStatusBar(customStatusBar);
    statusBar()->setSizeGripEnabled(true);
223

224
    emit initStatusChanged(tr("Building common widgets."), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
225
226
227
228

    buildCommonWidgets();
    connectCommonWidgets();

229
    emit initStatusChanged(tr("Building common actions"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
230
231
232
233
234

    // Create actions
    connectCommonActions();

    // Populate link menu
235
    emit initStatusChanged(tr("Populating link menu"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
236
237
238
239
240
241
242
243
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    foreach(LinkInterface* link, links)
    {
        this->addLink(link);
    }

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

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
    if (apmToolBarEnabled) {
        // Add the APM 'toolbar'

        APMToolBar *apmToolBar = new APMToolBar(this);
        apmToolBar->setFlightViewAction(ui.actionFlightView);
        apmToolBar->setFlightPlanViewAction(ui.actionMissionView);
        apmToolBar->setHardwareViewAction(ui.actionHardwareConfig);
        apmToolBar->setSoftwareViewAction(ui.actionSoftwareConfig);
        apmToolBar->setSimulationViewAction(ui.actionSimulation_View);
        apmToolBar->setTerminalViewAction(ui.actionSimulation_View);

        QDockWidget *widget = new QDockWidget(tr("APM Tool Bar"),this);
        widget->setWidget(apmToolBar);
        widget->setMinimumHeight(72);
        widget->setMaximumHeight(72);
        widget->setMinimumWidth(1024);
        widget->setFeatures(QDockWidget::NoDockWidgetFeatures);
        widget->setTitleBarWidget(new QWidget(this)); // Disables the title bar
    //    /*widget*/->setStyleSheet("QDockWidget { border: 0px solid #FFFFFF; border-radius: 0px; border-bottom: 0px;}");
        this->addDockWidget(Qt::TopDockWidgetArea, widget);
    }
265

266
    // Connect user interface devices
267
    emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
268
269
270
271
    joystickWidget = 0;
    joystick = new JoystickInput();

#ifdef MOUSE_ENABLED_WIN
272
    emit initStatusChanged(tr("Initializing 3D mouse interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
273
274
275
276
277

    mouseInput = new Mouse3DInput(this);
    mouse = new Mouse6dofInput(mouseInput);
#endif //MOUSE_ENABLED_WIN

278
#if MOUSE_ENABLED_LINUX
279
    emit initStatusChanged(tr("Initializing 3D mouse interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
280
281

    mouse = new Mouse6dofInput(this);
282
    connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
283
284
#endif //MOUSE_ENABLED_LINUX

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    // Connect link
    if (autoReconnect)
    {
        SerialLink* link = new SerialLink();
        // Add to registry
        LinkManager::instance()->add(link);
        LinkManager::instance()->addProtocol(link, mavlink);
        link->connect();
    }

    // Set low power mode
    enableLowPowerMode(lowPowerMode);

    // Initialize window state
    windowStateVal = windowState();

301
    emit initStatusChanged(tr("Restoring last view state"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
302
303
304
305

    // Restore the window setup
    loadViewState();

306
    emit initStatusChanged(tr("Restoring last window size"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
307
308
309
310
311
312
313
314
315
316
317
318
319
    // Restore the window position and size
    if (settings.contains(getWindowGeometryKey()))
    {
        // Restore the window geometry
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
        show();
    }
    else
    {
        // Adjust the size
        const int screenWidth = QApplication::desktop()->width();
        const int screenHeight = QApplication::desktop()->height();

Lorenz Meier's avatar
Lorenz Meier committed
320
        if (screenWidth < 1500)
321
        {
322
323
            resize(screenWidth, screenHeight - 80);
            show();
324
325
326
327
328
329
330
331
332
333
334
        }
        else
        {
            resize(screenWidth*0.67f, qMin(screenHeight, (int)(screenWidth*0.67f*0.67f)));
            show();
        }

    }

    connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName()));
    windowNameUpdateTimer.start(15000);
335
    emit initStatusChanged(tr("Done"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
336
337
338
339
340
341
342
343
344
345
    show();
}

MainWindow::~MainWindow()
{
    if (mavlink)
    {
        delete mavlink;
        mavlink = NULL;
    }
346
347
348
349
350
    //    if (simulationLink)
    //    {
    //        simulationLink->deleteLater();
    //        simulationLink = NULL;
    //    }
351
352
    if (joystick)
    {
353
354
        joystick->shutdown();
        joystick->wait(5000);
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
        delete joystick;
        joystick = NULL;
    }

    // Get and delete all dockwidgets and contained
    // widgets
    QObjectList childList(this->children());

    QObjectList::iterator i;
    QDockWidget* dockWidget;
    for (i = childList.begin(); i != childList.end(); ++i)
    {
        dockWidget = dynamic_cast<QDockWidget*>(*i);
        if (dockWidget)
        {
            // Remove dock widget from main window
            // removeDockWidget(dockWidget);
            // delete dockWidget->widget();
            delete dockWidget;
            dockWidget = NULL;
        }
        else if (dynamic_cast<QWidget*>(*i))
        {
            delete dynamic_cast<QWidget*>(*i);
            *i = NULL;
        }
    }
    // Delete all UAS objects
383
384
385
386
387
388
389
390
391
392


    if (debugConsole)
    {
        delete debugConsole;
    }
    for (int i=0;i<commsWidgetList.size();i++)
    {
        commsWidgetList[i]->deleteLater();
    }
393
394
395
396
397
398
399
400
401
}

void MainWindow::resizeEvent(QResizeEvent * event)
{
    QMainWindow::resizeEvent(event);
}

QString MainWindow::getWindowStateKey()
{
402
403
404
405
406
    if (UASManager::instance()->getActiveUAS())
    {
        return QString::number(currentView)+"_windowstate_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName();
    }
    else
407
        return QString::number(currentView)+"_windowstate";
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
}

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

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

    if (widgets.size() > 0)
    {
        ui.menuTools->addSeparator();
    }

    for(int i = 0; i < widgets.size(); ++i)
    {
        // Check if this widget already has a parent, do not create it in this case
        QGCToolWidget* tool = widgets.at(i);
        QDockWidget* dock = dynamic_cast<QDockWidget*>(tool->parentWidget());
        if (!dock)
        {
433
434
435
436
            QSettings settings;
            settings.beginGroup("QGC_MAINWINDOW");

            /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this);
437
438
439
440
441
442
443
444
            dock->setObjectName(tool->objectName()+"_DOCK");
            dock->setWidget(tool);
            connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
            QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this);
            showAction->setCheckable(true);
            connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
            connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
            widgets.at(i)->setMainMenuAction(showAction);
445
            ui.menuTools->addAction(showAction);*/
446
447
448
449

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

450
451
452
453
454
            //addDockWidget(location, dock);
            //dock->hide();
            int view = settings.value(QString("TOOL_PARENT_") + tool->objectName(),-1).toInt();
            //settings.setValue(QString("TOOL_PARENT_") + "UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size()),currentView);
            settings.endGroup();
Lorenz Meier's avatar
Lorenz Meier committed
455
456
457

            QDockWidget* dock;

458
459
460
            switch (view)
            {
            case VIEW_ENGINEER:
461
                dock = createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
462
463
                break;
            case VIEW_FLIGHT:
Lorenz Meier's avatar
Lorenz Meier committed
464
                dock = createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
465
466
                break;
            case VIEW_SIMULATION:
Lorenz Meier's avatar
Lorenz Meier committed
467
                dock = createDockWidget(simView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
468
469
                break;
            case VIEW_MISSION:
Lorenz Meier's avatar
Lorenz Meier committed
470
                dock = createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
471
                break;
472
473
474
            case VIEW_MAVLINK:
                dock = createDockWidget(mavlinkView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
                break;
475
            default:
Lorenz Meier's avatar
Lorenz Meier committed
476
                dock = createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
477
478
479
                break;
            }

Lorenz Meier's avatar
Lorenz Meier committed
480
481
482
            // XXX temporary "fix"
            dock->hide();

483
            //createDockWidget(0,tool,tool->getTitle(),tool->objectName(),view,location);
484
485
486
487
488
489
490
491
492
493
494
495
        }
    }
}

void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
    // Add generic MAVLink decoder
    mavlinkDecoder = new MAVLinkDecoder(mavlink, this);

496
497
498
499
    // Log player
    logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar);
    customStatusBar->setLogPlayer(logPlayer);

500
501
502
503
504
505
506
507
508
509
510
511
512
    // Center widgets
    if (!plannerView)
    {
        plannerView = new SubMainWindow(this);
        plannerView->setCentralWidget(new QGCMapTool(this));
        //mapWidget = new QGCMapTool(this);
        addCentralWidget(plannerView, "Maps");
    }

    //pilotView
    if (!pilotView)
    {
        pilotView = new SubMainWindow(this);
513
        pilotView->setObjectName("VIEW_FLIGHT");
514
        pilotView->setCentralWidget(new QGCMapTool(this));
515
516
        addCentralWidget(pilotView, "Pilot");
    }
517
518
519
520
521
522
523
524
    if (apmToolBarEnabled) {
        if (!configView)
        {
            configView = new SubMainWindow(this);
            configView->setObjectName("VIEW_HARDWARE_CONFIG");
            configView->setCentralWidget(new ApmHardwareConfig(this));
            addCentralWidget(configView,"Hardware");
            centralWidgetToDockWidgetsMap[VIEW_HARDWARE_CONFIG] = QMap<QString,QWidget*>();
525

526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
        }
        if (!softwareConfigView)
        {
            softwareConfigView = new SubMainWindow(this);
            softwareConfigView->setObjectName("VIEW_SOFTWARE_CONFIG");
            softwareConfigView->setCentralWidget(new ApmSoftwareConfig(this));
            addCentralWidget(softwareConfigView,"Software");
            centralWidgetToDockWidgetsMap[VIEW_SOFTWARE_CONFIG] = QMap<QString,QWidget*>();
        }
    } else {
        if (!configView)
        {
            configView = new SubMainWindow(this);
            configView->setObjectName("VIEW_HARDWARE_CONFIG");
            configView->setCentralWidget(new QGCConfigView(this));
            addCentralWidget(configView,"Config");
            centralWidgetToDockWidgetsMap[VIEW_HARDWARE_CONFIG] = QMap<QString,QWidget*>();
        }
544
    }
545
546
547
548
    if (!engineeringView)
    {
        engineeringView = new SubMainWindow(this);
        engineeringView->setObjectName("VIEW_ENGINEER");
549
550
        engineeringView->setCentralWidget(new QGCDataPlot2D(this));
        addCentralWidget(engineeringView,tr("Logfile Plot"));
551
    }
552
    if (!mavlinkView)
553
    {
554
555
556
557
        mavlinkView = new SubMainWindow(this);
        mavlinkView->setObjectName("VIEW_MAVLINK");
        mavlinkView->setCentralWidget(new XMLCommProtocolWidget(this));
        addCentralWidget(mavlinkView,tr("Mavlink Generator"));
558
559
560
561
562
563
564
565
566
    }
    if (!simView)
    {
        simView = new SubMainWindow(this);
        simView->setObjectName("VIEW_SIMULATOR");
        simView->setCentralWidget(new QGCMapTool(this));
        addCentralWidget(simView,tr("Simulation View"));
    }

567
    // Dock widgets
568
569
570
571
    QAction* tempAction = ui.menuTools->addAction(tr("Control"));
    tempAction->setCheckable(true);
    connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));

572
    createDockWidget(simView,new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",VIEW_SIMULATION,Qt::LeftDockWidgetArea);
573

574
    createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea);
575
    createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea);
576

577
    {
578
579
580
581
582
        //createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea);
        QAction* tempAction = ui.menuTools->addAction(tr("Mission Plan"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        menuToDockNameMap[tempAction] = "WAYPOINT_LIST_DOCKWIDGET";
583
    }
584

585
586
    createDockWidget(simView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea);
    createDockWidget(engineeringView,new QGCMAVLinkInspector(mavlink,this),tr("MAVLink Inspector"),"MAVLINK_INSPECTOR_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea);
587

588
589
    createDockWidget(engineeringView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea);
    createDockWidget(simView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea);
590
591


592
    {
593
        QAction* tempAction = ui.menuTools->addAction(tr("Status Details"));
594
        menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET";
595
596
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
597
598
    }
    {
599
600
601
602
        if (!debugConsole)
        {
            debugConsole = new DebugConsole();
            debugConsole->setWindowTitle("Communications Console");
603
            debugConsole->hide();
604
605
606
607
608
609
            QAction* tempAction = ui.menuTools->addAction(tr("Communication Console"));
            //menuToDockNameMap[tempAction] = "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET";
            tempAction->setCheckable(true);
            connect(tempAction,SIGNAL(triggered(bool)),debugConsole,SLOT(setShown(bool)));

        }
610
611
    }
    createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea);
612

613
    {
614
615
616
617
        QAction* tempAction = ui.menuTools->addAction(tr("Flight Display"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_1_DOCKWIDGET";
618
    }
619

620
    {
621
622
623
624
        QAction* tempAction = ui.menuTools->addAction(tr("Actuator Status"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_2_DOCKWIDGET";
625
    }
626
627

    {
628
629
630
        QAction* tempAction = ui.menuTools->addAction(tr("Radio Control"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
631
    }
632

633
    createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5);
634

635
636
637
    createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5);

    createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5);
638
    createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8);
639

640
    QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this);
641
    infoview->addSource(mavlinkDecoder);
642
643
644
    createDockWidget(pilotView,infoview,tr("Info View"),"UAS_INFO_INFOVIEW_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);


645
646
    //createDockWidget(pilotView,new HUD(320,240,this),tr("Head Up Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8);

647
648
649
650
651
//    createDockWidget(pilotView,new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);
//    createDockWidget(pilotView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);
//    pilotView->setTabPosition(Qt::LeftDockWidgetArea,QTabWidget::North);
//    pilotView->tabifyDockWidget((QDockWidget*)centralWidgetToDockWidgetsMap[VIEW_FLIGHT]["HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET"],(QDockWidget*)centralWidgetToDockWidgetsMap[VIEW_FLIGHT]["UAS_INFO_QUICKVIEW_DOCKWIDGET"]);

652
653
654
    //UASRawStatusView *view = new UASRawStatusView();
    //view->setDecoder(mavlinkDecoder);
    //view->show();
655
    //hddisplay->addSource(mavlinkDecoder);
656
657
658
659
    //createDockWidget(pilotView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);
    //pilotView->setTabPosition(Qt::LeftDockWidgetArea,QTabWidget::North);
    //pilotView->tabifyDockWidget((QDockWidget*)centralWidgetToDockWidgetsMap[VIEW_FLIGHT]["HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET"],(QDockWidget*)centralWidgetToDockWidgetsMap[VIEW_FLIGHT]["UAS_INFO_QUICKVIEW_DOCKWIDGET"]);

660

661
    //createDockWidget(pilotView,new UASActionsWidget(this),tr("Actions"),"UNMANNED_SYSTEM_ACTION_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
662
663
664
665
666

    // Custom widgets, added last to all menus and layouts
    buildCustomWidget();


667
668

    /*if (!protocolWidget)
669
670
671
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addCentralWidget(protocolWidget, "Mavlink Generator");
672
673
    }*/

674

675
676
677
678
679
    //    if (!firmwareUpdateWidget)
    //    {
    //        firmwareUpdateWidget    = new QGCFirmwareUpdate(this);
    //        addCentralWidget(firmwareUpdateWidget, "Firmware Update");
    //    }
680

681
    /*if (!hudWidget)
682
683
684
    {
        hudWidget         = new HUD(320, 240, this);
        addCentralWidget(hudWidget, tr("Head Up Display"));
685
    }*/
686

687
    /*if (!configWidget)
688
689
690
    {
        configWidget = new QGCVehicleConfig(this);
        addCentralWidget(configWidget, tr("Vehicle Configuration"));
691
692
    }*/

693

694
    /*if (!dataplotWidget)
695
696
697
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addCentralWidget(dataplotWidget, tr("Logfile Plot"));
698
    }*/
699
700
701
702
703
704
705
706
707

#ifdef QGC_OSG_ENABLED
    if (!_3DWidget)
    {
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK", this);
        addCentralWidget(_3DWidget, tr("Local 3D"));
    }
#endif

708
#if (defined _MSC_VER) /*| (defined Q_OS_MAC) mac os doesn't support gearth right now */
709
710
711
712
713
714
715
716
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addCentralWidget(gEarthWidget, tr("Google Earth"));
    }
#endif
}

717
void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
718
{
719
720
    QList<QAction*> actionlist = ui.menuTools->actions();
    bool found = false;
721
    QAction *targetAction;
722
723
724
725
726
    for (int i=0;i<actionlist.size();i++)
    {
        if (actionlist[i]->text() == title)
        {
            found = true;
727
            targetAction = actionlist[i];
728
729
730
731
732
733
        }
    }
    if (!found)
    {
        QAction* tempAction = ui.menuTools->addAction(title);
        tempAction->setCheckable(true);
734
        menuToDockNameMap[tempAction] = widget->objectName();
735
736
737
738
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
739
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
740
741
742
743
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
        tempAction->setChecked(widget->isVisible());
    }
744
745
746
747
    else
    {
        if (!menuToDockNameMap.contains(targetAction))
        {
748
749
            menuToDockNameMap[targetAction] = widget->objectName();
            //menuToDockNameMap[targetAction] = title;
750
751
752
753
754
        }
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
755
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
756
757
        connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool)));
    }
758
    parent->addDockWidget(area,widget);
759
760
}

Lorenz Meier's avatar
Lorenz Meier committed
761
QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight)
762
{
763
    child->setObjectName(objectname);
764
    QDockWidget *widget = new QDockWidget(title,this);
765
766
    dockWidgets.append(widget);
    setDockWidgetTitleBar(widget);
767
    widget->setObjectName(child->objectName());
768
769
770
771
772
773
774
    widget->setWidget(child);
    if (minheight != 0 || minwidth != 0)
    {
        widget->setMinimumHeight(minheight);
        widget->setMinimumWidth(minwidth);
    }
    addTool(qobject_cast<SubMainWindow*>(parent),view,widget,title,area);
Lorenz Meier's avatar
Lorenz Meier committed
775
776

    return widget;
777
}
778
779
780
781
782
783
void MainWindow::loadDockWidget(QString name)
{
    if (centralWidgetToDockWidgetsMap[currentView].contains(name))
    {
        return;
    }
784
785
786
787
788
789
    if (name.startsWith("HIL_CONFIG"))
    {
        //It's a HIL widget.
        showHILConfigurationWidget(UASManager::instance()->getActiveUAS());
    }
    else if (name == "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET")
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
    {
        createDockWidget(centerStack->currentWidget(),new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea);
    }
    else if (name == "UNMANNED_SYSTEM_LIST_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "WAYPOINT_LIST_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea);
    }
    else if (name == "MAVLINK_INSPECTOR_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new QGCMAVLinkInspector(mavlink,this),tr("MAVLink Inspector"),"MAVLINK_INSPECTOR_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "PARAMETER_INTERFACE_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "UAS_STATUS_DETAILS_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new UASInfoWidget(this),tr("Status Details"),"UAS_STATUS_DETAILS_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET")
    {
815
816
817
        //This is now a permanently detached window.
        //centralWidgetToDockWidgetsMap[currentView][name] = console;
        //createDockWidget(centerStack->currentWidget(),new DebugConsole(this),tr("Communication Console"),"COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea);
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
    }
    else if (name == "HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea);
    }
    else if (name == "HEAD_DOWN_DISPLAY_1_DOCKWIDGET")
    {
        //FIXME: memory of acceptList will never be freed again
        QStringList* acceptList = new QStringList();
        acceptList->append("-3.3,ATTITUDE.roll,rad,+3.3,s");
        acceptList->append("-3.3,ATTITUDE.pitch,deg,+3.3,s");
        acceptList->append("-3.3,ATTITUDE.yaw,deg,+3.3,s");
        HDDisplay *hddisplay = new HDDisplay(acceptList,"Flight Display",this);
        hddisplay->addSource(mavlinkDecoder);
        createDockWidget(centerStack->currentWidget(),hddisplay,tr("Flight Display"),"HEAD_DOWN_DISPLAY_1_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "HEAD_DOWN_DISPLAY_2_DOCKWIDGET")
    {
        //FIXME: memory of acceptList2 will never be freed again
        QStringList* acceptList2 = new QStringList();
        acceptList2->append("0,RAW_PRESSURE.pres_abs,hPa,65500");
        HDDisplay *hddisplay = new HDDisplay(acceptList2,"Actuator Status",this);
        hddisplay->addSource(mavlinkDecoder);
        createDockWidget(centerStack->currentWidget(),hddisplay,tr("Actuator Status"),"HEAD_DOWN_DISPLAY_2_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
    else if (name == "Radio Control")
    {
        qDebug() << "Error loading window:" << name << "Unknown window type";
        //createDockWidget(centerStack->currentWidget(),hddisplay,tr("Actuator Status"),"HEADS_DOWN_DISPLAY_2_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
    }
848
    else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET")
849
    {
850
851
        // createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Head Up Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
        createDockWidget(centerStack->currentWidget(),new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
852
    }
853
854
855
856
    else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea);
    }
857
858
    else
    {
859
860
861
862
863
864
865
866
867
        if (customWidgetNameToFilenameMap.contains(name))
        {
            loadCustomWidget(customWidgetNameToFilenameMap[name],currentView);
            //customWidgetNameToFilenameMap.remove(name);
        }
        else
        {
            qDebug() << "Error loading window:" << name;
        }
868
869
    }
}
870

871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
void MainWindow::setDockWidgetTitleBar(QDockWidget* widget)
{
    QWidget* oldTitleBar = widget->titleBarWidget();

    // In advanced mode, we use the default titlebar provided by Qt.
    if (isAdvancedMode)
    {
        widget->setTitleBarWidget(0);
    }
    // Otherwise, if just a textlabel should be shown, make that the titlebar.
    else if (dockWidgetTitleBarEnabled)
    {
        QLabel* label = new QLabel(this);
        label->setText(widget->windowTitle());
        label->installEventFilter(new DockWidgetTitleBarEventFilter());
        widget->setTitleBarWidget(label);
    }
    // And if nothing should be shown, use an empty widget.
    else
    {
        QWidget* newTitleBar = new QWidget(this);
        widget->setTitleBarWidget(newTitleBar);
    }

    // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(),
    // it doesn't delete the old titlebar object.
    if (oldTitleBar)
    {
        delete oldTitleBar;
    }
}

903
904
void MainWindow::showTool(bool show)
{
905
906
    //Called when a menu item is clicked on, regardless of view.

907
    QAction* act = qobject_cast<QAction *>(sender());
908
909
910
911
912
913
914
    if (menuToDockNameMap.contains(act))
    {
        QString name = menuToDockNameMap[act];
        if (centralWidgetToDockWidgetsMap.contains(currentView))
        {
            if (centralWidgetToDockWidgetsMap[currentView].contains(name))
            {
915
916
917
918
919
920
921
922
                if (show)
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->show();
                }
                else
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->hide();
                }
923
            }
924
            else if (show)
925
            {
926
                loadDockWidget(name);
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
            }
        }
    }
    //QWidget* widget = qVariantValue<QWidget *>(act->data());
    //widget->setVisible(show);
}
/*void addToolByName(QString name,SubMainWindow parent,const QString& title, Qt::DockWidgetArea area)
{
    if (name == "Control")
    {
        QDockWidget *widget = new QDockWidget(tr("Control"),this);
        dockToTitleBarMap[widget] = widget->titleBarWidget();
        widget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
        widget->setWidget(new UASControlWidget(this));
        addTool(parent,VIEW_SIMULATION,widget,tr("Control"),area);
    }
}*/
944
945
void MainWindow::addCentralWidget(QWidget* widget, const QString& title)
{
Bryant's avatar
Bryant committed
946
    Q_UNUSED(title);
947

948
949
950
951
952
    // Check if this widget already has been added
    if (centerStack->indexOf(widget) == -1)
    {
        centerStack->addWidget(widget);

953
        //        QAction* tempAction = ui.menuMain->addAction(title);
954

955
956
957
958
959
960
        //        tempAction->setCheckable(true);
        //        QVariant var;
        //        var.setValue((QWidget*)widget);
        //        tempAction->setData(var);
        //        centerStackActionGroup->addAction(tempAction);
        //        connect(tempAction,SIGNAL(triggered()),this, SLOT(showCentralWidget()));
961
        //connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
962
        //        tempAction->setChecked(widget->isVisible());
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
    }
}


void MainWindow::showCentralWidget()
{
    QAction* act = qobject_cast<QAction *>(sender());
    QWidget* widget = qVariantValue<QWidget *>(act->data());
    centerStack->setCurrentWidget(widget);
}

void MainWindow::showHILConfigurationWidget(UASInterface* uas)
{
    // Add simulation configuration widget
    UAS* mav = dynamic_cast<UAS*>(uas);

979
    if (mav && !hilDocks.contains(mav->getUASID()))
980
    {
Michael Carpenter's avatar
Michael Carpenter committed
981
982
983
        //QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size()));
        //createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea);

984
        QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this);
985
        QString hilDockName = tr("HIL Config %1").arg(uas->getUASName());
986
        QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea);
987
        hilDocks.insert(mav->getUASID(), hilDock);
988

989
990
991
992
        //        if (currentView != VIEW_SIMULATION)
        //            hilDock->hide();
        //        else
        //            hilDock->show();
993
994
995
996
997
998
999
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (isVisible()) storeViewState();
    aboutToCloseFlag = true;
1000
    storeSettings();
For faster browsing, not all history is shown. View entire blame