MainWindow.cc 81.1 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
#include "SerialSettingsDialog.h"
#include "terminalconsole.h"
75
76
77
78
79
80
81
82
83
84
85

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

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

#include "LogCompressor.h"

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

90
MainWindow* MainWindow::instance_mode(QSplashScreen* screen, enum MainWindow::CUSTOM_MODE mode)
91
92
{
    static MainWindow* _instance = 0;
93
    if (_instance == 0)
94
95
    {
        _instance = new MainWindow();
96
        _instance->setCustomMode(mode);
97
98
99
100
101
102
        if (screen)
        {
            connect(_instance, SIGNAL(initStatusChanged(QString,int,QColor)),
                    screen, SLOT(showMessage(QString,int,QColor)));
        }
        _instance->init();
103
104
105
106
    }
    return _instance;
}

107
108
MainWindow* MainWindow::instance(QSplashScreen* screen)
{
109
    return instance_mode(screen, CUSTOM_MODE_UNCHANGED);
110
111
}

112
113
114
115
116
117
118
119
120
/**
* 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),
121
    currentView(VIEW_FLIGHT),
122
    currentStyle(QGC_MAINWINDOW_STYLE_DARK),
123
124
125
    aboutToCloseFlag(false),
    changingViewsFlag(false),
    centerStackActionGroup(new QActionGroup(this)),
126
127
    darkStyleFileName(defaultDarkStyle),
    lightStyleFileName(defaultLightStyle),
128
    autoReconnect(false),
129
    simulationLink(NULL),
130
    lowPowerMode(false),
131
    isAdvancedMode(false),
Lorenz Meier's avatar
Lorenz Meier committed
132
    mavlink(new MAVLinkProtocol()),
133
    dockWidgetTitleBarEnabled(true),
134
    customMode(CUSTOM_MODE_NONE)
135
{
136
    this->setAttribute(Qt::WA_DeleteOnClose);
Lorenz Meier's avatar
Lorenz Meier committed
137
138
    //TODO:  move protocol outside UI
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
139
    loadSettings();
140
141
142
143
}

void MainWindow::init()
{
Lorenz Meier's avatar
Lorenz Meier committed
144

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

156
157
158
159
160
    if (settings.contains("ADVANCED_MODE"))
    {
        isAdvancedMode = settings.value("ADVANCED_MODE").toBool();
    }

161
162
163
164
165
166
167
168
169
170
    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 &&
171
172
                currentViewCandidate != VIEW_MISSION &&
                currentViewCandidate != VIEW_FLIGHT &&
173
174
175
176
177
178
179
                currentViewCandidate != VIEW_FULL)
        {
            currentView = currentViewCandidate;
        }
    }

    settings.sync();
180
    emit initStatusChanged(tr("Setting up user interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
181
182
183
184
185

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

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

189
190
191
192
193
194
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

    configureWindowName();

    // Setup corners
195
    setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
196
197

    // Setup UI state machines
198
    centerStackActionGroup->setExclusive(true);
199
200
201
202

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

203

204
    // Load Toolbar
205
    if (!(getCustomMode() == CUSTOM_MODE_APM)) {
206
207
208
        toolBar = new QGCToolBar(this);
        this->addToolBar(toolBar);

209
210
        ui.actionHardwareConfig->setText(tr("Config"));

211
212
213
214
215
216
217
218
219
220
221
222
223
224
        // 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);
    }
225

226
    customStatusBar = new QGCStatusBar(this);
227
228
    setStatusBar(customStatusBar);
    statusBar()->setSizeGripEnabled(true);
229

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

    buildCommonWidgets();
    connectCommonWidgets();

235
    emit initStatusChanged(tr("Building common actions"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
236
237
238
239
240

    // Create actions
    connectCommonActions();

    // Populate link menu
241
    emit initStatusChanged(tr("Populating link menu"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
242
243
244
245
246
247
248
249
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    foreach(LinkInterface* link, links)
    {
        this->addLink(link);
    }

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

250
    if (getCustomMode() == CUSTOM_MODE_APM) {
251
252
253
254
255
256
257
258
        // 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);
Lorenz Meier's avatar
Lorenz Meier committed
259
        apmToolBar->setTerminalViewAction(ui.actionTerminalView);
260
261
262
263
264
265
266
267
268
269
270

        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);
    }
271

272
    // Connect user interface devices
273
    emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
274
275
276
277
    joystickWidget = 0;
    joystick = new JoystickInput();

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

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

284
#if MOUSE_ENABLED_LINUX
285
    emit initStatusChanged(tr("Initializing 3D mouse interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
286
287

    mouse = new Mouse6dofInput(this);
288
    connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
289
290
#endif //MOUSE_ENABLED_LINUX

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    // 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();

307
    emit initStatusChanged(tr("Restoring last view state"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
308
309
310
311

    // Restore the window setup
    loadViewState();

312
    emit initStatusChanged(tr("Restoring last window size"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
313
314
315
316
317
318
319
320
321
322
323
324
325
    // 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
326
        if (screenWidth < 1500)
327
        {
328
329
            resize(screenWidth, screenHeight - 80);
            show();
330
331
332
333
334
335
336
337
338
339
340
        }
        else
        {
            resize(screenWidth*0.67f, qMin(screenHeight, (int)(screenWidth*0.67f*0.67f)));
            show();
        }

    }

    connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName()));
    windowNameUpdateTimer.start(15000);
341
    emit initStatusChanged(tr("Done"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
342
343
344
345
346
347
348
349
350
351
    show();
}

MainWindow::~MainWindow()
{
    if (mavlink)
    {
        delete mavlink;
        mavlink = NULL;
    }
352
353
354
355
356
    if (simulationLink)
    {
        delete simulationLink;
        simulationLink = NULL;
    }
357
358
    if (joystick)
    {
359
360
        joystick->shutdown();
        joystick->wait(5000);
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        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
389
390
391
392
393
394
395
396
397
398


    if (debugConsole)
    {
        delete debugConsole;
    }
    for (int i=0;i<commsWidgetList.size();i++)
    {
        commsWidgetList[i]->deleteLater();
    }
399
400
401
402
403
404
405
406
407
}

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

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

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)
        {
439
440
441
442
            QSettings settings;
            settings.beginGroup("QGC_MAINWINDOW");

            /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this);
443
444
445
446
447
448
449
450
            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);
451
            ui.menuTools->addAction(showAction);*/
452
453
454
455

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

456
457
458
459
460
            //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
461
462
463

            QDockWidget* dock;

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

Lorenz Meier's avatar
Lorenz Meier committed
486
487
488
            // XXX temporary "fix"
            dock->hide();

489
            //createDockWidget(0,tool,tool->getTitle(),tool->objectName(),view,location);
490
491
492
493
494
495
496
497
498
        }
    }
}

void MainWindow::buildCommonWidgets()
{
    // Add generic MAVLink decoder
    mavlinkDecoder = new MAVLinkDecoder(mavlink, this);

499
500
501
502
    // Log player
    logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar);
    customStatusBar->setLogPlayer(logPlayer);

503
504
505
506
    // Center widgets
    if (!plannerView)
    {
        plannerView = new SubMainWindow(this);
507
        plannerView->setObjectName("VIEW_MISSION");
508
        plannerView->setCentralWidget(new QGCMapTool(this));
509
        addToCentralStackedWidget(plannerView, VIEW_MISSION, "Maps");
510
511
    }

512
    //pilotView (aka Flight or Mission View)
513
514
515
    if (!pilotView)
    {
        pilotView = new SubMainWindow(this);
516
        pilotView->setObjectName("VIEW_FLIGHT");
517
        pilotView->setCentralWidget(new QGCMapTool(this));
518
        addToCentralStackedWidget(pilotView, VIEW_FLIGHT, "Pilot");
519
    }
520

521
    if (getCustomMode() == CUSTOM_MODE_APM) {
522
523
524
525
526
        if (!configView)
        {
            configView = new SubMainWindow(this);
            configView->setObjectName("VIEW_HARDWARE_CONFIG");
            configView->setCentralWidget(new ApmHardwareConfig(this));
Lorenz Meier's avatar
Lorenz Meier committed
527
            addToCentralStackedWidget(configView, VIEW_HARDWARE_CONFIG, "Hardware");
528

529
530
531
532
533
534
        }
        if (!softwareConfigView)
        {
            softwareConfigView = new SubMainWindow(this);
            softwareConfigView->setObjectName("VIEW_SOFTWARE_CONFIG");
            softwareConfigView->setCentralWidget(new ApmSoftwareConfig(this));
Lorenz Meier's avatar
Lorenz Meier committed
535
536
537
538
539
540
541
542
543
            addToCentralStackedWidget(softwareConfigView, VIEW_SOFTWARE_CONFIG, "Software");
        }
        if (!terminalView)
        {
            terminalView = new SubMainWindow(this);
            terminalView->setObjectName("VIEW_TERMINAL");
            TerminalConsole *terminalConsole = new TerminalConsole(this);
            terminalView->setCentralWidget(terminalConsole);
            addToCentralStackedWidget(terminalView, VIEW_TERMINAL, tr("Terminal View"));
544
545
546
547
548
549
550
        }
    } else {
        if (!configView)
        {
            configView = new SubMainWindow(this);
            configView->setObjectName("VIEW_HARDWARE_CONFIG");
            configView->setCentralWidget(new QGCConfigView(this));
Lorenz Meier's avatar
Lorenz Meier committed
551
            addToCentralStackedWidget(configView, VIEW_HARDWARE_CONFIG, "Config");
552
        }
553
    }
554

555
556
557
558
    if (!engineeringView)
    {
        engineeringView = new SubMainWindow(this);
        engineeringView->setObjectName("VIEW_ENGINEER");
559
        engineeringView->setCentralWidget(new QGCDataPlot2D(this));
560
        addToCentralStackedWidget(engineeringView, VIEW_ENGINEER, tr("Logfile Plot"));
561
    }
562

563
    if (!mavlinkView)
564
    {
565
566
567
        mavlinkView = new SubMainWindow(this);
        mavlinkView->setObjectName("VIEW_MAVLINK");
        mavlinkView->setCentralWidget(new XMLCommProtocolWidget(this));
568
        addToCentralStackedWidget(mavlinkView, VIEW_MAVLINK, tr("Mavlink Generator"));
569
    }
570

571
572
573
574
575
    if (!simView)
    {
        simView = new SubMainWindow(this);
        simView->setObjectName("VIEW_SIMULATOR");
        simView->setCentralWidget(new QGCMapTool(this));
576
        addToCentralStackedWidget(simView, VIEW_SIMULATION, tr("Simulation View"));
577
578
    }

579
    // Dock widgets
580
581
582
583
    QAction* tempAction = ui.menuTools->addAction(tr("Control"));
    tempAction->setCheckable(true);
    connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));

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

586
    createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea);
587
    createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea);
588

589
    {
590
591
592
593
594
        //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";
595
    }
596

597
598
    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);
599

600
601
    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);
602
603


604
    {
605
        QAction* tempAction = ui.menuTools->addAction(tr("Status Details"));
606
        menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET";
607
608
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
609
610
    }
    {
611
612
613
614
        if (!debugConsole)
        {
            debugConsole = new DebugConsole();
            debugConsole->setWindowTitle("Communications Console");
615
            debugConsole->hide();
616
617
618
619
620
621
            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)));

        }
622
623
    }
    createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea);
624

625
    {
626
627
628
629
        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";
630
    }
631

632
    {
633
634
635
636
        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";
637
    }
638
639

    {
640
641
642
        QAction* tempAction = ui.menuTools->addAction(tr("Radio Control"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
643
    }
644

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

647
648
649
    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);
650
    createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8);
651

652
    QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this);
653
    infoview->addSource(mavlinkDecoder);
654
655
656
    createDockWidget(pilotView,infoview,tr("Info View"),"UAS_INFO_INFOVIEW_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);


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

659
660
661
662
663
//    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"]);

664
665
666
    //UASRawStatusView *view = new UASRawStatusView();
    //view->setDecoder(mavlinkDecoder);
    //view->show();
667
    //hddisplay->addSource(mavlinkDecoder);
668
669
670
671
    //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"]);

672

673
    //createDockWidget(pilotView,new UASActionsWidget(this),tr("Actions"),"UNMANNED_SYSTEM_ACTION_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
674
675
676
677
678

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


679
680

    /*if (!protocolWidget)
681
682
683
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addCentralWidget(protocolWidget, "Mavlink Generator");
684
685
    }*/

686

687
688
689
690
691
    //    if (!firmwareUpdateWidget)
    //    {
    //        firmwareUpdateWidget    = new QGCFirmwareUpdate(this);
    //        addCentralWidget(firmwareUpdateWidget, "Firmware Update");
    //    }
692

693
    /*if (!hudWidget)
694
695
696
    {
        hudWidget         = new HUD(320, 240, this);
        addCentralWidget(hudWidget, tr("Head Up Display"));
697
    }*/
698

699
    /*if (!configWidget)
700
701
702
    {
        configWidget = new QGCVehicleConfig(this);
        addCentralWidget(configWidget, tr("Vehicle Configuration"));
703
704
    }*/

705

706
    /*if (!dataplotWidget)
707
708
709
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addCentralWidget(dataplotWidget, tr("Logfile Plot"));
710
    }*/
711
712

#ifdef QGC_OSG_ENABLED
713
    if (q3DWidget)
714
    {
715
716
717
718
        q3DWidget = Q3DWidgetFactory::get("PIXHAWK", this);
        q3DWidget->setObjectName("VIEW_3DWIDGET");

        addToCentralStackedWidget(q3DWidget, VIEW_3DWIDGET, tr("Local 3D"));
719
720
721
    }
#endif

722
#if (defined _MSC_VER) /*| (defined Q_OS_MAC) mac os doesn't support gearth right now */
723
724
    if (!gEarthWidget)
    {
725
726
        earthWidget = new QGCGoogleEarthView(this);
        addToCentralStackedWidget(earthWidget,VIEW_GOOGLEEARTH, tr("Google Earth"));
727
728
729
730
    }
#endif
}

731
void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
732
{
733
734
    QList<QAction*> actionlist = ui.menuTools->actions();
    bool found = false;
735
    QAction *targetAction;
736
737
738
739
740
    for (int i=0;i<actionlist.size();i++)
    {
        if (actionlist[i]->text() == title)
        {
            found = true;
741
            targetAction = actionlist[i];
742
743
744
745
746
747
        }
    }
    if (!found)
    {
        QAction* tempAction = ui.menuTools->addAction(title);
        tempAction->setCheckable(true);
748
        menuToDockNameMap[tempAction] = widget->objectName();
749
750
751
752
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
753
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
754
755
756
757
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
        tempAction->setChecked(widget->isVisible());
    }
758
759
760
761
    else
    {
        if (!menuToDockNameMap.contains(targetAction))
        {
762
763
            menuToDockNameMap[targetAction] = widget->objectName();
            //menuToDockNameMap[targetAction] = title;
764
765
766
767
768
        }
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
769
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
770
771
        connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool)));
    }
772
    parent->addDockWidget(area,widget);
773
774
}

Lorenz Meier's avatar
Lorenz Meier committed
775
QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight)
776
{
777
    child->setObjectName(objectname);
778
    QDockWidget *widget = new QDockWidget(title,this);
779
780
    dockWidgets.append(widget);
    setDockWidgetTitleBar(widget);
781
    widget->setObjectName(child->objectName());
782
783
784
785
786
787
788
    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
789
790

    return widget;
791
}
792
793
794
795
796
797
void MainWindow::loadDockWidget(QString name)
{
    if (centralWidgetToDockWidgetsMap[currentView].contains(name))
    {
        return;
    }
798
799
800
801
802
803
    if (name.startsWith("HIL_CONFIG"))
    {
        //It's a HIL widget.
        showHILConfigurationWidget(UASManager::instance()->getActiveUAS());
    }
    else if (name == "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET")
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
    {
        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")
    {
829
830
831
        //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);
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
    }
    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);
    }
862
    else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET")
863
    {
864
865
        // 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);
866
    }
867
868
869
870
    else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea);
    }
871
872
    else
    {
873
874
875
876
877
878
879
880
881
        if (customWidgetNameToFilenameMap.contains(name))
        {
            loadCustomWidget(customWidgetNameToFilenameMap[name],currentView);
            //customWidgetNameToFilenameMap.remove(name);
        }
        else
        {
            qDebug() << "Error loading window:" << name;
        }
882
883
    }
}
884

885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
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;
    }
}

917
918
void MainWindow::showTool(bool show)
{
919
920
    //Called when a menu item is clicked on, regardless of view.

921
    QAction* act = qobject_cast<QAction *>(sender());
922
923
924
925
926
927
928
    if (menuToDockNameMap.contains(act))
    {
        QString name = menuToDockNameMap[act];
        if (centralWidgetToDockWidgetsMap.contains(currentView))
        {
            if (centralWidgetToDockWidgetsMap[currentView].contains(name))
            {
929
930
931
932
933
934
935
936
                if (show)
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->show();
                }
                else
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->hide();
                }
937
            }
938
            else if (show)
939
            {
940
                loadDockWidget(name);
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
            }
        }
    }
    //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);
    }
}*/
958
void MainWindow::addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title)
959
{
Bryant's avatar
Bryant committed
960
    Q_UNUSED(title);
961
    Q_ASSERT(widget->objectName().length() != 0);
962

963
964
965
966
    // Check if this widget already has been added
    if (centerStack->indexOf(widget) == -1)
    {
        centerStack->addWidget(widget);
967
        centralWidgetToDockWidgetsMap[viewSection] = QMap<QString,QWidget*>();
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
    }
}


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);

984
    if (mav && !hilDocks.contains(mav->getUASID()))
985
    {
Michael Carpenter's avatar
Michael Carpenter committed
986
987
988
        //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);

989
        QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this);
990
        QString hilDockName = tr("HIL Config %1").arg(uas->getUASName());
991
        QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea);
992
        hilDocks.insert(mav->getUASID(), hilDock);
993

994
995
996
997
        //        if (currentView != VIEW_SIMULATION)
        //            hilDock->hide();
        //        else
        //            hilDock->show();
998
999
1000
    }
}

For faster browsing, not all history is shown. View entire blame