Skip to content
Snippets Groups Projects
MainWindow.cc 81.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • void MainWindow::closeEvent(QCloseEvent *event)
    {
        if (isVisible()) storeViewState();
        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(engineeringView,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);
            }
    
    
    void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance)
    {
        QGCToolWidget* tool = new QGCToolWidget("", this);
        if (tool->loadSettings(fileName, true) || !singleinstance)
        {
    
            qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName();
            QSettings settings;
            settings.beginGroup("QGC_MAINWINDOW");
            //settings.setValue(QString("TOOL_PARENT_") + "UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size()),currentView);
    
            int view = settings.value(QString("TOOL_PARENT_") + tool->objectName(),-1).toInt();
            switch (view)
            {
            case VIEW_ENGINEER:
    
                createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
    
                createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
    
                createDockWidget(simView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
    
                createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea);
    
            {
                //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);
            }
    
            /*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);
    
        }
        else
        {
            return;
        }
    }
    
    void MainWindow::loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType)
    {
        QString defaultsDir = qApp->applicationDirPath() + "/files/" + autopilotType.toLower() + "/widgets/";
        QString platformDir = qApp->applicationDirPath() + "/files/" + autopilotType.toLower() + "/" + systemType.toLower() + "/widgets/";
    
        QDir widgets(defaultsDir);
        QStringList files = widgets.entryList();
        QDir platformWidgets(platformDir);
        files.append(platformWidgets.entryList());
    
        if (files.count() == 0)
        {
            qDebug() << "No default custom widgets for system " << systemType << "autopilot" << autopilotType << " found";
            qDebug() << "Tried with path: " << defaultsDir;
            showStatusMessage(tr("Did not find any custom widgets in %1").arg(defaultsDir));
        }
    
        // Load all custom widgets found in the AP folder
        for(int i = 0; i < files.count(); ++i)
        {
            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);
                showStatusMessage(tr("Loaded custom widget %1").arg(defaultsDir+"/"+file));
            }
        }
    }
    
    void MainWindow::loadSettings()
    {
        QSettings settings;
    
        settings.sync();
        customMode = static_cast<enum MainWindow::CUSTOM_MODE>(settings.value("QGC_CUSTOM_MODE", (unsigned int)MainWindow::CUSTOM_MODE_NONE).toInt());
    
        settings.beginGroup("QGC_MAINWINDOW");
        autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool();
        currentStyle = (QGC_MAINWINDOW_STYLE)settings.value("CURRENT_STYLE", currentStyle).toInt();
    
        darkStyleFileName = settings.value("DARK_STYLE_FILENAME", darkStyleFileName).toString();
        lightStyleFileName = settings.value("LIGHT_STYLE_FILENAME", lightStyleFileName).toString();
    
        lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool();
    
        dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled).toBool();
    
        enableDockWidgetTitleBars(dockWidgetTitleBarEnabled);
    
    }
    
    void MainWindow::storeSettings()
    {
        QSettings settings;
        settings.beginGroup("QGC_MAINWINDOW");
        settings.setValue("AUTO_RECONNECT", autoReconnect);
        settings.setValue("CURRENT_STYLE", currentStyle);
    
        settings.setValue("DARK_STYLE_FILENAME", darkStyleFileName);
        settings.setValue("LIGHT_STYLE_FILENAME", lightStyleFileName);
    
        settings.endGroup();
        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);
    
        settings.setValue("QGC_CUSTOM_MODE", (int)customMode);
    
        settings.sync();
    }
    
    void MainWindow::configureWindowName()
    {
        QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
        QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
        bool prevAddr = false;
    
        windowname.append(" (" + QHostInfo::localHostName() + ": ");
    
        for (int i = 0; i < hostAddresses.size(); i++)
        {
            // Exclude loopback IPv4 and all IPv6 addresses
            if (hostAddresses.at(i) != QHostAddress("127.0.0.1") && !hostAddresses.at(i).toString().contains(":"))
            {
                if(prevAddr) windowname.append("/");
                windowname.append(hostAddresses.at(i).toString());
                prevAddr = true;
            }
        }
    
        windowname.append(")");
    
        setWindowTitle(windowname);
    
    #ifndef Q_WS_MAC
        //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
    #endif
    }
    
    void MainWindow::startVideoCapture()
    {
        QString format = "bmp";
        QString initialPath = QDir::currentPath() + tr("/untitled.") + format;
    
        QString screenFileName = QFileDialog::getSaveFileName(this, tr("Save As"),
                                                              initialPath,
                                                              tr("%1 Files (*.%2);;All Files (*)")
                                                              .arg(format.toUpper())
                                                              .arg(format));
        delete videoTimer;
        videoTimer = new QTimer(this);
        //videoTimer->setInterval(40);
        //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
        //videoTimer->stop();
    }
    
    void MainWindow::stopVideoCapture()
    {
        videoTimer->stop();
    
        // TODO Convert raw images to PNG
    }
    
    void MainWindow::saveScreen()
    {
        QPixmap window = QPixmap::grabWindow(this->winId());
        QString format = "bmp";
    
        if (!screenFileName.isEmpty())
        {
            window.save(screenFileName, format.toAscii());
        }
    }
    
    void MainWindow::enableDockWidgetTitleBars(bool enabled)
    {
    
        dockWidgetTitleBarEnabled = enabled;
        QSettings settings;
        settings.beginGroup("QGC_MAINWINDOW");
        settings.setValue("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled);
        settings.endGroup();
        settings.sync();
    
    
        for (int i = 0; i < dockWidgets.size(); i++)
    
            setDockWidgetTitleBar(dockWidgets[i]);
    
    
    void MainWindow::enableAutoReconnect(bool enabled)
    {
        autoReconnect = enabled;
    }
    
    
    bool MainWindow::loadStyle(QGC_MAINWINDOW_STYLE style, QString cssFile)
    
        // Store the new style classification.
        currentStyle = style;
    
        // Load the new stylesheet.
    
        if (styleSheet.open(QIODevice::ReadOnly | QIODevice::Text))
    
            // Signal to the user that the app will pause to apply a new stylesheet
            qApp->setOverrideCursor(Qt::WaitCursor);
    
    
            qApp->setStyleSheet(styleSheet.readAll());
    
            // And save the new stylesheet path.
    
            if (currentStyle == QGC_MAINWINDOW_STYLE_LIGHT)
            {
                lightStyleFileName = cssFile;
            }
            else
            {
                darkStyleFileName = cssFile;
            }
    
    
            // And trigger any changes to other UI elements that are watching for
            // theme changes.
            emit styleChanged(style);
    
            emit styleChanged();
    
            // Finally restore the cursor before returning.
    
            qApp->restoreOverrideCursor();
            return true;
    
    
        // Otherwise alert return a failure code.
    
    }
    
    /**
     * 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
     */
    void MainWindow::showStatusMessage(const QString& status, int timeout)
    {
        statusBar()->showMessage(status, timeout);
    }
    
    /**
     * 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)
    {
        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();
    }
    
    void MainWindow::showInfoMessage(const QString& title, const QString& message)
    {
        QMessageBox msgBox(this);
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(title);
        msgBox.setInformativeText(message);
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
    
    /**
    * @brief Create all actions associated to the main window
    *
    **/
    void MainWindow::connectCommonActions()
    {
        // Bind together the perspective actions
        QActionGroup* perspectives = new QActionGroup(ui.menuPerspectives);
        perspectives->addAction(ui.actionEngineersView);
        perspectives->addAction(ui.actionMavlinkView);
    
        perspectives->addAction(ui.actionFlightView);
    
        perspectives->addAction(ui.actionSimulation_View);
    
        perspectives->addAction(ui.actionMissionView);
    
        //perspectives->addAction(ui.actionConfiguration_2);
        perspectives->addAction(ui.actionHardwareConfig);
        perspectives->addAction(ui.actionSoftwareConfig);
    
        perspectives->addAction(ui.actionFirmwareUpdateView);
    
        perspectives->addAction(ui.actionTerminalView);
    
        perspectives->addAction(ui.actionUnconnectedView);
        perspectives->setExclusive(true);
    
        // Mark the right one as selected
    
        if (currentView == VIEW_ENGINEER)
        {
            ui.actionEngineersView->setChecked(true);
            ui.actionEngineersView->activate(QAction::Trigger);
        }
        if (currentView == VIEW_MAVLINK)
        {
            ui.actionMavlinkView->setChecked(true);
            ui.actionMavlinkView->activate(QAction::Trigger);
        }
        if (currentView == VIEW_FLIGHT)
        {
            ui.actionFlightView->setChecked(true);
            ui.actionFlightView->activate(QAction::Trigger);
        }
        if (currentView == VIEW_SIMULATION)
        {
            ui.actionSimulation_View->setChecked(true);
            ui.actionSimulation_View->activate(QAction::Trigger);
        }
        if (currentView == VIEW_MISSION)
        {
            ui.actionMissionView->setChecked(true);
            ui.actionMissionView->activate(QAction::Trigger);
        }
    
            ui.actionHardwareConfig->setChecked(true);
            ui.actionHardwareConfig->activate(QAction::Trigger);
        }
        if (currentView == VIEW_SOFTWARE_CONFIG)
    
            ui.actionSoftwareConfig->setChecked(true);
            ui.actionSoftwareConfig->activate(QAction::Trigger);
    
        }
        if (currentView == VIEW_FIRMWAREUPDATE)
        {
            ui.actionFirmwareUpdateView->setChecked(true);
            ui.actionFirmwareUpdateView->activate(QAction::Trigger);
        }
    
        if (currentView == VIEW_TERMINAL)
        {
            ui.actionTerminalView->setChecked(true);
            ui.actionTerminalView->activate(QAction::Trigger);
        }
    
        if (currentView == VIEW_UNCONNECTED)
        {
            ui.actionUnconnectedView->setChecked(true);
            ui.actionUnconnectedView->activate(QAction::Trigger);
        }
    
    
        // 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);
    
        // Connect actions from ui
        connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink()));
    
        ui.actionAdvanced_Mode->setChecked(isAdvancedMode);
    
        connect(ui.actionAdvanced_Mode,SIGNAL(triggered()),this,SLOT(setAdvancedMode()));
    
    
        // Connect internal actions
        connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
    
        // Unmanned System controls
        connect(ui.actionLiftoff, SIGNAL(triggered()), UASManager::instance(), SLOT(launchActiveUAS()));
        connect(ui.actionLand, SIGNAL(triggered()), UASManager::instance(), SLOT(returnActiveUAS()));
        connect(ui.actionEmergency_Land, SIGNAL(triggered()), UASManager::instance(), SLOT(stopActiveUAS()));
        connect(ui.actionEmergency_Kill, SIGNAL(triggered()), UASManager::instance(), SLOT(killActiveUAS()));
        connect(ui.actionShutdownMAV, SIGNAL(triggered()), UASManager::instance(), SLOT(shutdownActiveUAS()));
        connect(ui.actionConfiguration, SIGNAL(triggered()), UASManager::instance(), SLOT(configureActiveUAS()));
    
        // Views actions
    
        connect(ui.actionFlightView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
    
        connect(ui.actionSimulation_View, SIGNAL(triggered()), this, SLOT(loadSimulationView()));
    
        connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
    
        connect(ui.actionMissionView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
    
        connect(ui.actionUnconnectedView, SIGNAL(triggered()), this, SLOT(loadUnconnectedView()));
    
        connect(ui.actionHardwareConfig,SIGNAL(triggered()),this,SLOT(loadHardwareConfigView()));
    
        if (getCustomMode() == CUSTOM_MODE_APM) {
    
            connect(ui.actionSoftwareConfig,SIGNAL(triggered()),this,SLOT(loadSoftwareConfigView()));
    
    Lorenz Meier's avatar
    Lorenz Meier committed
            connect(ui.actionTerminalView,SIGNAL(triggered()),this,SLOT(loadTerminalView()));
    
    
        connect(ui.actionFirmwareUpdateView, SIGNAL(triggered()), this, SLOT(loadFirmwareUpdateView()));
        connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
    
        // Help Actions
        connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
        connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
        connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
    
        // Custom widget actions
        connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget()));
        connect(ui.actionLoadCustomWidgetFile, SIGNAL(triggered()), this, SLOT(loadCustomWidget()));
    
        // Audio output
        ui.actionMuteAudioOutput->setChecked(GAudioOutput::instance()->isMuted());
        connect(GAudioOutput::instance(), SIGNAL(mutedChanged(bool)), ui.actionMuteAudioOutput, SLOT(setChecked(bool)));
        connect(ui.actionMuteAudioOutput, SIGNAL(triggered(bool)), GAudioOutput::instance(), SLOT(mute(bool)));
    
        // User interaction
        // NOTE: Joystick thread is not started and
        // configuration widget is not instantiated
        // unless it is actually used
        // so no ressources spend on this.
        ui.actionJoystickSettings->setVisible(true);
    
        // Configuration
        // Joystick
        connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
        // Application Settings
        connect(ui.actionSettings, SIGNAL(triggered()), this, SLOT(showSettings()));
    
    
        connect(ui.actionSimulate, SIGNAL(triggered(bool)), this, SLOT(simulateLink(bool)));
    
    }
    
    void MainWindow::showHelp()
    {
        if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/start")))
        {
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Critical);
            msgBox.setText("Could not open help in browser");
            msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/user_guide in a browser.");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
    }
    
    void MainWindow::showCredits()
    {
        if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits")))
        {
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Critical);
            msgBox.setText("Could not open credits in browser");
            msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/credits in a browser.");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
    }
    
    void MainWindow::showRoadMap()
    {
        if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/dev/roadmap")))
        {
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Critical);
            msgBox.setText("Could not open roadmap in browser");
            msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/roadmap in a browser.");
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.setDefaultButton(QMessageBox::Ok);
            msgBox.exec();
        }
    }
    
    void MainWindow::configure()
    {
        if (!joystickWidget)
        {
            if (!joystick->isRunning())
            {
                joystick->start();
            }
    
            joystickWidget = new JoystickWidget(joystick, this);
    
        }
        joystickWidget->show();
    }
    
    void MainWindow::showSettings()
    {
        QGCSettingsWidget* settings = new QGCSettingsWidget(this);
        settings->show();
    }
    
    
    LinkInterface* MainWindow::addLink()
    
    {
        SerialLink* link = new SerialLink();
        // TODO This should be only done in the dialog itself
    
        LinkManager::instance()->add(link);
        LinkManager::instance()->addProtocol(link, mavlink);
    
        // Go fishing for this link's configuration window
        QList<QAction*> actions = ui.menuNetwork->actions();
    
    
        const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link));
        const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId());
    
    
        foreach (QAction* act, actions)
        {
            if (act->data().toInt() == linkID)
            { // LinkManager::instance()->getLinks().indexOf(link)
                act->trigger();
                break;
            }
        }
    
    
    bool MainWindow::configLink(LinkInterface *link)
    {
        // Go searching for this link's configuration window
        QList<QAction*> actions = ui.menuNetwork->actions();
    
        bool found(false);
    
        const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link));
        const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId());
    
        foreach (QAction* action, actions)
        {
            if (action->data().toInt() == linkID)
            { // LinkManager::instance()->getLinks().indexOf(link)
                found = true;
                action->trigger(); // Show the Link Config Dialog
            }
        }
    
        return found;
    }
    
    
    void MainWindow::addLink(LinkInterface *link)
    {
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    
        qDebug() << "ADD LINK CALLED FROM SOMEWHERE";
    
    
        // IMPORTANT! KEEP THESE TWO LINES
        // THEY MAKE SURE THE LINK IS PROPERLY REGISTERED
        // BEFORE LINKING THE UI AGAINST IT
        // Register (does nothing if already registered)
        LinkManager::instance()->add(link);
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    
        if (mavlink) {
            qDebug() << "MAVLINK OK";
        } else {
            qDebug() << "MAVLINK FAIL";
        }
    
    
        LinkManager::instance()->addProtocol(link, mavlink);
    
        // Go fishing for this link's configuration window
        QList<QAction*> actions = ui.menuNetwork->actions();
    
        bool found(false);
    
    
        const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link));
        const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId());
    
    
        foreach (QAction* act, actions)
        {
            if (act->data().toInt() == linkID)
            { // LinkManager::instance()->getLinks().indexOf(link)
                found = true;
            }
        }
    
        if (!found)
    
            CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, NULL);
    
            commsWidgetList.append(commWidget);
            connect(commWidget,SIGNAL(destroyed(QObject*)),this,SLOT(commsWidgetDestroyed(QObject*)));
    
            QAction* action = commWidget->getAction();
            ui.menuNetwork->addAction(action);
    
            // Error handling
            connect(link, SIGNAL(communicationError(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
        }
    }
    
    void MainWindow::simulateLink(bool simulate) {
        if (!simulationLink)
            simulationLink = new MAVLinkSimulationLink(":/demo-log.txt");
        simulationLink->connectLink(simulate);
    }
    
    
    //void MainWindow::configLink(LinkInterface *link)
    //{
    
    //}
    
    void MainWindow::commsWidgetDestroyed(QObject *obj)
    {
        if (commsWidgetList.contains(obj))
        {
            commsWidgetList.removeOne(obj);
        }
    }
    
    
    void MainWindow::setActiveUAS(UASInterface* uas)
    {
    
        Q_UNUSED(uas);
    
        // Enable and rename menu
    
        //    ui.menuUnmanned_System->setTitle(uas->getUASName());
        //    if (!ui.menuUnmanned_System->isEnabled()) ui.menuUnmanned_System->setEnabled(true);
    
        if (settings.contains(getWindowStateKey()))
        {
            SubMainWindow *win = qobject_cast<SubMainWindow*>(centerStack->currentWidget());
            //settings.setValue(getWindowStateKey(), win->saveState(QGC::applicationVersion()))
            win->restoreState(settings.value(getWindowStateKey()).toByteArray(), QGC::applicationVersion());
        }
    
    
    }
    
    void MainWindow::UASSpecsChanged(int uas)
    {
        UASInterface* activeUAS = UASManager::instance()->getActiveUAS();
        if (activeUAS)
        {
            if (activeUAS->getUASID() == uas)
            {
    
                //            ui.menuUnmanned_System->setTitle(activeUAS->getUASName());
    
            //        ui.menuUnmanned_System->setTitle(tr("No System"));
            //        ui.menuUnmanned_System->setEnabled(false);
    
        }
    }
    
    void MainWindow::UASCreated(UASInterface* uas)
    {
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
        // Check if this is the 2nd system and we need a switch menu
        if (UASManager::instance()->getUASList().count() > 1)
    
            //        ui.menuConnected_Systems->setEnabled(true);
    
            // Connect the UAS to the full user interface
    
            // The pilot, operator and engineer views were not available on startup, enable them now
    
            ui.actionFlightView->setEnabled(true);
            ui.actionMissionView->setEnabled(true);
    
            ui.actionEngineersView->setEnabled(true);
            // The UAS actions are not enabled without connection to system
            ui.actionLiftoff->setEnabled(true);
            ui.actionLand->setEnabled(true);
            ui.actionEmergency_Kill->setEnabled(true);
            ui.actionEmergency_Land->setEnabled(true);
            ui.actionShutdownMAV->setEnabled(true);
    
            QIcon icon;
            // Set matching icon
            switch (uas->getSystemType())
    
            case MAV_TYPE_GENERIC:
                icon = QIcon(":files/images/mavs/generic.svg");
                break;
            case MAV_TYPE_FIXED_WING:
                icon = QIcon(":files/images/mavs/fixed-wing.svg");
                break;
            case MAV_TYPE_QUADROTOR:
                icon = QIcon(":files/images/mavs/quadrotor.svg");
                break;
            case MAV_TYPE_COAXIAL:
                icon = QIcon(":files/images/mavs/coaxial.svg");
                break;
            case MAV_TYPE_HELICOPTER:
                icon = QIcon(":files/images/mavs/helicopter.svg");
                break;
            case MAV_TYPE_ANTENNA_TRACKER:
                icon = QIcon(":files/images/mavs/antenna-tracker.svg");
                break;
            case MAV_TYPE_GCS:
                icon = QIcon(":files/images/mavs/groundstation.svg");
                break;
            case MAV_TYPE_AIRSHIP:
                icon = QIcon(":files/images/mavs/airship.svg");
                break;
            case MAV_TYPE_FREE_BALLOON:
                icon = QIcon(":files/images/mavs/free-balloon.svg");
                break;
            case MAV_TYPE_ROCKET:
                icon = QIcon(":files/images/mavs/rocket.svg");
                break;
            case MAV_TYPE_GROUND_ROVER:
                icon = QIcon(":files/images/mavs/ground-rover.svg");
                break;
            case MAV_TYPE_SURFACE_BOAT:
                icon = QIcon(":files/images/mavs/surface-boat.svg");
                break;
            case MAV_TYPE_SUBMARINE:
                icon = QIcon(":files/images/mavs/submarine.svg");
                break;
            case MAV_TYPE_HEXAROTOR:
                icon = QIcon(":files/images/mavs/hexarotor.svg");
                break;
            case MAV_TYPE_OCTOROTOR:
                icon = QIcon(":files/images/mavs/octorotor.svg");
                break;
            case MAV_TYPE_TRICOPTER:
                icon = QIcon(":files/images/mavs/tricopter.svg");
                break;
            case MAV_TYPE_FLAPPING_WING:
                icon = QIcon(":files/images/mavs/flapping-wing.svg");
                break;
            case MAV_TYPE_KITE:
                icon = QIcon(":files/images/mavs/kite.svg");
                break;
            default:
                icon = QIcon(":files/images/mavs/unknown.svg");
                break;
            }
    
    
        // XXX The multi-UAS selection menu has been disabled for now,
        // its redundant with right-clicking the UAS in the list.
        // this code piece might be removed later if this is the final
        // conclusion (May 2013)
        //        QAction* uasAction = new QAction(icon, tr("Select %1 for control").arg(uas->getUASName()), ui.menuConnected_Systems);
        //        connect(uasAction, SIGNAL(triggered()), uas, SLOT(setSelected()));
        //        ui.menuConnected_Systems->addAction(uasAction);
    
        connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int)));
    
        if (!linechartWidget)
        {
            linechartWidget = new Linecharts(this);
            //linechartWidget->hide();
    
        linechartWidget->addSource(mavlinkDecoder);
        if (engineeringView->centralWidget() != linechartWidget)
        {
            engineeringView->setCentralWidget(linechartWidget);
            linechartWidget->show();
        }
    
        // Load default custom widgets for this autopilot type
        loadCustomWidgetsFromDefaults(uas->getSystemTypeName(), uas->getAutopilotTypeName());
    
        if (uas->getAutopilotType() == MAV_AUTOPILOT_PIXHAWK)
        {
            // Dock widgets
            if (!detectionDockWidget)
    
                detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
                detectionDockWidget->setWidget( new ObjectDetectionView("files/images/patterns", this) );
                detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
                //addTool(detectionDockWidget, tr("Object Recognition"), Qt::RightDockWidgetArea);
            }
    
            if (!watchdogControlDockWidget)
            {
                watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
                watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
                watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
                //addTool(watchdogControlDockWidget, tr("Process Control"), Qt::BottomDockWidgetArea);
    
        // Change the view only if this is the first UAS
    
        // If this is the first connected UAS, it is both created as well as
        // the currently active UAS
        if (UASManager::instance()->getUASList().size() == 1)
        {
            // Load last view if setting is present
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
    
                /*int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
    
                    switch (view)
                    {
                    case VIEW_ENGINEER:
                        loadEngineerView();
                        break;
                    case VIEW_MAVLINK:
                        loadMAVLinkView();
                        break;
                    case VIEW_FIRMWAREUPDATE:
                        loadFirmwareUpdateView();
                        break;
    
                    case VIEW_SIMULATION:
                        loadSimulationView();
                        break;
    
                    case VIEW_UNCONNECTED:
                        loadUnconnectedView();
                        break;
    
                    default:
                        loadOperatorView();
                        break;
    
        //    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
        //    if (!ui.menuUnmanned_System->isEnabled()) ui.menuUnmanned_System->setEnabled(true);
    
    
        // Reload view state in case new widgets were added
        loadViewState();
    }
    
    void MainWindow::UASDeleted(UASInterface* uas)
    {
    
        Q_UNUSED(uas);
    
        if (UASManager::instance()->getUASList().count() == 0)
        {
            // Last system deleted
    
            //        ui.menuUnmanned_System->setTitle(tr("No System"));
            //        ui.menuUnmanned_System->setEnabled(false);
    
        //    QAction* act;
        //    QList<QAction*> actions = ui.menuConnected_Systems->actions();
    
        //    foreach (act, actions)
        //    {
        //        if (act->text().contains(uas->getUASName()))
        //            ui.menuConnected_Systems->removeAction(act);
        //    }
    
    }
    
    /**
     * Stores the current view state
     */
    void MainWindow::storeViewState()
    {
        if (!aboutToCloseFlag)
        {
            // Save current state
    
            SubMainWindow *win = qobject_cast<SubMainWindow*>(centerStack->currentWidget());
            QList<QDockWidget*> widgets = win->findChildren<QDockWidget*>();
            QString widgetnames = "";
            for (int i=0;i<widgets.size();i++)
            {
                widgetnames += widgets[i]->objectName() + ",";
            }
            widgetnames = widgetnames.mid(0,widgetnames.length()-1);
    
            settings.setValue(getWindowStateKey() + "WIDGETS",widgetnames);
            settings.setValue(getWindowStateKey(), win->saveState(QGC::applicationVersion()));
    
            settings.setValue(getWindowStateKey()+"CENTER_WIDGET", centerStack->currentIndex());
            // Although we want save the state of the window, we do not want to change the top-leve state (minimized, maximized, etc)
            // therefore this state is stored here and restored after applying the rest of the settings in the new
            // perspective.
            windowStateVal = this->windowState();
            settings.setValue(getWindowGeometryKey(), saveGeometry());
        }
    }
    
    void MainWindow::loadViewState()
    {
        // Restore center stack state
        int index = settings.value(getWindowStateKey()+"CENTER_WIDGET", -1).toInt();
        // The offline plot view is usually the consequence of a logging run, always show the realtime view first
    
        if (centerStack->indexOf(engineeringView) == index)
    
        {
            // Rewrite to realtime plot
    
            //index = centerStack->indexOf(linechartWidget);