PlanView.qml 51 KB
Newer Older
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *   (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.
 *
 ****************************************************************************/
Don Gagne's avatar
Don Gagne committed
9

10 11
import QtQuick          2.3
import QtQuick.Controls 1.2
Don Gagne's avatar
Don Gagne committed
12
import QtQuick.Dialogs  1.2
13 14 15
import QtLocation       5.3
import QtPositioning    5.3
import QtQuick.Layouts  1.2
16
import QtQuick.Window   2.2
Don Gagne's avatar
Don Gagne committed
17

18 19 20 21 22 23 24 25 26 27 28
import QGroundControl                   1.0
import QGroundControl.FlightMap         1.0
import QGroundControl.ScreenTools       1.0
import QGroundControl.Controls          1.0
import QGroundControl.FactSystem        1.0
import QGroundControl.FactControls      1.0
import QGroundControl.Palette           1.0
import QGroundControl.Controllers       1.0
import QGroundControl.ShapeFileHelper   1.0
import QGroundControl.Airspace          1.0
import QGroundControl.Airmap            1.0
Don Gagne's avatar
Don Gagne committed
29

30
Item {
31

Gus Grubba's avatar
Gus Grubba committed
32 33
    property bool planControlColapsed: false

34 35
    readonly property int   _decimalPlaces:             8
    readonly property real  _margin:                    ScreenTools.defaultFontPixelHeight * 0.5
DonLakeFlyer's avatar
DonLakeFlyer committed
36
    readonly property real  _toolsTopMargin:            ScreenTools.defaultFontPixelHeight * 0.5
Gus Grubba's avatar
Gus Grubba committed
37
    readonly property real  _radius:                    ScreenTools.defaultFontPixelWidth  * 0.5
38 39 40
    readonly property real  _rightPanelWidth:           Math.min(parent.width / 3, ScreenTools.defaultFontPixelWidth * 30)
    readonly property var   _defaultVehicleCoordinate:  QtPositioning.coordinate(37.803784, -122.462276)
    readonly property bool  _waypointsOnlyMode:         QGroundControl.corePlugin.options.missionWaypointsOnly
41

Gus Grubba's avatar
Gus Grubba committed
42
    property bool   _airspaceEnabled:                    QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
Gus Grubba's avatar
Gus Grubba committed
43 44 45 46 47 48 49 50
    property var    _missionController:                 _planMasterController.missionController
    property var    _geoFenceController:                _planMasterController.geoFenceController
    property var    _rallyPointController:              _planMasterController.rallyPointController
    property var    _visualItems:                       _missionController.visualItems
    property bool   _lightWidgetBorders:                editorMap.isSatelliteMap
    property bool   _addWaypointOnClick:                false
    property bool   _addROIOnClick:                     false
    property bool   _singleComplexItem:                 _missionController.complexMissionItemNames.length === 1
Gus Grubba's avatar
Gus Grubba committed
51
    property int    _editingLayer:                      bar.currentIndex ? _layers[bar.currentIndex] : _layerMission
Gus Grubba's avatar
Gus Grubba committed
52
    property int    _toolStripBottom:                   toolStrip.height + toolStrip.y
53
    property var    _appSettings:                       QGroundControl.settingsManager.appSettings
54

Gus Grubba's avatar
Gus Grubba committed
55 56
    readonly property var       _layers:                [_layerMission, _layerGeoFence, _layerRallyPoints]

57 58 59 60
    readonly property int       _layerMission:              1
    readonly property int       _layerGeoFence:             2
    readonly property int       _layerRallyPoints:          3
    readonly property string    _armedVehicleUploadPrompt:  qsTr("Vehicle is currently armed. Do you want to upload the mission to the vehicle?")
61

62 63
    function addComplexItem(complexItemName) {
        var coordinate = editorMap.center
64
        coordinate.latitude  = coordinate.latitude.toFixed(_decimalPlaces)
65
        coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
66
        coordinate.altitude  = coordinate.altitude.toFixed(_decimalPlaces)
67
        insertComplexMissionItem(complexItemName, coordinate, _missionController.visualItems.count)
68 69 70
    }

    function insertComplexMissionItem(complexItemName, coordinate, index) {
71
        _missionController.insertComplexMissionItem(complexItemName, coordinate, index, true /* makeCurrentItem */)
72 73
    }

74
    function insertComplexMissionItemFromKMLOrSHP(complexItemName, file, index) {
75
        _missionController.insertComplexMissionItemFromKMLOrSHP(complexItemName, file, index, true /* makeCurrentItem */)
76 77
    }

78
    function updateAirspace(reset) {
79 80 81 82
        if(_airspaceEnabled) {
            var coordinateNW = editorMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */)
            var coordinateSE = editorMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */)
            if(coordinateNW.isValid && coordinateSE.isValid) {
83
                QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, true /*planView*/, reset)
84 85 86 87
            }
        }
    }

88 89 90 91 92
    property bool _firstMissionLoadComplete:    false
    property bool _firstFenceLoadComplete:      false
    property bool _firstRallyLoadComplete:      false
    property bool _firstLoadComplete:           false

93
    MapFitFunctions {
94
        id:                         mapFitFunctions  // The name for this id cannot be changed without breaking references outside of this code. Beware!
95 96
        map:                        editorMap
        usePlannedHomePosition:     true
97
        planMasterController:       _planMasterController
98 99
    }

100
    on_AirspaceEnabledChanged: {
101
        if(QGroundControl.airmapSupported) {
102 103
            if(_airspaceEnabled) {
                planControlColapsed = QGroundControl.airspaceManager.airspaceVisible
104
                updateAirspace(true)
105 106 107
            } else {
                planControlColapsed = false
            }
108
        } else {
Gus Grubba's avatar
Gus Grubba committed
109 110 111 112
            planControlColapsed = false
        }
    }

DonLakeFlyer's avatar
DonLakeFlyer committed
113
    Connections {
Gus Grubba's avatar
Gus Grubba committed
114
        target: _appSettings ? _appSettings.defaultMissionItemAltitude : null
DonLakeFlyer's avatar
DonLakeFlyer committed
115 116
        onRawValueChanged: {
            if (_visualItems.count > 1) {
117
                mainWindow.showComponentDialog(applyNewAltitude, qsTr("Apply new alititude"), mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
DonLakeFlyer's avatar
DonLakeFlyer committed
118 119 120 121 122 123 124 125 126 127
            }
        }
    }

    Component {
        id: applyNewAltitude
        QGCViewMessage {
            message:    qsTr("You have changed the default altitude for mission items. Would you like to apply that altitude to all the items in the current mission?")
            function accept() {
                hideDialog()
128
                _missionController.applyDefaultMissionAltitude()
DonLakeFlyer's avatar
DonLakeFlyer committed
129 130 131 132
            }
        }
    }

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    Component {
        id: activeMissionUploadDialogComponent
        QGCViewDialog {
            Column {
                anchors.fill:   parent
                spacing:        ScreenTools.defaultFontPixelHeight
                QGCLabel {
                    width:      parent.width
                    wrapMode:   Text.WordWrap
                    text:       qsTr("Your vehicle is currently flying a mission. In order to upload a new or modified mission the current mission will be paused.")
                }
                QGCLabel {
                    width:      parent.width
                    wrapMode:   Text.WordWrap
                    text:       qsTr("After the mission is uploaded you can adjust the current waypoint and start the mission.")
                }
                QGCButton {
                    text:       qsTr("Pause and Upload")
                    onClicked: {
Gus Grubba's avatar
Gus Grubba committed
152
                        activeVehicle.flightMode = activeVehicle.pauseFlightMode
153
                        _planMasterController.sendToVehicle()
154
                        hideDialog()
155 156 157 158 159 160
                    }
                }
            }
        }
    }

Gus Grubba's avatar
Gus Grubba committed
161
    Connections {
162
        target: QGroundControl.airspaceManager
163
        onAirspaceVisibleChanged: {
164
            planControlColapsed = QGroundControl.airspaceManager.airspaceVisible
Gus Grubba's avatar
Gus Grubba committed
165 166 167
        }
    }

168 169 170 171 172 173 174
    Component {
        id: noItemForKML
        QGCViewMessage {
            message:    qsTr("You need at least one item to create a KML.")
        }
    }

175
    PlanMasterController {
Gus Grubba's avatar
Gus Grubba committed
176
        id: _planMasterController
177

178
        Component.onCompleted: {
179
            _planMasterController.start(false /* flyView */)
180
            _missionController.setCurrentPlanViewIndex(0, true)
Gus Grubba's avatar
Gus Grubba committed
181
            mainWindow.planMasterControllerPlan = _planMasterController
182 183
        }

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
        function waitingOnIncompleteDataMessage(save) {
            var saveOrUpload = save ? qsTr("Save") : qsTr("Upload")
            mainWindow.showMessageDialog(qsTr("Unable to %1").arg(saveOrUpload), qsTr("Plan has incomplete items. Complete all items and %1 again.").arg(saveOrUpload))
        }

        function waitingOnTerrainDataMessage(save) {
            var saveOrUpload = save ? qsTr("Save") : qsTr("Upload")
            mainWindow.showMessageDialog(qsTr("Unable to %1").arg(saveOrUpload), qsTr("Plan is waiting on terrain data from server for correct altitude values."))
        }

        function checkReadyForSaveUpload(save) {
            if (readyForSaveState() == VisualMissionItem.NotReadyForSaveData) {
                waitingOnIncompleteDataMessage(save)
                return false
            } else if (readyForSaveState() == VisualMissionItem.NotReadyForSaveTerrain) {
                waitingOnTerrainDataMessage(save)
                return false
            }
            return true
203 204
        }

205
        function upload() {
206
            if (!checkReadyForSaveUpload(false /* save */)) {
207 208
                return
            }
Gus Grubba's avatar
Gus Grubba committed
209
            if (activeVehicle && activeVehicle.armed && activeVehicle.flightMode === activeVehicle.missionFlightMode) {
210
                mainWindow.showComponentDialog(activeMissionUploadDialogComponent, qsTr("Plan Upload"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel)
211
            } else {
212 213
                sendToVehicle()
            }
DonLakeFlyer's avatar
DonLakeFlyer committed
214 215
        }

216
        function loadFromSelectedFile() {
217
            fileDialog.title =          qsTr("Select Plan File")
DonLakeFlyer's avatar
DonLakeFlyer committed
218
            fileDialog.planFiles =      true
219
            fileDialog.selectExisting = true
Gus Grubba's avatar
Gus Grubba committed
220
            fileDialog.nameFilters =    _planMasterController.loadNameFilters
221 222
            fileDialog.fileExtension =  _appSettings.planFileExtension
            fileDialog.fileExtension2 = _appSettings.missionFileExtension
223
            fileDialog.openForLoad()
224 225 226
        }

        function saveToSelectedFile() {
227
            if (!checkReadyForSaveUpload(true /* save */)) {
228 229
                return
            }
230
            fileDialog.title =          qsTr("Save Plan")
231
            fileDialog.planFiles =      true
232
            fileDialog.selectExisting = false
Gus Grubba's avatar
Gus Grubba committed
233
            fileDialog.nameFilters =    _planMasterController.saveNameFilters
234 235
            fileDialog.fileExtension =  _appSettings.planFileExtension
            fileDialog.fileExtension2 = _appSettings.missionFileExtension
236
            fileDialog.openForSave()
237 238
        }

239
        function fitViewportToItems() {
240
            mapFitFunctions.fitMapViewportToMissionItems()
241
        }
242

243 244
        function loadShapeFromSelectedFile() {
            fileDialog.title =          qsTr("Load Shape")
245 246
            fileDialog.planFiles =      false
            fileDialog.selectExisting = true
247 248 249
            fileDialog.nameFilters =    ShapeFileHelper.fileDialogKMLOrSHPFilters
            fileDialog.fileExtension =  _appSettings.kmlFileExtension
            fileDialog.fileExtension2 = _appSettings.shpFileExtension
250 251 252
            fileDialog.openForLoad()
        }

253
        function saveKmlToSelectedFile() {
254
            if (!checkReadyForSaveUpload(true /* save */)) {
255 256
                return
            }
257
            fileDialog.title =          qsTr("Save KML")
258
            fileDialog.planFiles =      false
259
            fileDialog.selectExisting = false
260 261
            fileDialog.nameFilters =    ShapeFileHelper.fileDialogKMLFilters
            fileDialog.fileExtension =  _appSettings.kmlFileExtension
262
            fileDialog.fileExtension2 = ""
263 264
            fileDialog.openForSave()
        }
265
    }
266

267 268
    Connections {
        target: _missionController
269

270
        onNewItemsFromVehicle: {
Gus Grubba's avatar
Gus Grubba committed
271
            if (_visualItems && _visualItems.count !== 1) {
272 273
                mapFitFunctions.fitMapViewportToMissionItems()
            }
274
            _missionController.setCurrentPlanViewIndex(0, true)
275 276
        }
    }
277

278 279 280 281
    /// Inserts a new simple mission item
    ///     @param coordinate Location to insert item
    ///     @param index Insert item at this index
    function insertSimpleMissionItem(coordinate, index) {
282
        _missionController.insertSimpleMissionItem(coordinate, index, true /* makeCurrentItem */)
283 284
    }

285 286 287 288 289 290 291
    /// Inserts a new ROI mission item
    ///     @param coordinate Location to insert item
    ///     @param index Insert item at this index
    function insertROIMissionItem(coordinate, index) {
        var sequenceNumber = _missionController.insertROIMissionItem(coordinate, index)
        _missionController.setCurrentPlanViewIndex(sequenceNumber, true)
        _addROIOnClick = false
292
        toolStrip.lastClickedButton.checked = false
293 294
    }

295 296 297 298 299 300 301 302 303 304 305
    function selectNextNotReady() {
        var foundCurrent = false
        for (var i=0; i<_missionController.visualItems.count; i++) {
            var vmi = _missionController.visualItems.get(i)
            if (vmi.readyForSaveState === VisualMissionItem.NotReadyForSaveData) {
                _missionController.setCurrentPlanViewIndex(vmi.sequenceNumber, true)
                break
            }
        }
    }

306 307
    property int _moveDialogMissionItemIndex

308 309
    QGCFileDialog {
        id:             fileDialog
Gus Grubba's avatar
Gus Grubba committed
310
        folder:         _appSettings ? _appSettings.missionSavePath : ""
311

312 313
        property bool planFiles: true    ///< true: working with plan files, false: working with kml file

314
        onAcceptedForSave: {
315
            if (planFiles) {
Gus Grubba's avatar
Gus Grubba committed
316
                _planMasterController.saveToFile(file)
317
            } else {
Gus Grubba's avatar
Gus Grubba committed
318
                _planMasterController.saveToKml(file)
319
            }
320
            close()
321 322
        }

323
        onAcceptedForLoad: {
324
            if (planFiles) {
Gus Grubba's avatar
Gus Grubba committed
325 326
                _planMasterController.loadFromFile(file)
                _planMasterController.fitViewportToItems()
327 328
                _missionController.setCurrentPlanViewIndex(0, true)
            } else {
329 330
                var retList = ShapeFileHelper.determineShapeType(file)
                if (retList[0] == ShapeFileHelper.Error) {
331
                    mainWindow.showMessageDialog("Error", retList[1])
332
                } else if (retList[0] == ShapeFileHelper.Polygon) {
Gus Grubba's avatar
Gus Grubba committed
333
                     var editVehicle = activeVehicle ? activeVehicle : QGroundControl.multiVehicleManager.offlineEditingVehicle
334 335 336 337
                    if (editVehicle.fixedWing) {
                        insertComplexMissionItemFromKMLOrSHP(_missionController.surveyComplexItemName, file, -1)
                    } else {
                        polygonSelectPatternFile = file
338
                        mainWindow.showComponentDialog(patternPolygonSelectDialog, fileDialog.title, mainWindow.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
339
                    }
340 341
                } else if (retList[0] == ShapeFileHelper.Polyline) {
                    insertComplexMissionItemFromKMLOrSHP(_missionController.corridorScanComplexItemName, file, -1)
342 343
                }
            }
344
            close()
345 346 347
        }
    }

348
    property string polygonSelectPatternFile
349
    Component {
350
        id: patternPolygonSelectDialog
351 352 353 354 355 356 357 358
        QGCViewDialog {
            function accept() {
                var complexItemName
                if (surveyRadio.checked) {
                    complexItemName = _missionController.surveyComplexItemName
                } else {
                    complexItemName = _missionController.structureScanComplexItemName
                }
359
                insertComplexMissionItemFromKMLOrSHP(complexItemName, polygonSelectPatternFile, -1)
360 361 362 363 364 365 366 367 368 369
                hideDialog()
            }
            Column {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        ScreenTools.defaultFontPixelHeight
                QGCLabel {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    wrapMode:       Text.WordWrap
370
                    text:           qsTr("Create which pattern type?")
371 372 373 374 375 376 377 378 379 380 381 382 383
                }
                QGCRadioButton {
                    id:             surveyRadio
                    text:           qsTr("Survey")
                    checked:        true
                }
                QGCRadioButton {
                    text:           qsTr("Structure Scan")
                }
            }
        }
    }

384 385 386 387 388
    Component {
        id: moveDialog
        QGCViewDialog {
            function accept() {
                var toIndex = toCombo.currentIndex
Gus Grubba's avatar
Gus Grubba committed
389
                if (toIndex === 0) {
390 391
                    toIndex = 1
                }
392
                _missionController.moveMissionItem(_moveDialogMissionItemIndex, toIndex)
393 394 395 396 397 398 399 400 401 402 403
                hideDialog()
            }
            Column {
                anchors.left:   parent.left
                anchors.right:  parent.right
                spacing:        ScreenTools.defaultFontPixelHeight

                QGCLabel {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    wrapMode:       Text.WordWrap
404
                    text:           qsTr("Move the selected mission item to the be after following mission item:")
405 406 407 408
                }

                QGCComboBox {
                    id:             toCombo
409
                    model:          _visualItems.count
410 411 412 413 414 415
                    currentIndex:   _moveDialogMissionItemIndex
                }
            }
        }
    }

416
    Item {
Don Gagne's avatar
Don Gagne committed
417
        id:             panel
418
        anchors.fill:   parent
Don Gagne's avatar
Don Gagne committed
419

420
        FlightMap {
421 422 423 424 425
            id:                         editorMap
            anchors.fill:               parent
            mapName:                    "MissionEditor"
            allowGCSLocationCenter:     true
            allowVehicleLocationCenter: true
426
            planView:                   true
Don Gagne's avatar
Don Gagne committed
427

428
            // This is the center rectangle of the map which is not obscured by tools
DonLakeFlyer's avatar
DonLakeFlyer committed
429
            property rect centerViewport:   Qt.rect(_leftToolWidth + _margin, _toolsTopMargin, editorMap.width - _leftToolWidth - _rightToolWidth - (_margin * 2), mapScale.y - _margin - _toolsTopMargin)
430

431 432
            property real _leftToolWidth:       toolStrip.x + toolStrip.width
            property real _rightToolWidth:      rightPanel.width + rightPanel.anchors.rightMargin
433

434
            readonly property real animationDuration: 500
435

436 437
            // Initial map position duplicates Fly view position
            Component.onCompleted: editorMap.center = QGroundControl.flightMapPosition
438

439 440 441 442 443 444
            Behavior on zoomLevel {
                NumberAnimation {
                    duration:       editorMap.animationDuration
                    easing.type:    Easing.InOutQuad
                }
            }
445

446 447
            QGCMapPalette { id: mapPal; lightColors: editorMap.isSatelliteMap }

448 449
            onZoomLevelChanged: updateAirspace(false)
            onCenterChanged:    updateAirspace(false)
450

451 452 453
            MouseArea {
                anchors.fill: parent
                onClicked: {
454 455
                    // Take focus to close any previous editing
                    editorMap.focus = true
456 457 458 459
                    var coordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
                    coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
                    coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
                    coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
460

461 462 463
                    switch (_editingLayer) {
                    case _layerMission:
                        if (_addWaypointOnClick) {
464
                            insertSimpleMissionItem(coordinate, _missionController.visualItems.count)
465 466 467
                        } else if (_addROIOnClick) {
                            _addROIOnClick = false
                            insertROIMissionItem(coordinate, _missionController.visualItems.count)
468
                        }
469 470
                        break
                    case _layerRallyPoints:
Gus Grubba's avatar
Gus Grubba committed
471
                        if (_rallyPointController.supported && _addWaypointOnClick) {
472
                            _rallyPointController.addPoint(coordinate)
473
                        }
474
                        break
Don Gagne's avatar
Don Gagne committed
475
                    }
Don Gagne's avatar
Don Gagne committed
476
                }
477
            }
Don Gagne's avatar
Don Gagne committed
478

DonLakeFlyer's avatar
DonLakeFlyer committed
479 480 481 482 483 484 485 486 487 488 489 490
            PlanStartOverlay {
                id:                     startOverlay
                x:                      editorMap.centerViewport.left
                y:                      editorMap.centerViewport.top
                width:                  editorMap.centerViewport.width
                height:                 editorMap.centerViewport.height
                z:                      QGroundControl.zOrderMapItems + 2
                visible:                !_planMasterController.containsItems
                planMasterController:   _planMasterController
                mapControl:             editorMap
            }

491 492
            // Add the mission item visuals to the map
            Repeater {
493
                model: _editingLayer == _layerMission ? _missionController.visualItems : undefined
494 495
                delegate: MissionItemMapVisual {
                    map:        editorMap
496
                    onClicked:  _missionController.setCurrentPlanViewIndex(sequenceNumber, false)
497
                    visible:    _editingLayer == _layerMission
498
                }
499
            }
500

501 502
            // Add lines between waypoints
            MissionLineView {
503
                model: _editingLayer == _layerMission ? _missionController.waypointLines : undefined
504
            }
505

506 507 508 509 510 511
            MapItemView {
                model: _editingLayer == _layerMission ? _missionController.directionArrows : undefined

                delegate: MapLineArrow {
                    fromCoord:      object ? object.coordinate1 : undefined
                    toCoord:        object ? object.coordinate2 : undefined
512 513 514 515 516 517 518 519 520 521 522 523 524
                    arrowPosition:  3
                    z:              QGroundControl.zOrderWaypointLines + 1
                }
            }

            // UI for splitting the current segment
            MapQuickItem {
                id:             splitSegmentItem
                anchorPoint.x:  sourceItem.width / 2
                anchorPoint.y:  sourceItem.height / 2
                z:              QGroundControl.zOrderWaypointLines + 1

                sourceItem: SplitIndicator {
Don Gagne's avatar
Don Gagne committed
525
                    onClicked:  insertSimpleMissionItem(splitSegmentItem.coordinate, _missionController.visualItemIndexFromSequenceNumber(_missionController.currentPlanViewIndex))
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
                }

                function _updateSplitCoord() {
                    if (_missionController.splitSegment) {
                        var distance = _missionController.splitSegment.coordinate1.distanceTo(_missionController.splitSegment.coordinate2)
                        var azimuth = _missionController.splitSegment.coordinate1.azimuthTo(_missionController.splitSegment.coordinate2)
                        splitSegmentItem.coordinate = _missionController.splitSegment.coordinate1.atDistanceAndAzimuth(distance / 2, azimuth)
                    } else {
                        coordinate = QtPositioning.coordinate()
                    }
                }

                Connections {
                    target:                 _missionController
                    onSplitSegmentChanged:  splitSegmentItem._updateSplitCoord()
                }

                Connections {
                    target:                 _missionController.splitSegment
                    onCoordinate1Changed:   splitSegmentItem._updateSplitCoord()
                    onCoordinate2Changed:   splitSegmentItem._updateSplitCoord()
547 548 549
                }
            }

550 551 552 553 554 555 556
            // Add the vehicles to the map
            MapItemView {
                model: QGroundControl.multiVehicleManager.vehicles
                delegate:
                    VehicleMapItem {
                    vehicle:        object
                    coordinate:     object.coordinate
557
                    map:            editorMap
558 559
                    size:           ScreenTools.defaultFontPixelHeight * 3
                    z:              QGroundControl.zOrderMapItems - 1
560
                }
561
            }
562

563 564
            GeoFenceMapVisuals {
                map:                    editorMap
565
                myGeoFenceController:   _geoFenceController
566
                interactive:            _editingLayer == _layerGeoFence
567
                homePosition:           _missionController.plannedHomePosition
568 569
                planView:               true
            }
570

571 572
            RallyPointMapVisuals {
                map:                    editorMap
573
                myRallyPointController: _rallyPointController
574 575
                interactive:            _editingLayer == _layerRallyPoints
                planView:               true
576
            }
577

578 579
            // Airspace overlap support
            MapItemView {
580
                model:              _airspaceEnabled && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : []
581 582 583
                delegate: MapCircle {
                    center:         object.center
                    radius:         object.radius
584
                    color:          object.color
Gus Grubba's avatar
Gus Grubba committed
585 586
                    border.color:   object.lineColor
                    border.width:   object.lineWidth
587 588 589 590
                }
            }

            MapItemView {
591
                model:              _airspaceEnabled && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : []
592 593
                delegate: MapPolygon {
                    path:           object.polygon
594
                    color:          object.color
Gus Grubba's avatar
Gus Grubba committed
595 596
                    border.color:   object.lineColor
                    border.width:   object.lineWidth
597 598
                }
            }
599
        }
600

601 602
        //-----------------------------------------------------------
        // Left tool strip
Gus Grubba's avatar
Gus Grubba committed
603
        ToolStrip {
604
            id:                 toolStrip
605
            anchors.leftMargin: ScreenTools.defaultFontPixelWidth * 2
606
            anchors.left:       parent.left
DonLakeFlyer's avatar
DonLakeFlyer committed
607
            anchors.topMargin:  _toolsTopMargin
608 609
            anchors.top:        parent.top
            z:                  QGroundControl.zOrderWidgets
Gus Grubba's avatar
Gus Grubba committed
610
            maxHeight:          mapScale.y - toolStrip.y
611

Gus Grubba's avatar
Gus Grubba committed
612
            property bool _isRally:     _editingLayer == _layerRallyPoints
613

Gus Grubba's avatar
Gus Grubba committed
614 615 616 617 618 619
            model: [
                {
                    name:               qsTr("Fly"),
                    iconSource:         "/qmlimages/PaperPlane.svg",
                    buttonEnabled:      true,
                    buttonVisible:      true,
620
                },
621
                {
Gus Grubba's avatar
Gus Grubba committed
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
                    name:               qsTr("File"),
                    iconSource:         "/qmlimages/MapSync.svg",
                    buttonEnabled:      !_planMasterController.syncInProgress,
                    buttonVisible:      true,
                    showAlternateIcon:  _planMasterController.dirty,
                    alternateIconSource:"/qmlimages/MapSyncChanged.svg",
                    dropPanelComponent: syncDropPanel
                },
                {
                    name:               _editingLayer == _layerRallyPoints ? qsTr("Rally Point") : qsTr("Waypoint"),
                    iconSource:         "/qmlimages/MapAddMission.svg",
                    buttonEnabled:      true,
                    buttonVisible:      true,
                    toggle:             true,
                    checked:            _addWaypointOnClick
                },
                {
                    name:               qsTr("ROI"),
                    iconSource:         "/qmlimages/MapAddMission.svg",
                    buttonEnabled:      true,
                    buttonVisible:      !_isRally && _waypointsOnlyMode,
                    toggle:             true
                },
                {
                    name:               _singleComplexItem ? _missionController.complexMissionItemNames[0] : qsTr("Pattern"),
                    iconSource:         "/qmlimages/MapDrawShape.svg",
                    buttonEnabled:      true,
                    buttonVisible:      !_isRally,
                    dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel
                },
                {
                    name:               qsTr("Center"),
                    iconSource:         "/qmlimages/MapCenter.svg",
                    buttonEnabled:      true,
                    buttonVisible:      true,
                    dropPanelComponent: centerMapDropPanel
                }
            ]
660

Gus Grubba's avatar
Gus Grubba committed
661 662
            onClicked: {
                switch (index) {
663 664 665 666
                case 0:
                    mainWindow.showFlyView()
                    break;
                case 2:
Gus Grubba's avatar
Gus Grubba committed
667 668 669 670 671 672
                    if(_addWaypointOnClick) {
                        //-- Toggle it off
                        _addWaypointOnClick = false
                        _addROIOnClick = false
                        setChecked(index, false)
                    } else {
673
                        _addWaypointOnClick = checked
674
                        _addROIOnClick = false
Gus Grubba's avatar
Gus Grubba committed
675 676
                    }
                    break
677
                case 3:
Gus Grubba's avatar
Gus Grubba committed
678 679 680
                    _addROIOnClick = checked
                    _addWaypointOnClick = false
                    break
681
                case 4:
Gus Grubba's avatar
Gus Grubba committed
682 683 684 685
                    if (_singleComplexItem) {
                        addComplexItem(_missionController.complexMissionItemNames[0])
                    }
                    break
686 687
                }
            }
Gus Grubba's avatar
Gus Grubba committed
688
        }
689

Gus Grubba's avatar
Gus Grubba committed
690
        //-----------------------------------------------------------
691 692 693
        // Right pane for mission editing controls
        Rectangle {
            id:                 rightPanel
694
            height:             parent.height
695 696
            width:              _rightPanelWidth
            color:              qgcPal.window
697
            opacity:            planExpanded.visible ? 0.2 : 0
Gus Grubba's avatar
Gus Grubba committed
698 699 700
            anchors.bottom:     parent.bottom
            anchors.right:      parent.right
            anchors.rightMargin: ScreenTools.defaultFontPixelWidth
701
        }
Gus Grubba's avatar
Gus Grubba committed
702 703
        //-------------------------------------------------------
        // Right Panel Controls
704
        Item {
Gus Grubba's avatar
Gus Grubba committed
705
            anchors.fill:           rightPanel
DonLakeFlyer's avatar
DonLakeFlyer committed
706
            anchors.topMargin:      _toolsTopMargin
Gus Grubba's avatar
Gus Grubba committed
707 708 709
            DeadMouseArea {
                anchors.fill:   parent
            }
Gus Grubba's avatar
Gus Grubba committed
710 711
            Column {
                id:                 rightControls
Gus Grubba's avatar
Gus Grubba committed
712
                spacing:            ScreenTools.defaultFontPixelHeight * 0.5
713 714
                anchors.left:       parent.left
                anchors.right:      parent.right
Gus Grubba's avatar
Gus Grubba committed
715 716 717 718
                anchors.top:        parent.top
                //-------------------------------------------------------
                // Airmap Airspace Control
                AirspaceControl {
Gus Grubba's avatar
Gus Grubba committed
719 720
                    id:             airspaceControl
                    width:          parent.width
721
                    visible:        _airspaceEnabled
722
                    planView:       true
723
                    showColapse:    true
724
                }
Gus Grubba's avatar
Gus Grubba committed
725 726 727 728
                //-------------------------------------------------------
                // Mission Controls (Colapsed)
                Rectangle {
                    width:      parent.width
Gus Grubba's avatar
Gus Grubba committed
729
                    height:     planControlColapsed ? colapsedRow.height + ScreenTools.defaultFontPixelHeight : 0
Gus Grubba's avatar
Gus Grubba committed
730 731
                    color:      qgcPal.missionItemEditor
                    radius:     _radius
732
                    visible:    planControlColapsed && _airspaceEnabled
Gus Grubba's avatar
Gus Grubba committed
733 734 735 736 737 738 739
                    Row {
                        id:                     colapsedRow
                        spacing:                ScreenTools.defaultFontPixelWidth
                        anchors.left:           parent.left
                        anchors.leftMargin:     ScreenTools.defaultFontPixelWidth
                        anchors.verticalCenter: parent.verticalCenter
                        QGCColoredImage {
740 741 742 743 744
                            width:              height
                            height:             ScreenTools.defaultFontPixelWidth * 2.5
                            sourceSize.height:  height
                            source:             "qrc:/res/waypoint.svg"
                            color:              qgcPal.text
Gus Grubba's avatar
Gus Grubba committed
745 746 747
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        QGCLabel {
748 749
                            text:               qsTr("Plan")
                            color:              qgcPal.text
Gus Grubba's avatar
Gus Grubba committed
750
                            anchors.verticalCenter: parent.verticalCenter
751 752
                        }
                    }
Gus Grubba's avatar
Gus Grubba committed
753 754 755 756
                    QGCColoredImage {
                        width:                  height
                        height:                 ScreenTools.defaultFontPixelWidth * 2.5
                        sourceSize.height:      height
757
                        source:                 QGroundControl.airmapSupported ? "qrc:/airmap/expand.svg" : ""
758
                        color:                  "white"
759
                        visible:                QGroundControl.airmapSupported
Gus Grubba's avatar
Gus Grubba committed
760 761 762 763 764 765
                        anchors.right:          parent.right
                        anchors.rightMargin:    ScreenTools.defaultFontPixelWidth
                        anchors.verticalCenter: parent.verticalCenter
                    }
                    MouseArea {
                        anchors.fill:   parent
766
                        enabled:        QGroundControl.airmapSupported
Gus Grubba's avatar
Gus Grubba committed
767
                        onClicked: {
768
                            QGroundControl.airspaceManager.airspaceVisible = false
Gus Grubba's avatar
Gus Grubba committed
769 770
                        }
                    }
Gus Grubba's avatar
Gus Grubba committed
771
                }
Gus Grubba's avatar
Gus Grubba committed
772 773 774 775 776
                //-------------------------------------------------------
                // Mission Controls (Expanded)
                Rectangle {
                    id:         planExpanded
                    width:      parent.width
Gus Grubba's avatar
Gus Grubba committed
777
                    height:     (!planControlColapsed || !_airspaceEnabled) ? bar.height + ScreenTools.defaultFontPixelHeight : 0
Gus Grubba's avatar
Gus Grubba committed
778 779
                    color:      qgcPal.missionItemEditor
                    radius:     _radius
Gus Grubba's avatar
Gus Grubba committed
780
                    visible:    (!planControlColapsed || !_airspaceEnabled) && QGroundControl.corePlugin.options.enablePlanViewSelector
Gus Grubba's avatar
Gus Grubba committed
781
                    Item {
Gus Grubba's avatar
Gus Grubba committed
782
                        height:             bar.height
Gus Grubba's avatar
Gus Grubba committed
783 784
                        anchors.left:       parent.left
                        anchors.right:      parent.right
Gus Grubba's avatar
Gus Grubba committed
785
                        anchors.margins:    ScreenTools.defaultFontPixelWidth
Gus Grubba's avatar
Gus Grubba committed
786
                        anchors.verticalCenter: parent.verticalCenter
Gus Grubba's avatar
Gus Grubba committed
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
                        QGCTabBar {
                            id:             bar
                            width:          parent.width
                            anchors.centerIn: parent
                            Component.onCompleted: {
                                currentIndex = 0
                            }
                            QGCTabButton {
                                text:       qsTr("Mission")
                            }
                            QGCTabButton {
                                text:       qsTr("Fence")
                                enabled:    _geoFenceController.supported
                            }
                            QGCTabButton {
                                text:       qsTr("Rally")
                                enabled:    _rallyPointController.supported
Gus Grubba's avatar
Gus Grubba committed
804 805 806 807 808 809 810 811 812 813 814 815
                            }
                        }
                    }
                }
            }
            //-------------------------------------------------------
            // Mission Item Editor
            Item {
                id:                     missionItemEditor
                anchors.left:           parent.left
                anchors.right:          parent.right
                anchors.top:            rightControls.bottom
Gus Grubba's avatar
Gus Grubba committed
816
                anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
Gus Grubba's avatar
Gus Grubba committed
817 818 819 820
                anchors.bottom:         parent.bottom
                anchors.bottomMargin:   ScreenTools.defaultFontPixelHeight * 0.25
                visible:                _editingLayer == _layerMission && !planControlColapsed
                QGCListView {
Gus Grubba's avatar
Gus Grubba committed
821 822 823 824 825 826 827 828
                    id:                 missionItemEditorListView
                    anchors.fill:       parent
                    spacing:            ScreenTools.defaultFontPixelHeight / 4
                    orientation:        ListView.Vertical
                    model:              _missionController.visualItems
                    cacheBuffer:        Math.max(height * 2, 0)
                    clip:               true
                    currentIndex:       _missionController.currentPlanViewIndex
Gus Grubba's avatar
Gus Grubba committed
829
                    highlightMoveDuration: 250
Gus Grubba's avatar
Gus Grubba committed
830
                    visible:            _editingLayer == _layerMission && !planControlColapsed
Gus Grubba's avatar
Gus Grubba committed
831 832
                    //-- List Elements
                    delegate: MissionItemEditor {
Gus Grubba's avatar
Gus Grubba committed
833
                        map:            editorMap
Gus Grubba's avatar
Gus Grubba committed
834
                        masterController:  _planMasterController
Gus Grubba's avatar
Gus Grubba committed
835 836 837 838
                        missionItem:    object
                        width:          parent.width
                        readOnly:       false
                        onClicked:      _missionController.setCurrentPlanViewIndex(object.sequenceNumber, false)
Gus Grubba's avatar
Gus Grubba committed
839 840 841 842 843 844 845 846
                        onRemove: {
                            var removeIndex = index
                            _missionController.removeMissionItem(removeIndex)
                            if (removeIndex >= _missionController.visualItems.count) {
                                removeIndex--
                            }
                            _missionController.setCurrentPlanViewIndex(removeIndex, true)
                        }
847 848 849
                        onInsertWaypoint:           insertSimpleMissionItem(editorMap.center, index)
                        onInsertComplexItem:        insertComplexMissionItem(complexItemName, editorMap.center, index)
                        onSelectNextNotReadyItem:   selectNextNotReady()
Gus Grubba's avatar
Gus Grubba committed
850 851 852 853 854 855
                    }
                }
            }
            // GeoFence Editor
            GeoFenceEditor {
                anchors.top:            rightControls.bottom
Gus Grubba's avatar
Gus Grubba committed
856
                anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
Don Gagne's avatar
Don Gagne committed
857
                anchors.bottom:         parent.bottom
Gus Grubba's avatar
Gus Grubba committed
858 859 860 861 862 863 864 865 866 867
                anchors.left:           parent.left
                anchors.right:          parent.right
                myGeoFenceController:   _geoFenceController
                flightMap:              editorMap
                visible:                _editingLayer == _layerGeoFence
            }
            // Rally Point Editor
            RallyPointEditorHeader {
                id:                     rallyPointHeader
                anchors.top:            rightControls.bottom
Gus Grubba's avatar
Gus Grubba committed
868
                anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
Gus Grubba's avatar
Gus Grubba committed
869 870 871 872 873 874 875 876
                anchors.left:           parent.left
                anchors.right:          parent.right
                visible:                _editingLayer == _layerRallyPoints
                controller:             _rallyPointController
            }
            RallyPointItemEditor {
                id:                     rallyPointEditor
                anchors.top:            rallyPointHeader.bottom
Gus Grubba's avatar
Gus Grubba committed
877
                anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
Gus Grubba's avatar
Gus Grubba committed
878 879 880 881 882
                anchors.left:           parent.left
                anchors.right:          parent.right
                visible:                _editingLayer == _layerRallyPoints && _rallyPointController.points.count
                rallyPoint:             _rallyPointController.currentRallyPoint
                controller:             _rallyPointController
883
            }
Gus Grubba's avatar
Gus Grubba committed
884
        }
885 886

        MapScale {
887 888 889 890 891 892 893 894 895 896 897
            id:                     mapScale
            anchors.margins:        ScreenTools.defaultFontPixelHeight * (0.66)
            anchors.bottom:         waypointValuesDisplay.visible ? waypointValuesDisplay.top : parent.bottom
            anchors.left:           parent.left
            mapControl:             editorMap
            buttonsOnLeft:          true
            terrainButtonVisible:   true
            visible:                _toolStripBottom < y && _editingLayer === _layerMission
            terrainButtonChecked:   waypointValuesDisplay.visible

            onTerrainButtonClicked: waypointValuesDisplay.toggleVisible()
898 899 900 901 902 903
        }

        MissionItemStatus {
            id:                 waypointValuesDisplay
            anchors.margins:    ScreenTools.defaultFontPixelWidth
            anchors.left:       parent.left
904
            height:             ScreenTools.defaultFontPixelHeight * 7
905
            maxWidth:           parent.width - rightPanel.width - x
906
            anchors.bottom:     parent.bottom
907
            missionItems:       _missionController.visualItems
908 909 910 911 912 913 914
            visible:            _internalVisible && _editingLayer === _layerMission && (_toolStripBottom + mapScale.height) < y && QGroundControl.corePlugin.options.showMissionStatus

            property bool _internalVisible: false

            function toggleVisible() {
                _internalVisible = !_internalVisible
            }
915
        }
Gus Grubba's avatar
Gus Grubba committed
916
    }
917

918 919 920 921
    Component {
        id: syncLoadFromVehicleOverwrite
        QGCViewMessage {
            id:         syncLoadFromVehicleCheck
Don Gagne's avatar
Don Gagne committed
922
            message:   qsTr("You have unsaved/unsent changes. Loading from the Vehicle will lose these changes. Are you sure you want to load from the Vehicle?")
923 924
            function accept() {
                hideDialog()
Gus Grubba's avatar
Gus Grubba committed
925
                _planMasterController.loadFromVehicle()
926 927 928 929 930 931 932 933
            }
        }
    }

    Component {
        id: syncLoadFromFileOverwrite
        QGCViewMessage {
            id:         syncLoadFromVehicleCheck
DonLakeFlyer's avatar
DonLakeFlyer committed
934
            message:   qsTr("You have unsaved/unsent changes. Loading from a file will lose these changes. Are you sure you want to load from a file?")
935 936
            function accept() {
                hideDialog()
Gus Grubba's avatar
Gus Grubba committed
937
                _planMasterController.loadFromSelectedFile()
938 939 940 941
            }
        }
    }

942 943 944
    Component {
        id: removeAllPromptDialog
        QGCViewMessage {
945
            message: qsTr("Are you sure you want to remove all items and create a new plan? ") +
946
                     (_planMasterController.offline ? "" : qsTr("This will also remove all items from the vehicle."))
947
            function accept() {
948
                if (_planMasterController.offline) {
Gus Grubba's avatar
Gus Grubba committed
949
                    _planMasterController.removeAll()
950
                } else {
Gus Grubba's avatar
Gus Grubba committed
951
                    _planMasterController.removeAllFromVehicle()
952
                }
953
                _missionController.setCurrentPlanViewIndex(0, true)
DonLakeFlyer's avatar
DonLakeFlyer committed
954
                startOverlay.visible = true
955 956 957 958 959
                hideDialog()
            }
        }
    }

960 961 962 963 964
    Component {
        id: clearVehicleMissionDialog
        QGCViewMessage {
            message: qsTr("Are you sure you want to remove all mission items and clear the mission from the vehicle?")
            function accept() {
Gus Grubba's avatar
Gus Grubba committed
965
                _planMasterController.removeAllFromVehicle()
966
                _missionController.setCurrentPlanViewIndex(0, true)
DonLakeFlyer's avatar
DonLakeFlyer committed
967
                startOverlay.visible = true
968 969 970 971 972
                hideDialog()
            }
        }
    }

973 974 975 976 977 978 979 980 981 982 983
    //- ToolStrip DropPanel Components

    Component {
        id: centerMapDropPanel

        CenterMapDropPanel {
            map:            editorMap
            fitFunctions:   mapFitFunctions
        }
    }

984 985 986 987 988 989 990 991 992
    Component {
        id: patternDropPanel

        ColumnLayout {
            spacing:    ScreenTools.defaultFontPixelWidth * 0.5

            QGCLabel { text: qsTr("Create complex pattern:") }

            Repeater {
993
                model: _missionController.complexMissionItemNames
994 995 996 997 998 999

                QGCButton {
                    text:               modelData
                    Layout.fillWidth:   true

                    onClicked: {
1000
                        addComplexItem(modelData)
1001 1002 1003 1004
                        dropPanel.hide()
                    }
                }
            }
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017

            Rectangle {
                width:              parent.width * 0.8
                height:             1
                color:              qgcPal.text
                opacity:            0.5
                Layout.fillWidth:   true
                Layout.columnSpan:  2
            }

            QGCButton {
                text:               qsTr("Load KML/SHP...")
                Layout.fillWidth:   true
Gus Grubba's avatar
Gus Grubba committed
1018
                enabled:            !_planMasterController.syncInProgress
1019
                onClicked: {
Gus Grubba's avatar
Gus Grubba committed
1020
                    _planMasterController.loadShapeFromSelectedFile()
1021 1022 1023
                    dropPanel.hide()
                }
            }
1024 1025
        } // Column
    }
1026 1027

    Component {
1028
        id: syncDropPanel
1029

1030 1031 1032
        Column {
            id:         columnHolder
            spacing:    _margin
1033

1034
            property string _overwriteText: (_editingLayer == _layerMission) ? qsTr("Mission overwrite") : ((_editingLayer == _layerGeoFence) ? qsTr("GeoFence overwrite") : qsTr("Rally Points overwrite"))
1035

1036 1037 1038
            QGCLabel {
                width:      sendSaveGrid.width
                wrapMode:   Text.WordWrap
Gus Grubba's avatar
Gus Grubba committed
1039
                text:       _planMasterController.dirty ?
Gus Grubba's avatar
Gus Grubba committed
1040
                                (activeVehicle ?
1041 1042 1043 1044
                                     qsTr("You have unsaved changes. You should upload to your vehicle, or save to a file:") :
                                     qsTr("You have unsaved changes.")
                                ) :
                                qsTr("Plan File:")
1045 1046
            }

1047 1048 1049 1050 1051 1052
            GridLayout {
                id:                 sendSaveGrid
                columns:            2
                anchors.margins:    _margin
                rowSpacing:         _margin
                columnSpacing:      ScreenTools.defaultFontPixelWidth
1053

1054
                QGCButton {
1055
                    text:               qsTr("New...")
1056
                    Layout.fillWidth:   true
1057
                    onClicked:  {
1058
                        dropPanel.hide()
1059 1060 1061 1062 1063
                        if (_planMasterController.containsItems) {
                            mainWindow.showComponentDialog(removeAllPromptDialog, qsTr("New Plan"), mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
                        } else {
                            startOverlay.visible = true
                        }
1064 1065
                    }
                }
1066

1067
                QGCButton {
1068
                    text:               qsTr("Open...")
1069
                    Layout.fillWidth:   true
Gus Grubba's avatar
Gus Grubba committed
1070
                    enabled:            !_planMasterController.syncInProgress
1071 1072
                    onClicked: {
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1073
                        if (_planMasterController.dirty) {
1074
                            mainWindow.showComponentDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
1075
                        } else {
Gus Grubba's avatar
Gus Grubba committed
1076
                            _planMasterController.loadFromSelectedFile()
1077 1078 1079
                        }
                    }
                }
1080

1081
                QGCButton {
1082
                    text:               qsTr("Save")
1083
                    Layout.fillWidth:   true
Gus Grubba's avatar
Gus Grubba committed
1084
                    enabled:            !_planMasterController.syncInProgress && _planMasterController.currentPlanFile !== ""
1085 1086
                    onClicked: {
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1087 1088
                        if(_planMasterController.currentPlanFile !== "") {
                            _planMasterController.saveToCurrent()
1089
                        } else {
Gus Grubba's avatar
Gus Grubba committed
1090
                            _planMasterController.saveToSelectedFile()
1091
                        }
1092 1093 1094 1095
                    }
                }

                QGCButton {
1096
                    text:               qsTr("Save As...")
1097
                    Layout.fillWidth:   true
1098
                    enabled:            !_planMasterController.syncInProgress && _planMasterController.containsItems
1099 1100
                    onClicked: {
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1101
                        _planMasterController.saveToSelectedFile()
1102 1103 1104 1105
                    }
                }

                QGCButton {
1106
                    text:               qsTr("Save Mission Waypoints As KML...")
1107
                    Layout.columnSpan:  2
Gus Grubba's avatar
Gus Grubba committed
1108
                    enabled:            !_planMasterController.syncInProgress && _visualItems.count > 1
1109
                    onClicked: {
1110
                        // First point does not count
1111
                        if (_visualItems.count < 2) {
1112
                            mainWindow.showComponentDialog(noItemForKML, qsTr("KML"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel)
1113 1114
                            return
                        }
1115
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1116
                        _planMasterController.saveKmlToSelectedFile()
1117 1118
                    }
                }
1119

1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
                Rectangle {
                    width:              parent.width * 0.8
                    height:             1
                    color:              qgcPal.text
                    opacity:            0.5
                    visible:            !QGroundControl.corePlugin.options.disableVehicleConnection
                    Layout.fillWidth:   true
                    Layout.columnSpan:  2
                }

1130
                QGCButton {
1131
                    text:               qsTr("Upload")
1132
                    Layout.fillWidth:   true
1133
                    enabled:            !_planMasterController.offline && !_planMasterController.syncInProgress && _planMasterController.containsItems
1134 1135
                    visible:            !QGroundControl.corePlugin.options.disableVehicleConnection
                    onClicked: {
1136
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1137
                        _planMasterController.upload()
1138 1139
                    }
                }
1140 1141 1142 1143

                QGCButton {
                    text:               qsTr("Download")
                    Layout.fillWidth:   true
Gus Grubba's avatar
Gus Grubba committed
1144
                    enabled:            !_planMasterController.offline && !_planMasterController.syncInProgress
1145 1146 1147
                    visible:            !QGroundControl.corePlugin.options.disableVehicleConnection
                    onClicked: {
                        dropPanel.hide()
Gus Grubba's avatar
Gus Grubba committed
1148
                        if (_planMasterController.dirty) {
1149
                            mainWindow.showComponentDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
1150
                        } else {
Gus Grubba's avatar
Gus Grubba committed
1151
                            _planMasterController.loadFromVehicle()
1152 1153 1154 1155 1156 1157 1158 1159
                        }
                    }
                }

                QGCButton {
                    text:               qsTr("Clear Vehicle Mission")
                    Layout.fillWidth:   true
                    Layout.columnSpan:  2
Gus Grubba's avatar
Gus Grubba committed
1160
                    enabled:            !_planMasterController.offline && !_planMasterController.syncInProgress
1161 1162 1163
                    visible:            !QGroundControl.corePlugin.options.disableVehicleConnection
                    onClicked: {
                        dropPanel.hide()
1164
                        mainWindow.showComponentDialog(clearVehicleMissionDialog, text, mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
1165 1166 1167
                    }
                }

1168
            }
1169 1170
        }
    }
Gus Grubba's avatar
Gus Grubba committed
1171
}