MainWindow.cc 77.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 "dockwidgettitlebareventfilter.h"
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#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"
60
#include "QGCStatusBar.h"
61
#include "UASQuickView.h"
62
63
#include "QGCDataPlot2D.h"
#include "Linecharts.h"
64
65
66
#include "UASActionsWidget.h"
#include "QGCTabbedInfoView.h"
#include "UASRawStatusView.h"
67
#include "PrimaryFlightDisplay.h"
68
69
70
71
72
73
74
75
76
77
78

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

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

#include "LogCompressor.h"

79
80
81
82
// Set up some constants
const QString MainWindow::defaultDarkStyle = ":files/styles/style-dark.css";
const QString MainWindow::defaultLightStyle = ":files/styles/style-light.css";

83
84
85
MainWindow* MainWindow::instance(QSplashScreen* screen)
{
    static MainWindow* _instance = 0;
86
    if (_instance == 0)
87
88
    {
        _instance = new MainWindow();
89
90
91
92
93
94
        if (screen)
        {
            connect(_instance, SIGNAL(initStatusChanged(QString,int,QColor)),
                    screen, SLOT(showMessage(QString,int,QColor)));
        }
        _instance->init();
95
96
97
98
99
100
101
102
103
104
105
106
107
    }
    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),
108
    currentView(VIEW_FLIGHT),
109
    currentStyle(QGC_MAINWINDOW_STYLE_DARK),
110
111
112
    aboutToCloseFlag(false),
    changingViewsFlag(false),
    centerStackActionGroup(new QActionGroup(this)),
113
114
    darkStyleFileName(defaultDarkStyle),
    lightStyleFileName(defaultLightStyle),
115
    autoReconnect(false),
116
117
118
    lowPowerMode(false),
    dockWidgetTitleBarEnabled(true),
    isAdvancedMode(false)
119
{
120
    this->setAttribute(Qt::WA_DeleteOnClose);
121
    hide();
122
123
124
125
126
}

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

129
    emit initStatusChanged(tr("Loading style"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
130
    qApp->setStyle("plastique");
131
132
133
134
135
136
137
138
    if (currentStyle == QGC_MAINWINDOW_STYLE_LIGHT)
    {
        loadStyle(currentStyle, lightStyleFileName);
    }
    else
    {
        loadStyle(currentStyle, darkStyleFileName);
    }
Lorenz Meier's avatar
Lorenz Meier committed
139

140
141
142
143
144
    if (settings.contains("ADVANCED_MODE"))
    {
        isAdvancedMode = settings.value("ADVANCED_MODE").toBool();
    }

145
146
147
148
149
150
151
152
153
154
    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 &&
155
156
                currentViewCandidate != VIEW_MISSION &&
                currentViewCandidate != VIEW_FLIGHT &&
157
158
159
160
161
162
163
                currentViewCandidate != VIEW_FULL)
        {
            currentView = currentViewCandidate;
        }
    }

    settings.sync();
164
    emit initStatusChanged(tr("Setting up user interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
165
166
167
168
169

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

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

173
174
175
176
177
178
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

    configureWindowName();

    // Setup corners
179
    setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
180
181

    // Setup UI state machines
182
    centerStackActionGroup->setExclusive(true);
183
184
185
186
187
188
189

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

    // Load Toolbar
    toolBar = new QGCToolBar(this);
    this->addToolBar(toolBar);
Lorenz Meier's avatar
Lorenz Meier committed
190

191
    // Add actions for average users (displayed next to each other)
Lorenz Meier's avatar
Lorenz Meier committed
192
    QList<QAction*> actions;
193
    actions << ui.actionFlightView;
194
    actions << ui.actionMissionView;
195
    actions << ui.actionConfiguration_2;
Lorenz Meier's avatar
Lorenz Meier committed
196
    toolBar->setPerspectiveChangeActions(actions);
197

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

    toolBar->setPerspectiveChangeAdvancedActions(advancedActions);
204
    customStatusBar = new QGCStatusBar(this);
205
206
    setStatusBar(customStatusBar);
    statusBar()->setSizeGripEnabled(true);
207

208
    emit initStatusChanged(tr("Building common widgets"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
209
210
211
212

    buildCommonWidgets();
    connectCommonWidgets();

213
    emit initStatusChanged(tr("Building common actions"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
214
215
216
217
218

    // Create actions
    connectCommonActions();

    // Populate link menu
219
    emit initStatusChanged(tr("Populating link menu"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
220
221
222
223
224
225
226
227
228
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    foreach(LinkInterface* link, links)
    {
        this->addLink(link);
    }

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

    // Connect user interface devices
229
    emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
230
231
232
233
    joystickWidget = 0;
    joystick = new JoystickInput();

#ifdef MOUSE_ENABLED_WIN
234
    emit initStatusChanged(tr("Initializing 3D mouse interface", Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
235
236
237
238
239

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

240
#if MOUSE_ENABLED_LINUX
241
    emit initStatusChanged(tr("Initializing 3D mouse interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
242
243

    mouse = new Mouse6dofInput(this);
244
    connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
245
246
#endif //MOUSE_ENABLED_LINUX

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    // 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();

263
    emit initStatusChanged(tr("Restoring last view state"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
264
265
266
267

    // Restore the window setup
    loadViewState();

268
    emit initStatusChanged(tr("Restoring last window size"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
269
270
271
272
273
274
275
276
277
278
279
280
281
    // 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
282
        if (screenWidth < 1500)
283
        {
284
285
            resize(screenWidth, screenHeight - 80);
            show();
286
287
288
289
290
291
292
293
294
295
296
        }
        else
        {
            resize(screenWidth*0.67f, qMin(screenHeight, (int)(screenWidth*0.67f*0.67f)));
            show();
        }

    }

    connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName()));
    windowNameUpdateTimer.start(15000);
297
    emit initStatusChanged(tr("Done"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
298
299
300
301
302
303
304
305
306
307
    show();
}

MainWindow::~MainWindow()
{
    if (mavlink)
    {
        delete mavlink;
        mavlink = NULL;
    }
308
309
310
311
312
    //    if (simulationLink)
    //    {
    //        simulationLink->deleteLater();
    //        simulationLink = NULL;
    //    }
313
314
    if (joystick)
    {
315
316
        joystick->shutdown();
        joystick->wait(5000);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
        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
345
346
347
348
349
350
351
352
353
354


    if (debugConsole)
    {
        delete debugConsole;
    }
    for (int i=0;i<commsWidgetList.size();i++)
    {
        commsWidgetList[i]->deleteLater();
    }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
}

void MainWindow::resizeEvent(QResizeEvent * event)
{
    if (width() > 1200)
    {
        toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    }
    else
    {
        toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
    }

    QMainWindow::resizeEvent(event);
}

QString MainWindow::getWindowStateKey()
{
373
374
375
376
377
    if (UASManager::instance()->getActiveUAS())
    {
        return QString::number(currentView)+"_windowstate_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName();
    }
    else
378
        return QString::number(currentView)+"_windowstate";
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
}

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)
        {
404
405
406
407
            QSettings settings;
            settings.beginGroup("QGC_MAINWINDOW");

            /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this);
408
409
410
411
412
413
414
415
            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);
416
            ui.menuTools->addAction(showAction);*/
417
418
419
420

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

421
422
423
424
425
            //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
426
427
428

            QDockWidget* dock;

429
430
431
            switch (view)
            {
            case VIEW_ENGINEER:
432
                dock = createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
433
434
                break;
            case VIEW_FLIGHT:
Lorenz Meier's avatar
Lorenz Meier committed
435
                dock = createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
436
437
                break;
            case VIEW_SIMULATION:
Lorenz Meier's avatar
Lorenz Meier committed
438
                dock = createDockWidget(simView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
439
440
                break;
            case VIEW_MISSION:
Lorenz Meier's avatar
Lorenz Meier committed
441
                dock = createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
442
                break;
443
444
445
            case VIEW_MAVLINK:
                dock = createDockWidget(mavlinkView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
                break;
446
            default:
Lorenz Meier's avatar
Lorenz Meier committed
447
                dock = createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
448
449
450
                break;
            }

Lorenz Meier's avatar
Lorenz Meier committed
451
452
453
            // XXX temporary "fix"
            dock->hide();

454
            //createDockWidget(0,tool,tool->getTitle(),tool->objectName(),view,location);
455
456
457
458
459
460
461
462
463
464
465
466
        }
    }
}

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

467
468
469
470
    // Log player
    logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar);
    customStatusBar->setLogPlayer(logPlayer);

471
472
473
474
475
476
477
478
479
480
481
482
483
    // 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);
484
        pilotView->setObjectName("VIEW_FLIGHT");
485
        pilotView->setCentralWidget(new QGCMapTool(this));
486
487
488
489
490
491
492
493
        addCentralWidget(pilotView, "Pilot");
    }
    if (!configView)
    {
        configView = new SubMainWindow(this);
        configView->setObjectName("VIEW_CONFIGURATION");
        configView->setCentralWidget(new QGCVehicleConfig(this));
        addCentralWidget(configView,"Config");
494
        centralWidgetToDockWidgetsMap[VIEW_CONFIGURATION] = QMap<QString,QWidget*>();
495
496
497
498
499
500

    }
    if (!engineeringView)
    {
        engineeringView = new SubMainWindow(this);
        engineeringView->setObjectName("VIEW_ENGINEER");
501
502
        engineeringView->setCentralWidget(new QGCDataPlot2D(this));
        addCentralWidget(engineeringView,tr("Logfile Plot"));
503
    }
504
    if (!mavlinkView)
505
    {
506
507
508
509
        mavlinkView = new SubMainWindow(this);
        mavlinkView->setObjectName("VIEW_MAVLINK");
        mavlinkView->setCentralWidget(new XMLCommProtocolWidget(this));
        addCentralWidget(mavlinkView,tr("Mavlink Generator"));
510
511
512
513
514
515
516
517
518
    }
    if (!simView)
    {
        simView = new SubMainWindow(this);
        simView->setObjectName("VIEW_SIMULATOR");
        simView->setCentralWidget(new QGCMapTool(this));
        addCentralWidget(simView,tr("Simulation View"));
    }

519
    // Dock widgets
520
521
522
523
    QAction* tempAction = ui.menuTools->addAction(tr("Control"));
    tempAction->setCheckable(true);
    connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));

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

526
    createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea);
527
    createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea);
528

529
    {
530
531
532
533
534
        //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";
535
    }
536

537
538
    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);
539

540
541
    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);
542
543


544
    {
545
        QAction* tempAction = ui.menuTools->addAction(tr("Status Details"));
546
        menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET";
547
548
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
549
550
    }
    {
551
552
553
554
        if (!debugConsole)
        {
            debugConsole = new DebugConsole();
            debugConsole->setWindowTitle("Communications Console");
555
            debugConsole->hide();
556
557
558
559
560
561
            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)));

        }
562
563
    }
    createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea);
564

565
    {
566
567
568
569
        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";
570
    }
571

572
    {
573
574
575
576
        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";
577
    }
578
579

    {
580
581
582
        QAction* tempAction = ui.menuTools->addAction(tr("Radio Control"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
583
    }
584

585
    createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5);
586
    createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5);
587

588
    createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8);
589

590
    QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this);
591
    infoview->addSource(mavlinkDecoder);
592
593
594
    createDockWidget(pilotView,infoview,tr("Info View"),"UAS_INFO_INFOVIEW_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea);


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

597
598
599
600
601
//    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"]);

602
603
604
    //UASRawStatusView *view = new UASRawStatusView();
    //view->setDecoder(mavlinkDecoder);
    //view->show();
605
    //hddisplay->addSource(mavlinkDecoder);
606
607
608
609
    //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"]);

610

611
    //createDockWidget(pilotView,new UASActionsWidget(this),tr("Actions"),"UNMANNED_SYSTEM_ACTION_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
612
613
614
615
616

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


617
618

    /*if (!protocolWidget)
619
620
621
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addCentralWidget(protocolWidget, "Mavlink Generator");
622
623
    }*/

624

625
626
627
628
629
    //    if (!firmwareUpdateWidget)
    //    {
    //        firmwareUpdateWidget    = new QGCFirmwareUpdate(this);
    //        addCentralWidget(firmwareUpdateWidget, "Firmware Update");
    //    }
630

631
    /*if (!hudWidget)
632
633
634
    {
        hudWidget         = new HUD(320, 240, this);
        addCentralWidget(hudWidget, tr("Head Up Display"));
635
    }*/
636

637
    /*if (!configWidget)
638
639
640
    {
        configWidget = new QGCVehicleConfig(this);
        addCentralWidget(configWidget, tr("Vehicle Configuration"));
641
642
    }*/

643

644
    /*if (!dataplotWidget)
645
646
647
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addCentralWidget(dataplotWidget, tr("Logfile Plot"));
648
    }*/
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666

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

#if (defined _MSC_VER) | (defined Q_OS_MAC)
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addCentralWidget(gEarthWidget, tr("Google Earth"));
    }
#endif
}

667
void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
668
{
669
670
    QList<QAction*> actionlist = ui.menuTools->actions();
    bool found = false;
671
    QAction *targetAction;
672
673
674
675
676
    for (int i=0;i<actionlist.size();i++)
    {
        if (actionlist[i]->text() == title)
        {
            found = true;
677
            targetAction = actionlist[i];
678
679
680
681
682
683
        }
    }
    if (!found)
    {
        QAction* tempAction = ui.menuTools->addAction(title);
        tempAction->setCheckable(true);
684
        menuToDockNameMap[tempAction] = widget->objectName();
685
686
687
688
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
689
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
690
691
692
693
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
        tempAction->setChecked(widget->isVisible());
    }
694
695
696
697
    else
    {
        if (!menuToDockNameMap.contains(targetAction))
        {
698
699
            menuToDockNameMap[targetAction] = widget->objectName();
            //menuToDockNameMap[targetAction] = title;
700
701
702
703
704
        }
        if (!centralWidgetToDockWidgetsMap.contains(view))
        {
            centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
        }
705
        centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
706
707
        connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool)));
    }
708
    parent->addDockWidget(area,widget);
709
710
}

Lorenz Meier's avatar
Lorenz Meier committed
711
QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight)
712
{
713
714
    //if (child->objectName() == "")
    //{
715
    child->setObjectName(objectname);
716
    //}
717
    QDockWidget *widget = new QDockWidget(title,this);
718
719
    if (!isAdvancedMode)
    {
720
721
722
723
724
725
        if (dockWidgetTitleBarEnabled)
        {
            dockToTitleBarMap[widget] = widget->titleBarWidget();
            QLabel *label = new QLabel(this);
            label->setText(title);
            widget->setTitleBarWidget(label);
726
            label->installEventFilter(new DockWidgetTitleBarEventFilter());
727
728
729
730
731
732
        }
        else
        {
            dockToTitleBarMap[widget] = widget->titleBarWidget();
            widget->setTitleBarWidget(new QWidget(this));
        }
733
734
735
    }
    else
    {
736
737
738
        QLabel *label = new QLabel(this);
        label->setText(title);
        dockToTitleBarMap[widget] = label;
739
740
        label->installEventFilter(new DockWidgetTitleBarEventFilter());
        label->hide();
741
    }
742
    widget->setObjectName(child->objectName());
743
744
745
746
747
748
749
    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
750
751

    return widget;
752
}
753
754
755
756
757
758
void MainWindow::loadDockWidget(QString name)
{
    if (centralWidgetToDockWidgetsMap[currentView].contains(name))
    {
        return;
    }
759
760
761
762
763
764
    if (name.startsWith("HIL_CONFIG"))
    {
        //It's a HIL widget.
        showHILConfigurationWidget(UASManager::instance()->getActiveUAS());
    }
    else if (name == "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET")
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
    {
        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")
    {
790
791
792
        //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);
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
    }
    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);
    }
823
    else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET")
824
    {
825
826
        // 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);
827
    }
828
829
830
831
    else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET")
    {
        createDockWidget(centerStack->currentWidget(),new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea);
    }
832
833
    else
    {
834
835
836
837
838
839
840
841
842
        if (customWidgetNameToFilenameMap.contains(name))
        {
            loadCustomWidget(customWidgetNameToFilenameMap[name],currentView);
            //customWidgetNameToFilenameMap.remove(name);
        }
        else
        {
            qDebug() << "Error loading window:" << name;
        }
843
844
    }
}
845
846
847

void MainWindow::showTool(bool show)
{
848
849
    //Called when a menu item is clicked on, regardless of view.

850
    QAction* act = qobject_cast<QAction *>(sender());
851
852
853
854
855
856
857
    if (menuToDockNameMap.contains(act))
    {
        QString name = menuToDockNameMap[act];
        if (centralWidgetToDockWidgetsMap.contains(currentView))
        {
            if (centralWidgetToDockWidgetsMap[currentView].contains(name))
            {
858
859
860
861
862
863
864
865
                if (show)
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->show();
                }
                else
                {
                    centralWidgetToDockWidgetsMap[currentView][name]->hide();
                }
866
            }
867
            else if (show)
868
            {
869
                loadDockWidget(name);
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
            }
        }
    }
    //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);
    }
}*/
887
888
void MainWindow::addCentralWidget(QWidget* widget, const QString& title)
{
Bryant's avatar
Bryant committed
889
    Q_UNUSED(title);
890
891
892
893
894
    // Check if this widget already has been added
    if (centerStack->indexOf(widget) == -1)
    {
        centerStack->addWidget(widget);

895
        //        QAction* tempAction = ui.menuMain->addAction(title);
896

897
898
899
900
901
902
        //        tempAction->setCheckable(true);
        //        QVariant var;
        //        var.setValue((QWidget*)widget);
        //        tempAction->setData(var);
        //        centerStackActionGroup->addAction(tempAction);
        //        connect(tempAction,SIGNAL(triggered()),this, SLOT(showCentralWidget()));
903
        //connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
904
        //        tempAction->setChecked(widget->isVisible());
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
    }
}


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

921
    if (mav && !hilDocks.contains(mav->getUASID()))
922
    {
Michael Carpenter's avatar
Michael Carpenter committed
923
924
925
        //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);

926
        QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this);
dongfang's avatar
dongfang committed
927
       QString hilDockName = tr("HIL Config %1").arg(uas->getUASName());
928
        QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea);
929
        hilDocks.insert(mav->getUASID(), hilDock);
930

931
932
933
934
        //        if (currentView != VIEW_SIMULATION)
        //            hilDock->hide();
        //        else
        //            hilDock->show();
935
936
937
938
939
940
941
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (isVisible()) storeViewState();
    aboutToCloseFlag = true;
942
    storeSettings();
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
    mavlink->storeSettings();
    UASManager::instance()->storeSettings();
    QMainWindow::closeEvent(event);
}

/**
 * Connect the signals and slots of the common window widgets
 */
void MainWindow::connectCommonWidgets()
{
    if (infoDockWidget && infoDockWidget->widget())
    {
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
}

void MainWindow::createCustomWidget()
{
962
963
    //void MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight)
    //QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
964
965
966
967
968
969

    if (QGCToolWidget::instances()->size() < 2)
    {
        // This is the first widget
        ui.menuTools->addSeparator();
    }
970
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size()));
971
    createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea);
972
973
974
975
976
977
    //tool->setObjectName("UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size()));
    QSettings settings;
    settings.beginGroup("QGC_MAINWINDOW");
    settings.setValue(QString("TOOL_PARENT_") + tool->objectName(),currentView);
    settings.endGroup();

978
979


980
981
    //connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
    //dock->setWidget(tool);
982

983
984
985
986
987
988
989
990
    //QAction* showAction = new QAction(tool->getTitle(), this);
    //showAction->setCheckable(true);
    //connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
    //connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
    //tool->setMainMenuAction(showAction);
    //ui.menuTools->addAction(showAction);
    //this->addDockWidget(Qt::BottomDockWidgetArea, dock);
    //dock->setVisible(true);
991
992
993
994
995
996
997
998
}

void MainWindow::loadCustomWidget()
{
    QString widgetFileExtension(".qgw");
    QString fileName = QFileDialog::getOpenFileName(this, tr("Specify Widget File Name"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension));
    if (fileName != "") loadCustomWidget(fileName);
}
999
1000
void MainWindow::loadCustomWidget(const QString& fileName, int view)
{
For faster browsing, not all history is shown. View entire blame