Skip to content
Snippets Groups Projects
MainWindowInner.qml 21.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • /****************************************************************************
     *
     *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
     *
     * QGroundControl is licensed according to the terms in the file
     * COPYING.md in the root of the source code directory.
     *
     ****************************************************************************/
    
    import QtQuick          2.3
    import QtQuick.Controls 1.2
    
    import QtQuick.Dialogs  1.2
    
    import QtPositioning    5.3
    
    import QGroundControl                       1.0
    import QGroundControl.Palette               1.0
    import QGroundControl.Controls              1.0
    import QGroundControl.FlightDisplay         1.0
    import QGroundControl.ScreenTools           1.0
    import QGroundControl.MultiVehicleManager   1.0
    
    /// Inner common QML for mainWindow
    
        id: mainWindow
    
    Don Gagne's avatar
    Don Gagne committed
    
    
        QGCPalette { id: qgcPal; colorGroupEnabled: true }
    
        property var    currentPopUp:       null
        property real   currentCenterX:     0
    
        property var    activeVehicle:      QGroundControl.multiVehicleManager.activeVehicle
    
        property string formatedMessage:    activeVehicle ? activeVehicle.formatedMessage : ""
    
    Don Gagne's avatar
    Don Gagne committed
        property var _viewList: [ settingsViewLoader, setupViewLoader, planViewLoader, flightView, analyzeViewLoader ]
    
        readonly property string _settingsViewSource:   "AppSettings.qml"
        readonly property string _setupViewSource:      "SetupView.qml"
    
        readonly property string _planViewSource:       "PlanView.qml"
    
    Don Gagne's avatar
    Don Gagne committed
        readonly property string _analyzeViewSource:    "AnalyzeView.qml"
    
    
        onHeightChanged: {
    
            //-- We only deal with the available height if within the Fly or Plan view
            if(!setupViewLoader.visible) {
                ScreenTools.availableHeight = parent.height - toolBar.height
            }
    
        function disableToolbar() {
            toolbarBlocker.enabled = true
        }
    
        function enableToolbar() {
            toolbarBlocker.enabled = false
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        function hideAllViews() {
            for (var i=0; i<_viewList.length; i++) {
                _viewList[i].visible = false
    
            planToolBar.visible = false
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
    Don Gagne's avatar
    Don Gagne committed
        function showSettingsView() {
    
            rootLoader.sourceComponent = null
    
    Don Gagne's avatar
    Don Gagne committed
            if(currentPopUp) {
                currentPopUp.close()
    
    Don Gagne's avatar
    Don Gagne committed
            //-- In settings view, the full height is available. Set to 0 so it is ignored.
            ScreenTools.availableHeight = 0
    
            hideAllViews()
    
    Don Gagne's avatar
    Don Gagne committed
            if (settingsViewLoader.source != _settingsViewSource) {
                settingsViewLoader.source  = _settingsViewSource
    
    Don Gagne's avatar
    Don Gagne committed
            }
    
    Don Gagne's avatar
    Don Gagne committed
            settingsViewLoader.visible  = true
            toolBar.checkSettingsButton()
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
    Don Gagne's avatar
    Don Gagne committed
        function showSetupView() {
    
            rootLoader.sourceComponent = null
    
    Don Gagne's avatar
    Don Gagne committed
            if(currentPopUp) {
                currentPopUp.close()
            }
    
            //-- In setup view, the full height is available. Set to 0 so it is ignored.
            ScreenTools.availableHeight = 0
    
            hideAllViews()
    
    Don Gagne's avatar
    Don Gagne committed
            if (setupViewLoader.source  != _setupViewSource) {
                setupViewLoader.source  = _setupViewSource
    
    Don Gagne's avatar
    Don Gagne committed
            setupViewLoader.visible  = true
    
    Don Gagne's avatar
    Don Gagne committed
            toolBar.checkSetupButton()
        }
    
    Don Gagne's avatar
    Don Gagne committed
        function showPlanView() {
    
            rootLoader.sourceComponent = null
    
            if(currentPopUp) {
                currentPopUp.close()
            }
    
    Don Gagne's avatar
    Don Gagne committed
            if (planViewLoader.source   != _planViewSource) {
                planViewLoader.source   = _planViewSource
    
    Don Gagne's avatar
    Don Gagne committed
            ScreenTools.availableHeight = parent.height - toolBar.height
            hideAllViews()
            planViewLoader.visible = true
    
            planToolBar.visible = true
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
    Don Gagne's avatar
    Don Gagne committed
        function showFlyView() {
    
            rootLoader.sourceComponent = null
    
    Don Gagne's avatar
    Don Gagne committed
            if(currentPopUp) {
                currentPopUp.close()
            }
            ScreenTools.availableHeight = parent.height - toolBar.height
            hideAllViews()
            flightView.visible = true
            toolBar.checkFlyButton()
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
    Don Gagne's avatar
    Don Gagne committed
        function showAnalyzeView() {
    
            rootLoader.sourceComponent = null
    
    Don Gagne's avatar
    Don Gagne committed
            if(currentPopUp) {
                currentPopUp.close()
            }
            ScreenTools.availableHeight = 0
            if (analyzeViewLoader.source  != _analyzeViewSource) {
                analyzeViewLoader.source  = _analyzeViewSource
            }
            hideAllViews()
            analyzeViewLoader.visible = true
            toolBar.checkAnalyzeButton()
    
        /// Start the process of closing QGroundControl. Prompts the user are needed.
        function attemptWindowClose() {
            unsavedMissionCloseDialog.check()
        }
    
        function finishCloseProcess() {
            QGroundControl.linkManager.shutdown()
            // The above shutdown causes a flurry of activity as the vehicle components are removed. This in turn
            // causes the Windows Version of Qt to crash if you allow the close event to be accepted. In order to prevent
            // the crash, we ignore the close event and setup a delayed timer to close the window after things settle down.
            delayedWindowCloseTimer.start()
        }
    
        MessageDialog {
            id:                 unsavedMissionCloseDialog
    
            title:              qsTr("%1 close").arg(QGroundControl.appName)
    
    Tomaz Canabrava's avatar
    Tomaz Canabrava committed
            text:               qsTr("You have a mission edit in progress which has not been saved/sent. If you close you will lose changes. Are you sure you want to close?")
    
            standardButtons:    StandardButton.Yes | StandardButton.No
            modality:           Qt.ApplicationModal
            visible:            false
    
            onYes: activeConnectionsCloseDialog.check()
    
            function check() {
                if (planViewLoader.item && planViewLoader.item.syncNeeded) {
                    unsavedMissionCloseDialog.open()
                } else {
                    activeConnectionsCloseDialog.check()
                }
            }
        }
    
        MessageDialog {
            id:                 activeConnectionsCloseDialog
    
            title:              qsTr("%1 close").arg(QGroundControl.appName)
    
    Tomaz Canabrava's avatar
    Tomaz Canabrava committed
            text:               qsTr("There are still active connections to vehicles. Do you want to disconnect these before closing?")
    
            standardButtons:    StandardButton.Yes | StandardButton.Cancel
            modality:           Qt.ApplicationModal
            visible:            false
            onYes:              finishCloseProcess()
    
            function check() {
                if (QGroundControl.multiVehicleManager.activeVehicle) {
                    activeConnectionsCloseDialog.open()
                } else {
                    finishCloseProcess()
                }
            }
        }
    
        Timer {
            id:         delayedWindowCloseTimer
            interval:   1500
            running:    false
            repeat:     false
    
            onTriggered: {
                mainWindow.reallyClose()
            }
        }
    
    
        property var messageQueue: []
    
    
    Don Gagne's avatar
    Don Gagne committed
        function showMessage(message) {
    
            if(criticalMmessageArea.visible) {
                messageQueue.push(message)
            } else {
                criticalMessageText.text = message
                criticalMmessageArea.visible = true
            }
        }
    
    
        function formatMessage(message) {
            message = message.replace(new RegExp("<#E>", "g"), "color: #f95e5e; font: " + (ScreenTools.defaultFontPointSize.toFixed(0) - 1) + "pt monospace;");
            message = message.replace(new RegExp("<#I>", "g"), "color: #f9b55e; font: " + (ScreenTools.defaultFontPointSize.toFixed(0) - 1) + "pt monospace;");
            message = message.replace(new RegExp("<#N>", "g"), "color: #ffffff; font: " + (ScreenTools.defaultFontPointSize.toFixed(0) - 1) + "pt monospace;");
            return message;
        }
    
    
        onFormatedMessageChanged: {
            if(messageArea.visible) {
    
                messageText.append(formatMessage(formatedMessage))
    
                //-- Hack to scroll down
                messageFlick.flick(0,-500)
            }
        }
    
        function showMessageArea() {
    
            rootLoader.sourceComponent = null
            var currentlyVisible = messageArea.visible
    
            if(!currentlyVisible) {
                if(QGroundControl.multiVehicleManager.activeVehicleAvailable) {
                    messageText.text = formatMessage(activeVehicle.formatedMessages)
                    //-- Hack to scroll to last message
                    for (var i = 0; i < activeVehicle.messageCount; i++)
                        messageFlick.flick(0,-5000)
                    activeVehicle.resetMessages()
                } else {
                    messageText.text = qsTr("No Messages")
                }
                currentPopUp = messageArea
                messageArea.visible = true
    
            rootLoader.sourceComponent = null
            var oldIndicator = indicatorDropdown.sourceComponent
    
            if(currentPopUp) {
                currentPopUp.close()
    
    Don Gagne's avatar
    Don Gagne committed
            }
    
            if(oldIndicator !== dropItem) {
                console.log(oldIndicator)
                console.log(dropItem)
                indicatorDropdown.centerX = centerX
                indicatorDropdown.sourceComponent = dropItem
                indicatorDropdown.visible = true
                currentPopUp = indicatorDropdown
            }
    
    dogmaphobic's avatar
    dogmaphobic committed
        //-- Main UI
    
    
    dogmaphobic's avatar
    dogmaphobic committed
        MainToolBar {
            id:                 toolBar
    
            height:             ScreenTools.toolbarHeight
    
    dogmaphobic's avatar
    dogmaphobic committed
            anchors.left:       parent.left
            anchors.right:      parent.right
            anchors.top:        parent.top
    
    Gus Grubba's avatar
    Gus Grubba committed
            opacity:            planToolBar.visible ? 0 : 1
    
    Gus Grubba's avatar
    Gus Grubba committed
            z:                  QGroundControl.zOrderTopMost
    
    Don Gagne's avatar
    Don Gagne committed
            Component.onCompleted:  ScreenTools.availableHeight = parent.height - toolBar.height
            onShowSettingsView:     mainWindow.showSettingsView()
            onShowSetupView:        mainWindow.showSetupView()
            onShowPlanView:         mainWindow.showPlanView()
            onShowFlyView:          mainWindow.showFlyView()
            onShowAnalyzeView:      mainWindow.showAnalyzeView()
    
            onArmVehicle:           flightView.guidedController.confirmAction(flightView.guidedController.actionArm)
    
            onDisarmVehicle: {
                if (flightView.guidedController.showEmergenyStop) {
                    flightView.guidedController.confirmAction(flightView.guidedController.actionEmergencyStop)
                } else {
                    flightView.guidedController.confirmAction(flightView.guidedController.actionDisarm)
                }
            }
    
            //-- Entire tool bar area disable on cammand
            MouseArea {
                id:             toolbarBlocker
                anchors.fill:   parent
                enabled:        false
                onWheel:        { wheel.accepted = true; }
                onPressed:      { mouse.accepted = true; }
                onReleased:     { mouse.accepted = true; }
            }
    
        PlanToolBar {
            id:                 planToolBar
            height:             ScreenTools.toolbarHeight
            anchors.left:       parent.left
            anchors.right:      parent.right
            anchors.top:        parent.top
            z:                  toolBar.z + 1
    
            onShowFlyView: {
                planToolBar.visible = false
                mainWindow.showFlyView()
            }
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
            id:                 settingsViewLoader
            anchors.left:       parent.left
            anchors.right:      parent.right
            anchors.top:        toolBar.bottom
            anchors.bottom:     parent.bottom
    
            visible:            false
    
    Don Gagne's avatar
    Don Gagne committed
            onVisibleChanged: {
                if (!visible) {
                    // Free up the memory for this when not shown. No need to persist.
                    source = ""
                }
    
        }
    
        Loader {
            id:                 setupViewLoader
    
            anchors.left:       parent.left
            anchors.right:      parent.right
            anchors.top:        toolBar.bottom
            anchors.bottom:     parent.bottom
    
            visible:            false
    
    
            property var planToolBar: planToolBar
    
    dogmaphobic's avatar
    dogmaphobic committed
    
    
        Loader {
    
    Don Gagne's avatar
    Don Gagne committed
            id:                 planViewLoader
            anchors.fill:       parent
            visible:            false
    
    
            property var toolbar: planToolBar
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
        FlightDisplayView {
            id:                 flightView
            anchors.fill:       parent
            visible:            true
        }
    
        Loader {
            id:                 analyzeViewLoader
    
            anchors.left:       parent.left
            anchors.right:      parent.right
            anchors.top:        toolBar.bottom
            anchors.bottom:     parent.bottom
            visible:            false
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
        //-------------------------------------------------------------------------
        //-- Dismiss Pop Up Messages
        MouseArea {
            visible:        currentPopUp != null
            enabled:        currentPopUp != null
            anchors.fill:   parent
            onClicked: {
                currentPopUp.close()
            }
        }
    
        //-------------------------------------------------------------------------
        //-- Indicator Drop Down Info
        Loader {
            id: indicatorDropdown
            visible: false
            property real centerX: 0
            function close() {
                sourceComponent = null
                mainWindow.currentPopUp = null
            }
        }
    
        //-------------------------------------------------------------------------
        //-- System Message Area
        Rectangle {
            id:                 messageArea
            function close() {
                currentPopUp = null
                messageText.text    = ""
                messageArea.visible = false
            }
            width:              mainWindow.width  * 0.5
            height:             mainWindow.height * 0.5
    
            color:              Qt.rgba(0,0,0,0.8)
    
            visible:            false
            radius:             ScreenTools.defaultFontPixelHeight * 0.5
    
            border.color:       "#808080"
    
    dogmaphobic's avatar
    dogmaphobic committed
            border.width:       2
    
            anchors.horizontalCenter:   parent.horizontalCenter
            anchors.top:                parent.top
    
    Don Gagne's avatar
    Don Gagne committed
            anchors.topMargin:          toolBar.height + ScreenTools.defaultFontPixelHeight
    
    dogmaphobic's avatar
    dogmaphobic committed
            MouseArea {
                // This MouseArea prevents the Map below it from getting Mouse events. Without this
                // things like mousewheel will scroll the Flickable and then scroll the map as well.
                anchors.fill:       parent
                preventStealing:    true
                onWheel:            wheel.accepted = true
            }
    
    Don Gagne's avatar
    Don Gagne committed
            QGCFlickable {
    
                id:                 messageFlick
                anchors.margins:    ScreenTools.defaultFontPixelHeight
                anchors.fill:       parent
                contentHeight:      messageText.height
                contentWidth:       messageText.width
                pixelAligned:       true
                clip:               true
                TextEdit {
    
                    id:             messageText
                    readOnly:       true
                    textFormat:     TextEdit.RichText
                    color:          "white"
    
    dogmaphobic's avatar
    dogmaphobic committed
                anchors.margins:    ScreenTools.defaultFontPixelHeight * 0.5
    
                anchors.top:        parent.top
                anchors.right:      parent.right
    
    dogmaphobic's avatar
    dogmaphobic committed
                width:              ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.5 : ScreenTools.defaultFontPixelHeight
    
                height:             width
    
                sourceSize.height:  width
    
                source:             "/res/XDelete.svg"
                fillMode:           Image.PreserveAspectFit
                mipmap:             true
                smooth:             true
                MouseArea {
    
    dogmaphobic's avatar
    dogmaphobic committed
                    anchors.fill:       parent
                    anchors.margins:    ScreenTools.isMobile ? -ScreenTools.defaultFontPixelHeight : 0
    
    dogmaphobic's avatar
    dogmaphobic committed
            //-- Clear Messages
            Image {
                anchors.bottom:     parent.bottom
                anchors.right:      parent.right
                anchors.margins:    ScreenTools.defaultFontPixelHeight * 0.5
    
    dogmaphobic's avatar
    dogmaphobic committed
                height:             ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.5 : ScreenTools.defaultFontPixelHeight
    
    dogmaphobic's avatar
    dogmaphobic committed
                width:              height
                sourceSize.height:   height
                source:             "/res/TrashDelete.svg"
                fillMode:           Image.PreserveAspectFit
                mipmap:             true
                smooth:             true
                MouseArea {
                    anchors.fill:   parent
                    onClicked: {
                        if(QGroundControl.multiVehicleManager.activeVehicleAvailable) {
                            activeVehicle.clearMessages();
                            messageArea.close()
                        }
                    }
                }
            }
    
        //-------------------------------------------------------------------------
        //-- Critical Message Area
        Rectangle {
    
    Don Gagne's avatar
    Don Gagne committed
            id:                         criticalMmessageArea
            width:                      mainWindow.width  * 0.55
            height:                     Math.min(criticalMessageText.height + _textMargins * 2, ScreenTools.defaultFontPixelHeight * 6)
    
    Gus Grubba's avatar
    Gus Grubba committed
            color:                      qgcPal.alertBackground
    
    Don Gagne's avatar
    Don Gagne committed
            visible:                    false
            radius:                     ScreenTools.defaultFontPixelHeight * 0.5
            anchors.horizontalCenter:   parent.horizontalCenter
            anchors.top:                parent.top
    
    Don Gagne's avatar
    Don Gagne committed
            anchors.topMargin:          toolBar.height + ScreenTools.defaultFontPixelHeight / 2
    
    Gus Grubba's avatar
    Gus Grubba committed
            border.color:               qgcPal.alertBorder
    
    Don Gagne's avatar
    Don Gagne committed
            border.width:               2
    
            readonly property real _textMargins: ScreenTools.defaultFontPixelHeight
    
    
            function close() {
                //-- Are there messages in the waiting queue?
                if(mainWindow.messageQueue.length) {
                    criticalMessageText.text = ""
                    //-- Show all messages in queue
                    for (var i = 0; i < mainWindow.messageQueue.length; i++) {
    
                        var text = mainWindow.messageQueue[i]
                        criticalMessageText.append(text)
    
                    }
                    //-- Clear it
                    mainWindow.messageQueue = []
                } else {
                    criticalMessageText.text = ""
                    criticalMmessageArea.visible = false
                }
            }
    
    
            MouseArea {
                // This MouseArea prevents the Map below it from getting Mouse events. Without this
                // things like mousewheel will scroll the Flickable and then scroll the map as well.
                anchors.fill:       parent
                preventStealing:    true
                onWheel:            wheel.accepted = true
            }
    
    
            Flickable {
                id:                 criticalMessageFlick
    
    Don Gagne's avatar
    Don Gagne committed
                anchors.margins:    parent._textMargins
    
                anchors.fill:       parent
                contentHeight:      criticalMessageText.height
                contentWidth:       criticalMessageText.width
                boundsBehavior:     Flickable.StopAtBounds
                pixelAligned:       true
                clip:               true
    
                TextEdit {
                    id:             criticalMessageText
                    width:          criticalMmessageArea.width - criticalClose.width - (ScreenTools.defaultFontPixelHeight * 2)
                    anchors.left:   parent.left
                    readOnly:       true
                    textFormat:     TextEdit.RichText
    
                    font.pointSize: ScreenTools.defaultFontPointSize
    
                    font.family:    ScreenTools.demiboldFontFamily
    
                    wrapMode:       TextEdit.WordWrap
    
    Gus Grubba's avatar
    Gus Grubba committed
                    color:          qgcPal.alertText
    
            //-- Dismiss Critical Message
    
            QGCColoredImage {
    
    dogmaphobic's avatar
    dogmaphobic committed
                anchors.margins:    ScreenTools.defaultFontPixelHeight * 0.5
    
                anchors.top:        parent.top
                anchors.right:      parent.right
    
    dogmaphobic's avatar
    dogmaphobic committed
                width:              ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.5 : ScreenTools.defaultFontPixelHeight
    
                height:             width
    
                sourceSize.height:  width
    
                source:             "/res/XDelete.svg"
                fillMode:           Image.PreserveAspectFit
    
    Gus Grubba's avatar
    Gus Grubba committed
                color:              qgcPal.alertText
    
    dogmaphobic's avatar
    dogmaphobic committed
                    anchors.fill:       parent
                    anchors.margins:    ScreenTools.isMobile ? -ScreenTools.defaultFontPixelHeight : 0
    
                    onClicked: {
                        criticalMmessageArea.close()
                    }
                }
            }
    
            //-- More text below indicator
    
            QGCColoredImage {
    
    dogmaphobic's avatar
    dogmaphobic committed
                anchors.margins:    ScreenTools.defaultFontPixelHeight * 0.5
    
                anchors.bottom:     parent.bottom
                anchors.right:      parent.right
    
    dogmaphobic's avatar
    dogmaphobic committed
                width:              ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.5 : ScreenTools.defaultFontPixelHeight
    
                height:             width
                sourceSize.height:  width
    
                source:             "/res/ArrowDown.svg"
                fillMode:           Image.PreserveAspectFit
                visible:            criticalMessageText.lineCount > 5
    
    Gus Grubba's avatar
    Gus Grubba committed
                color:              qgcPal.alertText
    
                MouseArea {
                    anchors.fill:   parent
                    onClicked: {
                        criticalMessageFlick.flick(0,-500)
                    }
                }
            }
        }
    
    
        //-------------------------------------------------------------------------
        //-- Loader helper for any child, no matter how deep can display an element
        //   in the middle of the main window.
        Loader {
            id: rootLoader
            anchors.centerIn: parent
        }