Skip to content
Snippets Groups Projects
MainWindow.cc 53.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*=====================================================================
    
    QGroundControl Open Source Ground Control Station
    
    (c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
    
    This file is part of the QGROUNDCONTROL project
    
        QGROUNDCONTROL is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        QGROUNDCONTROL is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
    
    
    pixhawk's avatar
    pixhawk committed
    ======================================================================*/
    
    /**
     * @file
    
     *   @brief Implementation of class MainWindow
    
     *   @author Lorenz Meier <mail@qgroundcontrol.org>
    
    pixhawk's avatar
    pixhawk committed
     */
    
    #include <QSettings>
    #include <QDockWidget>
    #include <QNetworkInterface>
    #include <QMessageBox>
    #include <QDebug>
    #include <QTimer>
    #include <QHostInfo>
    
    lm's avatar
    lm committed
    #include <QSplashScreen>
    
    pixhawk's avatar
    pixhawk committed
    
    
    #include "QGC.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "MAVLinkSimulationLink.h"
    #include "SerialLink.h"
    #include "UDPLink.h"
    #include "MAVLinkProtocol.h"
    #include "CommConfigurationWindow.h"
    
    #include "QGCWaypointListMulti.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "MainWindow.h"
    #include "JoystickWidget.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "GAudioOutput.h"
    
    #include "QGCMapTool.h"
    
    LM's avatar
    LM committed
    #include "MAVLinkDecoder.h"
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    #include "QGCMAVLinkMessageSender.h"
    
    #include "QGCRGBDView.h"
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    #include "QGCFirmwareUpdate.h"
    
    #ifdef QGC_OSG_ENABLED
    
    #include "Q3DWidgetFactory.h"
    
    pixhawk's avatar
    pixhawk committed
    
    
    lm's avatar
    lm committed
    // FIXME Move
    #include "PxQuadMAV.h"
    #include "SlugsMAV.h"
    
    
    pixhawk's avatar
    pixhawk committed
    
    
    #include "LogCompressor.h"
    
    pixhawk's avatar
    pixhawk committed
    
    
    lm's avatar
    lm committed
    MainWindow* MainWindow::instance(QSplashScreen* screen)
    
    lm's avatar
    lm committed
            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;
    
    pixhawk's avatar
    pixhawk committed
    /**
    * 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()
    **/
    
        QMainWindow(parent),
        currentView(VIEW_UNCONNECTED),
    
        aboutToCloseFlag(false),
        changingViewsFlag(false),
    
        centerStackActionGroup(new QActionGroup(this)),
    
        styleFileName(QCoreApplication::applicationDirPath() + "/style-indoor.css"),
    
    pixhawk's avatar
    pixhawk committed
    {
    
    lm's avatar
    lm committed
        hide();
        emit initStatusChanged("Loading UI Settings..");
    
        if (!settings.contains("CURRENT_VIEW"))
        {
    
            // Set this view as default view
            settings.setValue("CURRENT_VIEW", currentView);
    
            // LOAD THE LAST VIEW
            VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
            if (currentViewCandidate != VIEW_ENGINEER &&
    
                    currentViewCandidate != VIEW_OPERATOR &&
    
                    currentViewCandidate != VIEW_PILOT &&
                    currentViewCandidate != VIEW_FULL)
            {
    
                currentView = currentViewCandidate;
    
    lm's avatar
    lm committed
        emit initStatusChanged("Loading Style.");
    
    lm's avatar
    lm committed
        emit initStatusChanged("Setting up user interface.");
    
    
    pixhawk's avatar
    pixhawk committed
        // Setup user interface
        ui.setupUi(this);
    
    lm's avatar
    lm committed
        hide();
    
    pixhawk's avatar
    pixhawk committed
    
    
        // Set dock options
        setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);
        statusBar()->setSizeGripEnabled(true);
    
        configureWindowName();
    
    
        // Setup corners
        setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
    
    
    	centerStackActionGroup->setExclusive(true);
    
        centerStack = new QStackedWidget(this);
        setCentralWidget(centerStack);
    
    lm's avatar
    lm committed
        // Load Toolbar
        toolBar = new QGCToolBar(this);
        this->addToolBar(toolBar);
        // Add actions
        toolBar->addPerspectiveChangeAction(ui.actionOperatorsView);
        toolBar->addPerspectiveChangeAction(ui.actionEngineersView);
        toolBar->addPerspectiveChangeAction(ui.actionPilotsView);
    
    
    lm's avatar
    lm committed
        emit initStatusChanged("Building common widgets.");
    
    
    lm's avatar
    lm committed
        emit initStatusChanged("Building common actions.");
    
    
        // Create actions
    
    lm's avatar
    lm committed
        emit initStatusChanged("Populating link menu");
    
        QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    
        foreach(LinkInterface* link, links)
        {
    
        connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));
    
    
        // Connect user interface devices
    
    lm's avatar
    lm committed
        emit initStatusChanged("Initializing joystick interface.");
    
        joystickWidget = 0;
        joystick = new JoystickInput();
    
            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();
    
    lm's avatar
    lm committed
        emit initStatusChanged("Restoring last view state.");
    
    
        // Restore the window setup
        loadViewState();
    
    
    lm's avatar
    lm committed
        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();
    
            if (screenWidth < 1200)
            {
                showFullScreen();
            }
            else
            {
                resize(screenWidth*0.67f, qMin(screenHeight, (int)(screenWidth*0.67f*0.67f)));
                show();
            }
    
        }
    
    
        connect(&windowNameUpdateTimer, SIGNAL(timeout()), this, SLOT(configureWindowName()));
        windowNameUpdateTimer.start(15000);
    
    lm's avatar
    lm committed
        emit initStatusChanged("Done.");
        show();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
    MainWindow::~MainWindow()
    
    pixhawk's avatar
    pixhawk committed
    {
    
        delete joystick;
    
        // Get and delete all dockwidgets and contained
        // widgets
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        QObjectList childList(this->children());
    
    
        QObjectList::iterator i;
        QDockWidget* dockWidget;
    
        for (i = childList.begin(); i != childList.end(); ++i)
        {
    
            dockWidget = dynamic_cast<QDockWidget*>(*i);
    
                // Remove dock widget from main window
    
                // removeDockWidget(dockWidget);
                // delete dockWidget->widget();
    
                delete dockWidget;
            }
    
    Lorenz Meier's avatar
    Lorenz Meier committed
            else if (dynamic_cast<QObject*>(*i))
    
    LM's avatar
    LM committed
            {
                delete dynamic_cast<QObject*>(*i);
            }
    
    LM's avatar
    LM committed
        // Delete all UAS objects
    
    lm's avatar
    lm committed
    void MainWindow::resizeEvent(QResizeEvent * event)
    {
    
    lm's avatar
    lm committed
            ui.statusBar->setVisible(false);
    
    lm's avatar
    lm committed
            ui.statusBar->setVisible(true);
    
            ui.statusBar->setSizeGripEnabled(true);
    
    lm's avatar
    lm committed
        }
    
    
        if (width() > 1200)
        {
            toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        }
        else
        {
            toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
        }
    
        QMainWindow::resizeEvent(event);
    
    lm's avatar
    lm committed
    }
    
    
    QString MainWindow::getWindowStateKey()
    {
    
        return QString::number(currentView)+"_windowstate";
    
    }
    
    QString MainWindow::getWindowGeometryKey()
    {
    
        //return QString::number(currentView)+"_geometry";
        return "_geometry";
    
    lm's avatar
    lm committed
    void MainWindow::buildCustomWidget()
    {
    
    lm's avatar
    lm committed
        // Create custom widgets
        QList<QGCToolWidget*> widgets = QGCToolWidget::createWidgetsFromSettings(this);
    
    lm's avatar
    lm committed
    
    
    lm's avatar
    lm committed
        if (widgets.size() > 0)
        {
            ui.menuTools->addSeparator();
        }
    
    lm's avatar
    lm committed
    
    
    lm's avatar
    lm committed
        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)
    
    lm's avatar
    lm committed
                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);
                ui.menuTools->addAction(showAction);
    
                // Load dock widget location (default is bottom)
                Qt::DockWidgetArea location = static_cast <Qt::DockWidgetArea>(tool->getDockWidgetArea(currentView));
    
                addDockWidget(location, dock);
    
    void MainWindow::buildCommonWidgets()
    {
        //TODO:  move protocol outside UI
        mavlink     = new MAVLinkProtocol();
    
        connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
    
    LM's avatar
    LM committed
        // Add generic MAVLink decoder
        mavlinkDecoder = new MAVLinkDecoder(mavlink, this);
    
            controlDockWidget = new QDockWidget(tr("Control"), this);
    
            controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
    
            controlDockWidget->setWidget( new UASControlWidget(this) );
    
            addTool(controlDockWidget, tr("Control"), Qt::LeftDockWidgetArea);
    
            listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
            listDockWidget->setWidget( new UASListWidget(this) );
    
            listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
    
            addTool(listDockWidget, tr("Unmanned Systems"), Qt::RightDockWidgetArea);
    
            waypointsDockWidget = new QDockWidget(tr("Mission Plan"), this);
    
            waypointsDockWidget->setWidget( new QGCWaypointListMulti(this) );
    
            waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
    
            addTool(waypointsDockWidget, tr("Mission Plan"), Qt::BottomDockWidgetArea);
    
            infoDockWidget = new QDockWidget(tr("Status Details"), this);
            infoDockWidget->setWidget( new UASInfoWidget(this) );
    
    pixhawk's avatar
    pixhawk committed
            infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
    
            addTool(infoDockWidget, tr("Status Details"), Qt::RightDockWidgetArea);
    
            debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
            debugConsoleDockWidget->setWidget( new DebugConsole(this) );
    
            debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
    
    LM's avatar
    LM committed
    
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
            connect(mavlinkDecoder, SIGNAL(textMessageReceived(int, int, int, const QString)), debugConsole, SLOT(receiveTextMessage(int, int, int, const QString)));
    
    
            addTool(debugConsoleDockWidget, tr("Communication Console"), Qt::BottomDockWidgetArea);
    
            logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
    
    lm's avatar
    lm committed
            logPlayer = new QGCMAVLinkLogPlayer(mavlink, this);
            toolBar->setLogPlayer(logPlayer);
            logPlayerDockWidget->setWidget(logPlayer);
    
            logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
    
            addTool(logPlayerDockWidget, tr("MAVLink Log Replay"), Qt::RightDockWidgetArea);
    
    lm's avatar
    lm committed
        if (!mavlinkInspectorWidget)
        {
            mavlinkInspectorWidget = new QDockWidget(tr("MAVLink Message Inspector"), this);
            mavlinkInspectorWidget->setWidget( new QGCMAVLinkInspector(mavlink, this) );
            mavlinkInspectorWidget->setObjectName("MAVLINK_INSPECTOR_DOCKWIDGET");
    
    lm's avatar
    lm committed
            addTool(mavlinkInspectorWidget, tr("MAVLink Inspector"), Qt::RightDockWidgetArea);
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!mavlinkSenderWidget)
        {
            mavlinkSenderWidget = new QDockWidget(tr("MAVLink Message Sender"), this);
            mavlinkSenderWidget->setWidget( new QGCMAVLinkMessageSender(mavlink, this) );
            mavlinkSenderWidget->setObjectName("MAVLINK_SENDER_DOCKWIDGET");
            addTool(mavlinkSenderWidget, tr("MAVLink Sender"), Qt::RightDockWidgetArea);
        }
    
    
    pixhawk's avatar
    pixhawk committed
        //FIXME: memory of acceptList will never be freed again
        QStringList* acceptList = new QStringList();
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        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");
    
    pixhawk's avatar
    pixhawk committed
        //FIXME: memory of acceptList2 will never be freed again
        QStringList* acceptList2 = new QStringList();
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        acceptList2->append("0,RAW_PRESSURE.pres_abs,hPa,65500");
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!parametersDockWidget)
        {
    
    lm's avatar
    lm committed
            parametersDockWidget = new QDockWidget(tr("Calibration and Onboard Parameters"), this);
            parametersDockWidget->setWidget( new ParameterInterface(this) );
            parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
            addTool(parametersDockWidget, tr("Calibration and Parameters"), Qt::RightDockWidgetArea);
        }
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!hsiDockWidget)
        {
    
    lm's avatar
    lm committed
            hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
            hsiDockWidget->setWidget( new HSIDisplay(this) );
            hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
            addTool(hsiDockWidget, tr("Horizontal Situation"), Qt::BottomDockWidgetArea);
        }
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!headDown1DockWidget)
        {
    
    lm's avatar
    lm committed
            headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
    
            HDDisplay* hdDisplay = new HDDisplay(acceptList, "Flight Display", this);
            hdDisplay->addSource(mavlinkDecoder);
            headDown1DockWidget->setWidget(hdDisplay);
    
    lm's avatar
    lm committed
            headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
            addTool(headDown1DockWidget, tr("Flight Display"), Qt::RightDockWidgetArea);
        }
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!headDown2DockWidget)
        {
    
    lm's avatar
    lm committed
            headDown2DockWidget = new QDockWidget(tr("Actuator Status"), this);
    
            HDDisplay* hdDisplay = new HDDisplay(acceptList2, "Actuator Status", this);
            hdDisplay->addSource(mavlinkDecoder);
            headDown2DockWidget->setWidget(hdDisplay);
    
    lm's avatar
    lm committed
            headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
            addTool(headDown2DockWidget, tr("Actuator Status"), Qt::RightDockWidgetArea);
        }
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!rcViewDockWidget)
        {
    
    lm's avatar
    lm committed
            rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
            rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
            rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
            addTool(rcViewDockWidget, tr("Radio Control"), Qt::BottomDockWidgetArea);
        }
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!headUpDockWidget)
        {
    
    lm's avatar
    lm committed
            headUpDockWidget = new QDockWidget(tr("HUD"), this);
            headUpDockWidget->setWidget( new HUD(320, 240, this));
            headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
            addTool(headUpDockWidget, tr("Head Up Display"), Qt::RightDockWidgetArea);
        }
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!video1DockWidget)
        {
    
    lm's avatar
    lm committed
            video1DockWidget = new QDockWidget(tr("Video Stream 1"), this);
    
            QGCRGBDView* video1 =  new QGCRGBDView(160, 120, this);
    
    lm's avatar
    lm committed
            video1->enableHUDInstruments(false);
    
            video1->enableVideo(false);
    
    lm's avatar
    lm committed
            // FIXME select video stream as well
            video1DockWidget->setWidget(video1);
            video1DockWidget->setObjectName("VIDEO_STREAM_1_DOCK_WIDGET");
            addTool(video1DockWidget, tr("Video Stream 1"), Qt::LeftDockWidgetArea);
        }
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!video2DockWidget)
        {
    
    lm's avatar
    lm committed
            video2DockWidget = new QDockWidget(tr("Video Stream 2"), this);
    
            QGCRGBDView* video2 =  new QGCRGBDView(160, 120, this);
    
    lm's avatar
    lm committed
            video2->enableHUDInstruments(false);
    
            video2->enableVideo(false);
    
    lm's avatar
    lm committed
            // FIXME select video stream as well
            video2DockWidget->setWidget(video2);
            video2DockWidget->setObjectName("VIDEO_STREAM_2_DOCK_WIDGET");
            addTool(video2DockWidget, tr("Video Stream 2"), Qt::LeftDockWidgetArea);
        }
    
    
    //    if (!rgbd1DockWidget) {
    //        rgbd1DockWidget = new QDockWidget(tr("Video Stream 1"), this);
    //        HUD* video1 =  new HUD(160, 120, this);
    //        video1->enableHUDInstruments(false);
    //        video1->enableVideo(true);
    //        // FIXME select video stream as well
    //        video1DockWidget->setWidget(video1);
    //        video1DockWidget->setObjectName("VIDEO_STREAM_1_DOCK_WIDGET");
    //        addTool(video1DockWidget, tr("Video Stream 1"), Qt::LeftDockWidgetArea);
    //    }
    
    //    if (!rgbd2DockWidget) {
    //        video2DockWidget = new QDockWidget(tr("Video Stream 2"), this);
    //        HUD* video2 =  new HUD(160, 120, this);
    //        video2->enableHUDInstruments(false);
    //        video2->enableVideo(true);
    //        // FIXME select video stream as well
    //        video2DockWidget->setWidget(video2);
    //        video2DockWidget->setObjectName("VIDEO_STREAM_2_DOCK_WIDGET");
    //        addTool(video2DockWidget, tr("Video Stream 2"), Qt::LeftDockWidgetArea);
    //    }
    
    
    lm's avatar
    lm committed
        // Custom widgets, added last to all menus and layouts
        buildCustomWidget();
    
        // Center widgets
        if (!mapWidget)
        {
            mapWidget = new QGCMapTool(this);
            addCentralWidget(mapWidget, "Maps");
        }
    
        if (!protocolWidget)
        {
            protocolWidget    = new XMLCommProtocolWidget(this);
            addCentralWidget(protocolWidget, "Mavlink Generator");
        }
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!firmwareUpdateWidget)
        {
            firmwareUpdateWidget    = new QGCFirmwareUpdate(this);
            addCentralWidget(firmwareUpdateWidget, "Firmware Update");
        }
    
    
        if (!hudWidget) {
    
            addCentralWidget(hudWidget, tr("Head Up Display"));
    
    lm's avatar
    lm committed
        }
    
    
        if (!dataplotWidget) {
    
            dataplotWidget    = new QGCDataPlot2D(this);
    
            addCentralWidget(dataplotWidget, tr("Logfile Plot"));
    
        if (!_3DWidget) {
    
            _3DWidget         = Q3DWidgetFactory::get("PIXHAWK", this);
    
            addCentralWidget(_3DWidget, tr("Local 3D"));
    
    #if (defined _MSC_VER) | (defined Q_OS_MAC)
    
        if (!gEarthWidget) {
    
            gEarthWidget = new QGCGoogleEarthView(this);
    
            addCentralWidget(gEarthWidget, tr("Google Earth"));
    
    lm's avatar
    lm committed
    }
    
    void MainWindow::addTool(QDockWidget* widget, const QString& title, Qt::DockWidgetArea area)
    
    lm's avatar
    lm committed
    {
    
        QAction* tempAction = ui.menuTools->addAction(title);
    
        tempAction->setCheckable(true);
    
        QVariant var;
        var.setValue((QWidget*)widget);
        tempAction->setData(var);
        connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool)));
    
    LM's avatar
    LM committed
        connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool)));
        tempAction->setChecked(widget->isVisible());
    
    void MainWindow::showTool(bool show)
    
    lm's avatar
    lm committed
    {
    
        QAction* act = qobject_cast<QAction *>(sender());
        QWidget* widget = qVariantValue<QWidget *>(act->data());
        widget->setVisible(show);
    
    void MainWindow::addCentralWidget(QWidget* widget, const QString& title)
    
    lm's avatar
    lm committed
    {
    
        // 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()));
    
    LM's avatar
    LM committed
            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::closeEvent(QCloseEvent *event)
    {
    
    pixhawk's avatar
    pixhawk committed
        if (isVisible()) storeViewState();
    
        aboutToCloseFlag = true;
    
    lm's avatar
    lm committed
        UASManager::instance()->storeSettings();
    
        QMainWindow::closeEvent(event);
    }
    
    
    /**
     * Connect the signals and slots of the common window widgets
     */
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (infoDockWidget && infoDockWidget->widget())
        {
    
    pixhawk's avatar
    pixhawk committed
            connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                    infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
        }
    
        QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
        QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", dock);
    
    lm's avatar
    lm committed
    
    
    LM's avatar
    LM committed
        if (QGCToolWidget::instances()->size() < 2)
        {
    
    lm's avatar
    lm committed
            // This is the first widget
            ui.menuTools->addSeparator();
        }
    
        connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
    
        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);
    
    LM's avatar
    LM committed
    }
    
    LM's avatar
    LM committed
    void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance)
    {
        QGCToolWidget* tool = new QGCToolWidget("", this);
        if (tool->loadSettings(fileName, true) || !singleinstance)
    
    LM's avatar
    LM committed
        {
            // Add widget to UI
            QDockWidget* dock = new QDockWidget(tool->getTitle(), this);
            connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
            dock->setWidget(tool);
            tool->setParent(dock);
    
            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);
        }
    
    LM's avatar
    LM committed
        else
        {
            return;
    
    LM's avatar
    LM committed
    void MainWindow::loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType)
    
        QString defaultsDir = qApp->applicationDirPath() + "/files/" + autopilotType.toLower() + "/" + systemType.toLower() + "/widgets/";
    
    LM's avatar
    LM committed
        QDir widgets(defaultsDir);
        QStringList files = widgets.entryList();
        if (files.count() == 0)
        {
            qDebug() << "No default custom widgets for system " << systemType << "autopilot" << autopilotType << " found";
            qDebug() << "Tried with path: " << defaultsDir;
    
    lm's avatar
    lm committed
            showStatusMessage(tr("Did not find any custom widgets in %1").arg(defaultsDir));
    
    LM's avatar
    LM committed
        // Load all custom widgets found in the AP folder
        for(int i = 0; i < files.count(); ++i)
    
    lm's avatar
    lm committed
        {
    
    LM's avatar
    LM committed
            QString file = files[i];
            if (file.endsWith(".qgw"))
            {
                // Will only be loaded if not already a custom widget with
                // the same name is present
    
                loadCustomWidget(defaultsDir+"/"+file, true);
    
    lm's avatar
    lm committed
                showStatusMessage(tr("Loaded custom widget %1").arg(defaultsDir+"/"+file));
    
    LM's avatar
    LM committed
            }
    
    lm's avatar
    lm committed
        }
    
    void MainWindow::loadSettings()
    {
        QSettings settings;
        settings.beginGroup("QGC_MAINWINDOW");
        autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool();
        currentStyle = (QGC_MAINWINDOW_STYLE)settings.value("CURRENT_STYLE", currentStyle).toInt();
    
        lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool();
    
        settings.endGroup();
    }
    
    void MainWindow::storeSettings()
    {
        QSettings settings;
        settings.beginGroup("QGC_MAINWINDOW");
        settings.setValue("AUTO_RECONNECT", autoReconnect);
        settings.setValue("CURRENT_STYLE", currentStyle);
        settings.endGroup();
    
    pixhawk's avatar
    pixhawk committed
        if (!aboutToCloseFlag && isVisible())
        {
            settings.setValue(getWindowGeometryKey(), saveGeometry());
            // Save the last current view in any case
            settings.setValue("CURRENT_VIEW", currentView);
            // Save the current window state, but only if a system is connected (else no real number of widgets would be present)
            if (UASManager::instance()->getUASList().length() > 0) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
            // Save the current view only if a UAS is connected
            if (UASManager::instance()->getUASList().length() > 0) settings.setValue("CURRENT_VIEW_WITH_UAS_CONNECTED", currentView);
            // Save the current power mode
        }
    
        settings.setValue("LOW_POWER_MODE", lowPowerMode);
    
    pixhawk's avatar
    pixhawk committed
        QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
        QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
        bool prevAddr = false;
    
    pixhawk's avatar
    pixhawk committed
        windowname.append(" (" + QHostInfo::localHostName() + ": ");
    
        for (int i = 0; i < hostAddresses.size(); i++)
        {
    
    pixhawk's avatar
    pixhawk committed
            // Exclude loopback IPv4 and all IPv6 addresses
    
            if (hostAddresses.at(i) != QHostAddress("127.0.0.1") && !hostAddresses.at(i).toString().contains(":"))
            {
    
    pixhawk's avatar
    pixhawk committed
                if(prevAddr) windowname.append("/");
                windowname.append(hostAddresses.at(i).toString());
                prevAddr = true;
            }
        }
    
    pixhawk's avatar
    pixhawk committed
        windowname.append(")");
    
    pixhawk's avatar
    pixhawk committed
        setWindowTitle(windowname);
    
    pixhawk's avatar
    pixhawk committed
        //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
    
    pixhawk's avatar
    pixhawk committed
    void MainWindow::startVideoCapture()
    
    pixhawk's avatar
    pixhawk committed
    {
        QString format = "bmp";
        QString initialPath = QDir::currentPath() + tr("/untitled.") + format;
    
        QString screenFileName = QFileDialog::getSaveFileName(this, tr("Save As"),
    
    lm's avatar
    lm committed
                                                              initialPath,
                                                              tr("%1 Files (*.%2);;All Files (*)")
                                                              .arg(format.toUpper())
                                                              .arg(format));
    
    pixhawk's avatar
    pixhawk committed
        delete videoTimer;
        videoTimer = new QTimer(this);
    
        //videoTimer->setInterval(40);
        //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
        //videoTimer->stop();
    
    pixhawk's avatar
    pixhawk committed
    void MainWindow::stopVideoCapture()
    
    pixhawk's avatar
    pixhawk committed
    {
        videoTimer->stop();
    
        // TODO Convert raw images to PNG
    }
    
    
    pixhawk's avatar
    pixhawk committed
    void MainWindow::saveScreen()
    
    pixhawk's avatar
    pixhawk committed
    {
        QPixmap window = QPixmap::grabWindow(this->winId());
        QString format = "bmp";
    
    
        if (!screenFileName.isEmpty())
        {
    
    pixhawk's avatar
    pixhawk committed
            window.save(screenFileName, format.toAscii());
        }
    }
    
    
    void MainWindow::enableAutoReconnect(bool enabled)
    
    pixhawk's avatar
    pixhawk committed
    {
    
    void MainWindow::loadNativeStyle()
    {
        loadStyle(QGC_MAINWINDOW_STYLE_NATIVE);
    }
    
    void MainWindow::loadIndoorStyle()
    {
        loadStyle(QGC_MAINWINDOW_STYLE_INDOOR);
    }
    
    void MainWindow::loadOutdoorStyle()
    {
        loadStyle(QGC_MAINWINDOW_STYLE_OUTDOOR);
    }
    
    void MainWindow::loadStyle(QGC_MAINWINDOW_STYLE style)
    {
    
        switch (style) {
        case QGC_MAINWINDOW_STYLE_NATIVE: {
            // Native mode means setting no style
            // so if we were already in native mode
            // take no action
            // Only if a style was set, remove it.
            if (style != currentStyle) {
                qApp->setStyleSheet("");
                showInfoMessage(tr("Please restart QGroundControl"), tr("Please restart QGroundControl to switch to fully native look and feel. Currently you have loaded Qt's plastique style."));
    
        case QGC_MAINWINDOW_STYLE_INDOOR:
            qApp->setStyle("plastique");
            styleFileName = ":/images/style-mission.css";
            reloadStylesheet();
            break;
        case QGC_MAINWINDOW_STYLE_OUTDOOR:
            qApp->setStyle("plastique");
            styleFileName = ":/images/style-outdoor.css";
            reloadStylesheet();
            break;
        }
        currentStyle = style;
    }
    
    
    void MainWindow::selectStylesheet()
    
    pixhawk's avatar
    pixhawk committed
    {
    
        // Let user select style sheet
    
        styleFileName = QFileDialog::getOpenFileName(this, tr("Specify stylesheet"), styleFileName, tr("CSS Stylesheet (*.css);;"));
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!styleFileName.endsWith(".css"))
        {
    
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Information);
            msgBox.setText(tr("QGroundControl did lot load a new style"));
            msgBox.setInformativeText(tr("No suitable .css file selected. Please select a valid .css file."));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
            return;
        }
    
    
    pixhawk's avatar
    pixhawk committed
        // Load style sheet
    
        reloadStylesheet();
    }
    
    void MainWindow::reloadStylesheet()
    {
        // Load style sheet
        QFile* styleSheet = new QFile(styleFileName);
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (!styleSheet->exists())
        {
    
            styleSheet = new QFile(":/images/style-mission.css");
        }
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
        {
    
            QString style = QString(styleSheet->readAll());
            style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
    
    pixhawk's avatar
    pixhawk committed
            qApp->setStyleSheet(style);
    
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Information);
            msgBox.setText(tr("QGroundControl did lot load a new style"));
    
            msgBox.setInformativeText(tr("Stylesheet file %1 was not readable").arg(styleFileName));
    
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
    
    pixhawk's avatar
    pixhawk committed
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    /**
     * The status message will be overwritten if a new message is posted to this function
     *
     * @param status message text
     * @param timeout how long the status should be displayed
     */
    
    pixhawk's avatar
    pixhawk committed
    void MainWindow::showStatusMessage(const QString& status, int timeout)
    
    pixhawk's avatar
    pixhawk committed
    {
    
    lm's avatar
    lm committed
        statusBar()->showMessage(status, timeout);
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    /**
     * The status message will be overwritten if a new message is posted to this function.
     * it will be automatically hidden after 5 seconds.
     *
     * @param status message text
     */
    
    void MainWindow::showStatusMessage(const QString& status)
    
    pixhawk's avatar
    pixhawk committed
    {
    
    lm's avatar
    lm committed
        statusBar()->showMessage(status, 20000);
    
    }
    
    void MainWindow::showCriticalMessage(const QString& title, const QString& message)
    {
    
        QMessageBox msgBox(this);
    
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText(title);
        msgBox.setInformativeText(message);
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    lm's avatar
    lm committed
    void MainWindow::showInfoMessage(const QString& title, const QString& message)
    {
    
        QMessageBox msgBox(this);
    
    lm's avatar
    lm committed
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(title);
        msgBox.setInformativeText(message);
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
    
    
    pixhawk's avatar
    pixhawk committed
    /**
    * @brief Create all actions associated to the main window
    *
    **/
    
    pixhawk's avatar
    pixhawk committed
    {
    
        // Bind together the perspective actions
        QActionGroup* perspectives = new QActionGroup(ui.menuPerspectives);
        perspectives->addAction(ui.actionEngineersView);
        perspectives->addAction(ui.actionMavlinkView);
        perspectives->addAction(ui.actionPilotsView);
        perspectives->addAction(ui.actionOperatorsView);
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        perspectives->addAction(ui.actionFirmwareUpdateView);
    
        perspectives->addAction(ui.actionUnconnectedView);
        perspectives->setExclusive(true);
    
        // Mark the right one as selected
        if (currentView == VIEW_ENGINEER) ui.actionEngineersView->setChecked(true);
        if (currentView == VIEW_MAVLINK) ui.actionMavlinkView->setChecked(true);
        if (currentView == VIEW_PILOT) ui.actionPilotsView->setChecked(true);
        if (currentView == VIEW_OPERATOR) ui.actionOperatorsView->setChecked(true);
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        if (currentView == VIEW_FIRMWAREUPDATE) ui.actionFirmwareUpdateView->setChecked(true);
    
        if (currentView == VIEW_UNCONNECTED) ui.actionUnconnectedView->setChecked(true);
    
        // The UAS actions are not enabled without connection to system
        ui.actionLiftoff->setEnabled(false);
        ui.actionLand->setEnabled(false);
        ui.actionEmergency_Kill->setEnabled(false);
        ui.actionEmergency_Land->setEnabled(false);
        ui.actionShutdownMAV->setEnabled(false);
    
    
    pixhawk's avatar
    pixhawk committed
        // Connect actions from ui
        connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink()));
    
        // Connect internal actions
        connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
    
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
    
    pixhawk's avatar
    pixhawk committed
    
    
    pixhawk's avatar
    pixhawk committed
        connect(ui.actionLiftoff, SIGNAL(triggered()), UASManager::instance(), SLOT(launchActiveUAS()));
        connect(ui.actionLand, SIGNAL(triggered()), UASManager::instance(), SLOT(returnActiveUAS()));