Skip to content
Snippets Groups Projects
MainWindow.cc 75.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*=====================================================================
    
    QGroundControl Open Source Ground Control Station
    
    
    (c) 2009 - 2013 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
    
    
    This file is part of the QGROUNDCONTROL project
    
        QGROUNDCONTROL is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        QGROUNDCONTROL is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
    
    ======================================================================*/
    
    /**
     * @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>
    
    #include "dockwidgettitlebareventfilter.h"
    
    #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"
    
    #include "QGCStatusBar.h"
    
    
    #ifdef QGC_OSG_ENABLED
    #include "Q3DWidgetFactory.h"
    #endif
    
    // FIXME Move
    #include "PxQuadMAV.h"
    #include "SlugsMAV.h"
    
    #include "LogCompressor.h"
    
    
    // Set up some constants
    const QString MainWindow::defaultDarkStyle = ":files/styles/style-dark.css";
    const QString MainWindow::defaultLightStyle = ":files/styles/style-light.css";
    
    
    MainWindow* MainWindow::instance(QSplashScreen* screen)
    {
        static MainWindow* _instance = 0;
        if(_instance == 0)
        {
            _instance = new MainWindow();
            if (screen) connect(_instance, SIGNAL(initStatusChanged(QString)), screen, SLOT(showMessage(QString)));
    
            /* Set the application as parent to ensure that this object
                     * will be destroyed when the main application exits */
            //_instance->setParent(qApp);
        }
        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),
    
        currentView(VIEW_FLIGHT),
    
        currentStyle(QGC_MAINWINDOW_STYLE_DARK),
    
        aboutToCloseFlag(false),
        changingViewsFlag(false),
        centerStackActionGroup(new QActionGroup(this)),
    
        darkStyleFileName(defaultDarkStyle),
        lightStyleFileName(defaultLightStyle),
    
        autoReconnect(false),
        lowPowerMode(false)
    {
        hide();
    
        emit initStatusChanged("Loading UI Settings..");
        loadSettings();
    
    
        emit initStatusChanged("Loading Style.");
    
        if (currentStyle == QGC_MAINWINDOW_STYLE_LIGHT)
        {
            loadStyle(currentStyle, lightStyleFileName);
        }
        else
        {
            loadStyle(currentStyle, darkStyleFileName);
        }
    
        if (settings.contains("ADVANCED_MODE"))
        {
            isAdvancedMode = settings.value("ADVANCED_MODE").toBool();
        }
    
    
        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 &&
    
                    currentViewCandidate != VIEW_MISSION &&
                    currentViewCandidate != VIEW_FLIGHT &&
    
                    currentViewCandidate != VIEW_FULL)
            {
                currentView = currentViewCandidate;
            }
        }
    
        settings.sync();
    
        emit initStatusChanged("Setting up user interface.");
    
        // Setup user interface
        ui.setupUi(this);
        hide();
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        // We only need this menu if we have more than one system
    
    //    ui.menuConnected_Systems->setEnabled(false);
    
        // Set dock options
        setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);
    
        configureWindowName();
    
        // Setup corners
    
        setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
    
    
        // Setup UI state machines
    
        centerStackActionGroup->setExclusive(true);
    
    
        centerStack = new QStackedWidget(this);
        setCentralWidget(centerStack);
    
        // Load Toolbar
        toolBar = new QGCToolBar(this);
        this->addToolBar(toolBar);
    
        // Add actions for average users (displayed next to each other)
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        QList<QAction*> actions;
    
        actions << ui.actionMissionView;
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        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);
    
        customStatusBar = new QGCStatusBar(this);
    
        setStatusBar(customStatusBar);
        statusBar()->setSizeGripEnabled(true);
    
        emit initStatusChanged("Building common widgets.");
    
        buildCommonWidgets();
        connectCommonWidgets();
    
        emit initStatusChanged("Building common actions.");
    
        // Create actions
        connectCommonActions();
    
        // Populate link menu
        emit initStatusChanged("Populating link menu");
        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
        emit initStatusChanged("Initializing joystick interface.");
        joystickWidget = 0;
        joystick = new JoystickInput();
    
    #ifdef MOUSE_ENABLED_WIN
        emit initStatusChanged("Initializing 3D mouse interface.");
    
        mouseInput = new Mouse3DInput(this);
        mouse = new Mouse6dofInput(mouseInput);
    #endif //MOUSE_ENABLED_WIN
    
    
    #if MOUSE_ENABLED_LINUX
        emit initStatusChanged("Initializing 3D mouse interface.");
    
        mouse = new Mouse6dofInput(this);
    
        connect(this, SIGNAL(x11EventOccured(XEvent*)), mouse, SLOT(handleX11Event(XEvent*)));
    
    #endif //MOUSE_ENABLED_LINUX
    
    
        // 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();
    
        emit initStatusChanged("Restoring last view state.");
    
        // Restore the window setup
        loadViewState();
    
        emit initStatusChanged("Restoring last window size.");
        // 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
            if (screenWidth < 1500)
    
                resize(screenWidth, screenHeight - 80);
                show();
    
            }
            else
            {
                resize(screenWidth*0.67f, qMin(screenHeight, (int)(screenWidth*0.67f*0.67f)));
                show();
            }
    
        }
    
        connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName()));
        windowNameUpdateTimer.start(15000);
        emit initStatusChanged("Done.");
        show();
    }
    
    MainWindow::~MainWindow()
    {
        if (mavlink)
        {
            delete mavlink;
            mavlink = NULL;
        }
    //    if (simulationLink)
    //    {
    //        simulationLink->deleteLater();
    //        simulationLink = NULL;
    //    }
        if (joystick)
        {
    
            joystick->shutdown();
            joystick->wait(5000);
    
            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
    }
    
    void MainWindow::resizeEvent(QResizeEvent * event)
    {
        if (width() > 1200)
        {
            toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        }
        else
        {
            toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
        }
    
        QMainWindow::resizeEvent(event);
    }
    
    QString MainWindow::getWindowStateKey()
    {
    
        if (UASManager::instance()->getActiveUAS())
        {
            return QString::number(currentView)+"_windowstate_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName();
        }
        else
    
    
        return QString::number(currentView)+"_windowstate";
    }
    
    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)
            {
    
                QSettings settings;
                settings.beginGroup("QGC_MAINWINDOW");
    
                /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this);
    
                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);
    
    
                // Load dock widget location (default is bottom)
                Qt::DockWidgetArea location = static_cast <Qt::DockWidgetArea>(tool->getDockWidgetArea(currentView));
    
    
                //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();
    
    
                QDockWidget* dock;
    
    
                    dock = createDockWidget(dataView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
    
                    dock = createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
    
                    dock = createDockWidget(simView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
    
                    dock = createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
    
                    dock = createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location);
    
                // XXX temporary "fix"
                dock->hide();
    
    
                //createDockWidget(0,tool,tool->getTitle(),tool->objectName(),view,location);
    
            }
        }
    }
    
    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);
    
    
        // Log player
        logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar);
        customStatusBar->setLogPlayer(logPlayer);
    
    
        // 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);
    
            pilotView->setObjectName("VIEW_FLIGHT");
    
            //pilotView->setCentralWidget(new HUD(320,240,this));
            pilotView->setCentralWidget(new QGCMapTool(this));
    
            //hudWidget         = new HUD(320, 240, this);
            //addCentralWidget(hudWidget, tr("Head Up Display"));
            //mapWidget = new QGCMapTool(this);
            addCentralWidget(pilotView, "Pilot");
        }
        if (!configView)
        {
            configView = new SubMainWindow(this);
            configView->setObjectName("VIEW_CONFIGURATION");
            configView->setCentralWidget(new QGCVehicleConfig(this));
            addCentralWidget(configView,"Config");
    
            centralWidgetToDockWidgetsMap[VIEW_CONFIGURATION] = QMap<QString,QWidget*>();
    
    
        }
        if (!engineeringView)
        {
            engineeringView = new SubMainWindow(this);
            engineeringView->setObjectName("VIEW_ENGINEER");
            engineeringView->setCentralWidget(new XMLCommProtocolWidget(this));
            addCentralWidget(engineeringView,"Mavlink Generator");
        }
        if (!dataView)
        {
            dataView = new SubMainWindow(this);
            dataView->setObjectName("VIEW_DATA");
            dataView->setCentralWidget(new QGCDataPlot2D(this));
            addCentralWidget(dataView,tr("Logfile Plot"));
        }
        if (!simView)
        {
            simView = new SubMainWindow(this);
            simView->setObjectName("VIEW_SIMULATOR");
            simView->setCentralWidget(new QGCMapTool(this));
            addCentralWidget(simView,tr("Simulation View"));
        }
    
    
        QAction* tempAction = ui.menuTools->addAction(tr("Control"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
    
    
            createDockWidget(simView,new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",VIEW_SIMULATION,Qt::LeftDockWidgetArea);
    
            createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea);
    
    
            {
            //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";
            }
    
    
            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);
    
            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);
    
            QAction* tempAction = ui.menuTools->addAction(tr("Status Details"));
    
            menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET";
    
            tempAction->setCheckable(true);
            connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
    
            QAction* tempAction = ui.menuTools->addAction(tr("Communication Console"));
    
            menuToDockNameMap[tempAction] = "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET";
    
            tempAction->setCheckable(true);
            connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
    
            }
            createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea);
    
    
    
        //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");
    
        //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(acceptList, "Flight Display", this);
        //hdDisplay->addSource(mavlinkDecoder);
        //createDockWidget(pilotView,hdDisplay,tr("Flight Display"),"HEAD_DOWN_DISPLAY_1_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
    
        //HDDisplay* hdDisplay2 = new HDDisplay(acceptList2, "Actuator Status", this);
        //hdDisplay2->addSource(mavlinkDecoder);
        //createDockWidget(pilotView,hdDisplay2,tr("Actuator Status"),"HEAD_DOWN_DISPLAY_2_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
    
        {
        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";
        }
    
        {
        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";
        }
    
    
        {
        QAction* tempAction = ui.menuTools->addAction(tr("Radio Control"));
        tempAction->setCheckable(true);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
        }
    
        createDockWidget(simView,new HUD(320,240,this),tr("Head Up Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5);
    
        createDockWidget(pilotView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_FLIGHT,Qt::RightDockWidgetArea);
        createDockWidget(pilotView,new HUD(320,240,this),tr("Head Up Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8);
        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"]);
    
    
        // Custom widgets, added last to all menus and layouts
        buildCustomWidget();
    
    
    
        {
            protocolWidget    = new XMLCommProtocolWidget(this);
            addCentralWidget(protocolWidget, "Mavlink Generator");
    
    
    //    if (!firmwareUpdateWidget)
    //    {
    //        firmwareUpdateWidget    = new QGCFirmwareUpdate(this);
    //        addCentralWidget(firmwareUpdateWidget, "Firmware Update");
    //    }
    
    
        {
            hudWidget         = new HUD(320, 240, this);
            addCentralWidget(hudWidget, tr("Head Up Display"));
    
        {
            configWidget = new QGCVehicleConfig(this);
            addCentralWidget(configWidget, tr("Vehicle Configuration"));
    
        {
            dataplotWidget    = new QGCDataPlot2D(this);
            addCentralWidget(dataplotWidget, tr("Logfile Plot"));
    
    
    #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
    }
    
    
    void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
    
        QList<QAction*> actionlist = ui.menuTools->actions();
        bool found = false;
    
        for (int i=0;i<actionlist.size();i++)
        {
            if (actionlist[i]->text() == title)
            {
                found = true;
    
            }
        }
        if (!found)
        {
            QAction* tempAction = ui.menuTools->addAction(title);
            tempAction->setCheckable(true);
    
            menuToDockNameMap[tempAction] = widget->objectName();
    
            if (!centralWidgetToDockWidgetsMap.contains(view))
            {
                centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
            }
    
            centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
    
            connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
            connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
            tempAction->setChecked(widget->isVisible());
        }
    
        else
        {
            if (!menuToDockNameMap.contains(targetAction))
            {
    
                menuToDockNameMap[targetAction] = widget->objectName();
                //menuToDockNameMap[targetAction] = title;
    
            }
            if (!centralWidgetToDockWidgetsMap.contains(view))
            {
                centralWidgetToDockWidgetsMap[view] = QMap<QString,QWidget*>();
            }
    
            centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget;
    
            connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool)));
        }
    
    QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight)
    
        QDockWidget *widget = new QDockWidget(title,this);
    
            if (dockWidgetTitleBarEnabled)
            {
                dockToTitleBarMap[widget] = widget->titleBarWidget();
                QLabel *label = new QLabel(this);
                label->setText(title);
                widget->setTitleBarWidget(label);
    
                label->installEventFilter(new DockWidgetTitleBarEventFilter());
    
            }
            else
            {
                dockToTitleBarMap[widget] = widget->titleBarWidget();
                widget->setTitleBarWidget(new QWidget(this));
            }
    
            QLabel *label = new QLabel(this);
            label->setText(title);
            dockToTitleBarMap[widget] = label;
    
            label->installEventFilter(new DockWidgetTitleBarEventFilter());
            label->hide();
    
        widget->setWidget(child);
        if (minheight != 0 || minwidth != 0)
        {
            widget->setMinimumHeight(minheight);
            widget->setMinimumWidth(minwidth);
        }
        addTool(qobject_cast<SubMainWindow*>(parent),view,widget,title,area);
    
    
        return widget;
    
    void MainWindow::loadDockWidget(QString name)
    {
        if (centralWidgetToDockWidgetsMap[currentView].contains(name))
        {
            return;
        }
        if (name == "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET")
        {
            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")
        {
            createDockWidget(centerStack->currentWidget(),new DebugConsole(this),tr("Communication Console"),"COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea);
        }
        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);
        }
        else if (name == "HEAD_UP_DISPLAY_DOCKWIDGET")
        {
            createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Head Up Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea);
        }
    
        else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET")
        {
            createDockWidget(centerStack->currentWidget(),new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea);
        }
    
            if (customWidgetNameToFilenameMap.contains(name))
            {
                loadCustomWidget(customWidgetNameToFilenameMap[name],currentView);
                //customWidgetNameToFilenameMap.remove(name);
            }
            else
            {
                qDebug() << "Error loading window:" << name;
            }
    
    
    void MainWindow::showTool(bool show)
    {
    
        //Called when a menu item is clicked on, regardless of view.
    
    
        QAction* act = qobject_cast<QAction *>(sender());
    
        if (menuToDockNameMap.contains(act))
        {
            QString name = menuToDockNameMap[act];
            if (centralWidgetToDockWidgetsMap.contains(currentView))
            {
                if (centralWidgetToDockWidgetsMap[currentView].contains(name))
                {
    
                    if (show)
                    {
                        centralWidgetToDockWidgetsMap[currentView][name]->show();
                    }
                    else
                    {
                        centralWidgetToDockWidgetsMap[currentView][name]->hide();
                    }
    
                }
            }
        }
        //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);
        }
    }*/
    
    void MainWindow::addCentralWidget(QWidget* widget, const QString& title)
    {
    
        Q_UNUSED(title);
    
        // Check if this widget already has been added
        if (centerStack->indexOf(widget) == -1)
        {
            centerStack->addWidget(widget);
    
    
    //        QAction* tempAction = ui.menuMain->addAction(title);
    
    //        tempAction->setCheckable(true);
    //        QVariant var;
    //        var.setValue((QWidget*)widget);
    //        tempAction->setData(var);
    //        centerStackActionGroup->addAction(tempAction);
    //        connect(tempAction,SIGNAL(triggered()),this, SLOT(showCentralWidget()));
    
            //connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
    
    //        tempAction->setChecked(widget->isVisible());
    
        }
    }
    
    
    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);
    
    
        if (mav && !hilDocks.contains(mav->getUASID()))
    
        {
            QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this);
            QString hilDockName = tr("HIL Config (%1)").arg(uas->getUASName());
            QDockWidget* hilDock = new QDockWidget(hilDockName, this);
            hilDock->setWidget(hconf);
            hilDock->setObjectName(QString("HIL_CONFIG_%1").arg(uas->getUASID()));
    
            //addTool(hilDock, hilDockName, Qt::LeftDockWidgetArea);
    
            hilDocks.insert(mav->getUASID(), hilDock);
    
            if (currentView != VIEW_SIMULATION)
                hilDock->hide();
            else
                hilDock->show();
    
        }
    }
    
    void MainWindow::closeEvent(QCloseEvent *event)
    {
        if (isVisible()) storeViewState();
        storeSettings();
        aboutToCloseFlag = true;
        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()
    {
    
        //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);
    
    
        if (QGCToolWidget::instances()->size() < 2)
        {
            // This is the first widget
            ui.menuTools->addSeparator();
        }
    
        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);
    
        //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();
    
    
        //connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
        //dock->setWidget(tool);
    
        //QAction* showAction = new QAction(tool->getTitle(), this);
        //showAction->setCheckable(true);
        //connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
        //connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
        //tool->setMainMenuAction(showAction);
        //ui.menuTools->addAction(showAction);
        //this->addDockWidget(Qt::BottomDockWidgetArea, dock);
        //dock->setVisible(true);
    
    }
    
    void MainWindow::loadCustomWidget()
    {
        QString widgetFileExtension(".qgw");
        QString fileName = QFileDialog::getOpenFileName(this, tr("Specify Widget File Name"), QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension));
        if (fileName != "") loadCustomWidget(fileName);
    }
    
    void MainWindow::loadCustomWidget(const QString& fileName, int view)
    {
        QGCToolWidget* tool = new QGCToolWidget("", this);
        if (tool->loadSettings(fileName, true))
        {
            qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName();
            switch ((VIEW_SECTIONS)view)
            {
            case VIEW_ENGINEER:
                createDockWidget(dataView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
                break;
            case VIEW_FLIGHT:
                createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
                break;
            case VIEW_SIMULATION:
                createDockWidget(simView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
                break;
            case VIEW_MISSION:
                createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
                break;
            default:
                {
                    //Delete tool, create menu item to tie it to.
                    customWidgetNameToFilenameMap[tool->objectName()+"DOCK"] = fileName;
                    QAction* tempAction = ui.menuTools->addAction(tool->getTitle());
                    menuToDockNameMap[tempAction] = tool->objectName()+"DOCK";
                    tempAction->setCheckable(true);
                    connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
                    tool->deleteLater();
                    //createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
                }
                break;
            }