From 205138cf98a679dbcc1c9308372dc83bb9ed4fa1 Mon Sep 17 00:00:00 2001
From: Don Gagne <don@thegagnes.com>
Date: Fri, 17 Feb 2017 15:55:21 -0800
Subject: [PATCH] Fixed Wing landing pattern starting point

Also added ui support for multiple complex item types
---
 qgroundcontrol.pro                                 |   2 +
 qgroundcontrol.qrc                                 |   2 +
 src/MissionEditor/FWLandingPatternEditor.qml       |  41 +++++
 src/MissionEditor/MissionEditor.qml                |  51 ++++--
 src/MissionEditor/MissionItemEditor.qml            |   6 +-
 .../FWLandingPattern.FactMetaData.json             |   2 +
 src/MissionManager/FixedWingLandingComplexItem.cc  | 182 +++++++++++++++++++++
 src/MissionManager/FixedWingLandingComplexItem.h   |  76 +++++++++
 src/MissionManager/MissionController.cc            |  20 ++-
 src/MissionManager/MissionController.h             |  11 +-
 src/MissionManager/SimpleMissionItem.cc            |   2 +
 src/MissionManager/SurveyMissionItem.cc            |   2 +
 src/MissionManager/VisualMissionItem.h             |   2 +
 13 files changed, 372 insertions(+), 27 deletions(-)
 create mode 100644 src/MissionEditor/FWLandingPatternEditor.qml
 create mode 100644 src/MissionManager/FWLandingPattern.FactMetaData.json
 create mode 100644 src/MissionManager/FixedWingLandingComplexItem.cc
 create mode 100644 src/MissionManager/FixedWingLandingComplexItem.h

diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index 3ef7283..02a09e8 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -429,6 +429,7 @@ HEADERS += \
     src/LogCompressor.h \
     src/MG.h \
     src/MissionManager/ComplexMissionItem.h \
+    src/MissionManager/FixedWingLandingComplexItem.h \
     src/MissionManager/GeoFenceController.h \
     src/MissionManager/GeoFenceManager.h \
     src/MissionManager/MissionCommandList.h \
@@ -592,6 +593,7 @@ SOURCES += \
     src/JsonHelper.cc \
     src/LogCompressor.cc \
     src/MissionManager/ComplexMissionItem.cc \
+    src/MissionManager/FixedWingLandingComplexItem.cc \
     src/MissionManager/GeoFenceController.cc \
     src/MissionManager/GeoFenceManager.cc \
     src/MissionManager/MissionCommandList.cc \
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 9fe698a..aae4d36 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -149,6 +149,7 @@
         <file alias="SetupView.qml">src/VehicleSetup/SetupView.qml</file>
         <file alias="SimpleItemEditor.qml">src/MissionEditor/SimpleItemEditor.qml</file>
         <file alias="SurveyItemEditor.qml">src/MissionEditor/SurveyItemEditor.qml</file>
+        <file alias="FWLandingPatternEditor.qml">src/MissionEditor/FWLandingPatternEditor.qml</file>
         <file alias="TcpSettings.qml">src/ui/preferences/TcpSettings.qml</file>
         <file alias="test.qml">src/test.qml</file>
         <file alias="UdpSettings.qml">src/ui/preferences/UdpSettings.qml</file>
@@ -169,6 +170,7 @@
         <file alias="Vehicle/VibrationFact.json">src/Vehicle/VibrationFact.json</file>
         <file alias="QGroundControlQmlGlobal.json">src/QmlControls/QGroundControlQmlGlobal.json</file>
         <file alias="RallyPoint.FactMetaData.json">src/MissionManager/RallyPoint.FactMetaData.json</file>
+        <file alias="FWLandingPattern.FactMetaData.json">src/MissionManager/FWLandingPattern.FactMetaData.json</file>
         <file alias="Survey.FactMetaData.json">src/MissionManager/Survey.FactMetaData.json</file>
         <file alias="USBBoardInfo.json">src/comm/USBBoardInfo.json</file>
     </qresource>
diff --git a/src/MissionEditor/FWLandingPatternEditor.qml b/src/MissionEditor/FWLandingPatternEditor.qml
new file mode 100644
index 0000000..e30049a
--- /dev/null
+++ b/src/MissionEditor/FWLandingPatternEditor.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+ *
+ *   (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.2
+import QtQuick.Controls 1.2
+import QtQuick.Dialogs  1.2
+import QtQuick.Layouts  1.2
+
+import QGroundControl               1.0
+import QGroundControl.ScreenTools   1.0
+import QGroundControl.Vehicle       1.0
+import QGroundControl.Controls      1.0
+import QGroundControl.FactControls  1.0
+import QGroundControl.Palette       1.0
+
+// Editor for Fixed Wing Landing Pattern complex mission item
+Rectangle {
+    id:         _root
+    height:     visible ? (editorColumn.height + (_margin * 2)) : 0
+    width:      availableWidth
+    color:      qgcPal.windowShadeDark
+    radius:     _radius
+
+    // The following properties must be available up the hierarchy chain
+    //property real   availableWidth    ///< Width for control
+    //property var    missionItem       ///< Mission Item for editor
+
+    property real   _margin:        ScreenTools.defaultFontPixelWidth * 0.25
+
+    Column {
+        id: editorColumn
+
+        QGCLabel { text: "WIP" }
+    }
+}
diff --git a/src/MissionEditor/MissionEditor.qml b/src/MissionEditor/MissionEditor.qml
index 1389766..a71ce19 100644
--- a/src/MissionEditor/MissionEditor.qml
+++ b/src/MissionEditor/MissionEditor.qml
@@ -89,15 +89,6 @@ QGCView {
         }
     }
 
-    function addSurveyItem() {
-            var coordinate = editorMap.center
-            coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
-            coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
-            coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
-            var sequenceNumber = missionController.insertComplexMissionItem(coordinate, missionController.visualItems.count)
-            setCurrentItem(sequenceNumber)
-    }
-
     MapFitFunctions {
         id:                         mapFitFunctions
         map:                        editorMap
@@ -877,8 +868,9 @@ QGCView {
                             toggle:     true
                         },
                         {
-                            name:       "Pattern",
-                            iconSource: "/qmlimages/MapDrawShape.svg"
+                            name:               "Pattern",
+                            iconSource:         "/qmlimages/MapDrawShape.svg",
+                            dropPanelComponent: patternDropPanel
                         },
                         {
                             name:                   "Sync",
@@ -899,13 +891,8 @@ QGCView {
                     ]
 
                     onClicked: {
-                        switch (index) {
-                        case 0:
+                        if (index == 0) {
                             _addWaypointOnClick = checked
-                            break
-                        case 1:
-                            addSurveyItem()
-                            break
                         }
                     }
                 }
@@ -1084,6 +1071,7 @@ QGCView {
                         checked:        QGroundControl.flightMapSettings.mapType === text
                         text:           modelData
                         exclusiveGroup: _mapTypeButtonsExclusiveGroup
+
                         onClicked: {
                             QGroundControl.flightMapSettings.mapType = text
                             dropPanel.hide()
@@ -1093,4 +1081,33 @@ QGCView {
             }
         }
     }
+
+    Component {
+        id: patternDropPanel
+
+        ColumnLayout {
+            spacing:    ScreenTools.defaultFontPixelWidth * 0.5
+
+            QGCLabel { text: qsTr("Create complex pattern:") }
+
+            Repeater {
+                model: missionController.complexMissionItemNames
+
+                QGCButton {
+                    text:               modelData
+                    Layout.fillWidth:   true
+
+                    onClicked: {
+                        var coordinate = editorMap.center
+                        coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
+                        coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
+                        coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
+                        var sequenceNumber = missionController.insertComplexMissionItem(modelData, coordinate, missionController.visualItems.count)
+                        setCurrentItem(sequenceNumber)
+                        dropPanel.hide()
+                    }
+                }
+            }
+        } // Column
+    }
 } // QGCVIew
diff --git a/src/MissionEditor/MissionItemEditor.qml b/src/MissionEditor/MissionItemEditor.qml
index e9f4797..25b68ff 100644
--- a/src/MissionEditor/MissionItemEditor.qml
+++ b/src/MissionEditor/MissionItemEditor.qml
@@ -141,9 +141,7 @@ Rectangle {
         anchors.fill:       commandPicker
         visible:            missionItem.sequenceNumber == 0 || !missionItem.isCurrentItem || !missionItem.isSimpleItem
         verticalAlignment:  Text.AlignVCenter
-        text:               missionItem.sequenceNumber == 0 ?
-                                qsTr("Mission Settings") :
-                                (missionItem.isSimpleItem ? missionItem.commandName : qsTr("Survey"))
+        text:               missionItem.sequenceNumber == 0 ? qsTr("Mission Settings") : missionItem.commandName
         color:              _outerTextColor
     }
 
@@ -154,7 +152,7 @@ Rectangle {
         anchors.left:       parent.left
         anchors.top:        commandPicker.bottom
         height:             item ? item.height : 0
-        source:             missionItem.sequenceNumber == 0 ? "qrc:/qml/MissionSettingsEditor.qml" : (missionItem.isSimpleItem ? "qrc:/qml/SimpleItemEditor.qml" : "qrc:/qml/SurveyItemEditor.qml")
+        source:             missionItem.sequenceNumber == 0 ? "qrc:/qml/MissionSettingsEditor.qml" : missionItem.editorQml
 
         onLoaded: {
             item.visible = Qt.binding(function() { return _currentItem; })
diff --git a/src/MissionManager/FWLandingPattern.FactMetaData.json b/src/MissionManager/FWLandingPattern.FactMetaData.json
new file mode 100644
index 0000000..0d4f101
--- /dev/null
+++ b/src/MissionManager/FWLandingPattern.FactMetaData.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/src/MissionManager/FixedWingLandingComplexItem.cc b/src/MissionManager/FixedWingLandingComplexItem.cc
new file mode 100644
index 0000000..55fd5df
--- /dev/null
+++ b/src/MissionManager/FixedWingLandingComplexItem.cc
@@ -0,0 +1,182 @@
+/****************************************************************************
+ *
+ *   (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.
+ *
+ ****************************************************************************/
+
+#include "FixedWingLandingComplexItem.h"
+#include "JsonHelper.h"
+#include "MissionController.h"
+#include "QGCGeo.h"
+#include "QGroundControlQmlGlobal.h"
+
+#include <QPolygonF>
+
+QGC_LOGGING_CATEGORY(FixedWingLandingComplexItemLog, "FixedWingLandingComplexItemLog")
+
+const char* FixedWingLandingComplexItem::jsonComplexItemTypeValue = "fwLandingPattern";
+
+QMap<QString, FactMetaData*> FixedWingLandingComplexItem::_metaDataMap;
+
+FixedWingLandingComplexItem::FixedWingLandingComplexItem(Vehicle* vehicle, QObject* parent)
+    : ComplexMissionItem(vehicle, parent)
+    , _sequenceNumber(0)
+    , _dirty(false)
+{
+    _editorQml = "qrc:/qml/FWLandingPatternEditor.qml";
+
+    if (_metaDataMap.isEmpty()) {
+        _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/FWLandingPattern.FactMetaData.json"), NULL /* metaDataParent */);
+    }
+}
+
+int FixedWingLandingComplexItem::lastSequenceNumber(void) const
+{
+    return _sequenceNumber;
+}
+
+void FixedWingLandingComplexItem::setCoordinate(const QGeoCoordinate& coordinate)
+{
+    if (_coordinate != coordinate) {
+        _coordinate = coordinate;
+        emit coordinateChanged(_coordinate);
+    }
+}
+
+void FixedWingLandingComplexItem::setDirty(bool dirty)
+{
+    if (_dirty != dirty) {
+        _dirty = dirty;
+        emit dirtyChanged(_dirty);
+    }
+}
+
+void FixedWingLandingComplexItem::save(QJsonObject& saveObject) const
+{
+    saveObject[JsonHelper::jsonVersionKey] =                    1;
+    saveObject[VisualMissionItem::jsonTypeKey] =                VisualMissionItem::jsonTypeComplexItemValue;
+    saveObject[ComplexMissionItem::jsonComplexItemTypeKey] =    jsonComplexItemTypeValue;
+
+    // FIXME: Need real implementation
+}
+
+void FixedWingLandingComplexItem::setSequenceNumber(int sequenceNumber)
+{
+    if (_sequenceNumber != sequenceNumber) {
+        _sequenceNumber = sequenceNumber;
+        emit sequenceNumberChanged(sequenceNumber);
+        emit lastSequenceNumberChanged(lastSequenceNumber());
+    }
+}
+
+bool FixedWingLandingComplexItem::load(const QJsonObject& complexObject, int sequenceNumber, QString& errorString)
+{
+    // FIXME: Need real implementation
+    Q_UNUSED(complexObject);
+    Q_UNUSED(sequenceNumber);
+
+    errorString = "NYI";
+    return false;
+}
+
+double FixedWingLandingComplexItem::greatestDistanceTo(const QGeoCoordinate &other) const
+{
+    // FIXME: Need real implementation
+    Q_UNUSED(other);
+
+    double greatestDistance = 0.0;
+
+#if 0
+    for (int i=0; i<_gridPoints.count(); i++) {
+        QGeoCoordinate currentCoord = _gridPoints[i].value<QGeoCoordinate>();
+        double distance = currentCoord.distanceTo(other);
+        if (distance > greatestDistance) {
+            greatestDistance = distance;
+        }
+    }
+#endif
+
+    return greatestDistance;
+}
+
+void FixedWingLandingComplexItem::_setExitCoordinate(const QGeoCoordinate& coordinate)
+{
+    if (_exitCoordinate != coordinate) {
+        _exitCoordinate = coordinate;
+        emit exitCoordinateChanged(coordinate);
+    }
+}
+
+bool FixedWingLandingComplexItem::specifiesCoordinate(void) const
+{
+    return true;
+}
+
+QmlObjectListModel* FixedWingLandingComplexItem::getMissionItems(void) const
+{
+    // FIXME: Need real implementation
+    QmlObjectListModel* pMissionItems = new QmlObjectListModel;
+
+#if 0
+    int seqNum = _sequenceNumber;
+    for (int i=0; i<_gridPoints.count(); i++) {
+        QGeoCoordinate coord = _gridPoints[i].value<QGeoCoordinate>();
+        double altitude = _gridAltitudeFact.rawValue().toDouble();
+
+        MissionItem* item = new MissionItem(seqNum++,                       // sequence number
+                                            MAV_CMD_NAV_WAYPOINT,           // MAV_CMD
+                                            _gridAltitudeRelative ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL,  // MAV_FRAME
+                                            0.0, 0.0, 0.0, 0.0,             // param 1-4
+                                            coord.latitude(),
+                                            coord.longitude(),
+                                            altitude,
+                                            true,                           // autoContinue
+                                            false,                          // isCurrentItem
+                                            pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
+        pMissionItems->append(item);
+
+        if (_cameraTrigger && i == 0) {
+            // Turn on camera
+            MissionItem* item = new MissionItem(seqNum++,                       // sequence number
+                                                MAV_CMD_DO_SET_CAM_TRIGG_DIST,  // MAV_CMD
+                                                MAV_FRAME_MISSION,              // MAV_FRAME
+                                                _cameraTriggerDistanceFact.rawValue().toDouble(),   // trigger distance
+                                                0.0, 0.0, 0.0, 0.0, 0.0, 0.0,   // param 2-7
+                                                true,                           // autoContinue
+                                                false,                          // isCurrentItem
+                                                pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
+            pMissionItems->append(item);
+        }
+    }
+
+    if (_cameraTrigger) {
+        // Turn off camera
+        MissionItem* item = new MissionItem(seqNum++,                       // sequence number
+                                            MAV_CMD_DO_SET_CAM_TRIGG_DIST,  // MAV_CMD
+                                            MAV_FRAME_MISSION,              // MAV_FRAME
+                                            0.0,                            // trigger distance
+                                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0,   // param 2-7
+                                            true,                           // autoContinue
+                                            false,                          // isCurrentItem
+                                            pMissionItems);                 // parent - allow delete on pMissionItems to delete everthing
+        pMissionItems->append(item);
+    }
+#endif
+
+    return pMissionItems;
+}
+
+double FixedWingLandingComplexItem::complexDistance(void) const
+{
+    // FIXME: Need real implementation
+    return 0;
+}
+
+void FixedWingLandingComplexItem::setCruiseSpeed(double cruiseSpeed)
+{
+    // FIXME: Need real implementation
+    Q_UNUSED(cruiseSpeed);
+}
diff --git a/src/MissionManager/FixedWingLandingComplexItem.h b/src/MissionManager/FixedWingLandingComplexItem.h
new file mode 100644
index 0000000..0c9f76b
--- /dev/null
+++ b/src/MissionManager/FixedWingLandingComplexItem.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+ *
+ *   (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.
+ *
+ ****************************************************************************/
+
+#ifndef FixedWingLandingComplexItem_H
+#define FixedWingLandingComplexItem_H
+
+#include "ComplexMissionItem.h"
+#include "MissionItem.h"
+#include "Fact.h"
+#include "QGCLoggingCategory.h"
+
+Q_DECLARE_LOGGING_CATEGORY(FixedWingLandingComplexItemLog)
+
+class FixedWingLandingComplexItem : public ComplexMissionItem
+{
+    Q_OBJECT
+
+public:
+    FixedWingLandingComplexItem(Vehicle* vehicle, QObject* parent = NULL);
+
+    // Overrides from ComplexMissionItem
+
+    double              complexDistance     (void) const final;
+    int                 lastSequenceNumber  (void) const final;
+    QmlObjectListModel* getMissionItems     (void) const final;
+    bool                load                (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final;
+    double              greatestDistanceTo  (const QGeoCoordinate &other) const final;
+    void                setCruiseSpeed      (double cruiseSpeed) final;
+
+    // Overrides from VisualMissionItem
+
+    bool            dirty                   (void) const final { return _dirty; }
+    bool            isSimpleItem            (void) const final { return false; }
+    bool            isStandaloneCoordinate  (void) const final { return false; }
+    bool            specifiesCoordinate     (void) const final;
+    QString         commandDescription      (void) const final { return "Landing Pattern"; }
+    QString         commandName             (void) const final { return "Landing Pattern"; }
+    QString         abbreviation            (void) const final { return "L"; }
+    QGeoCoordinate  coordinate              (void) const final { return _coordinate; }
+    QGeoCoordinate  exitCoordinate          (void) const final { return _exitCoordinate; }
+    int             sequenceNumber          (void) const final { return _sequenceNumber; }
+    double          flightSpeed             (void) final { return std::numeric_limits<double>::quiet_NaN(); }
+
+    bool coordinateHasRelativeAltitude      (void) const final { return true; }
+    bool exitCoordinateHasRelativeAltitude  (void) const final { return true; }
+    bool exitCoordinateSameAsEntry          (void) const final { return true; }
+
+    void setDirty           (bool dirty) final;
+    void setCoordinate      (const QGeoCoordinate& coordinate) final;
+    void setSequenceNumber  (int sequenceNumber) final;
+    void save               (QJsonObject& saveObject) const final;
+
+    static const char* jsonComplexItemTypeValue;
+
+signals:
+
+private slots:
+
+private:
+    void _setExitCoordinate(const QGeoCoordinate& coordinate);
+
+    int             _sequenceNumber;
+    bool            _dirty;
+    QGeoCoordinate  _coordinate;
+    QGeoCoordinate  _exitCoordinate;
+
+    static QMap<QString, FactMetaData*> _metaDataMap;
+};
+
+#endif
diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc
index 71d2b6f..70011b7 100644
--- a/src/MissionManager/MissionController.cc
+++ b/src/MissionManager/MissionController.cc
@@ -16,6 +16,7 @@
 #include "QGCApplication.h"
 #include "SimpleMissionItem.h"
 #include "SurveyMissionItem.h"
+#include "FixedWingLandingComplexItem.h"
 #include "JsonHelper.h"
 #include "ParameterManager.h"
 #include "QGroundControlQmlGlobal.h"
@@ -59,7 +60,9 @@ MissionController::MissionController(QObject *parent)
     , _missionCruiseTime(0.0)
     , _missionMaxTelemetry(0.0)
 {
-
+    _surveyMissionItemName = tr("Survey");
+    _fwLandingMissionItemName = tr("Fixed Wing Landing");
+    _complexMissionItemNames << _surveyMissionItemName << _fwLandingMissionItemName;
 }
 
 MissionController::~MissionController()
@@ -218,12 +221,21 @@ int MissionController::insertSimpleMissionItem(QGeoCoordinate coordinate, int i)
     return newItem->sequenceNumber();
 }
 
-int MissionController::insertComplexMissionItem(QGeoCoordinate coordinate, int i)
+int MissionController::insertComplexMissionItem(QString itemName, QGeoCoordinate mapCenterCoordinate, int i)
 {
+    ComplexMissionItem* newItem;
+
     int sequenceNumber = _nextSequenceNumber();
-    SurveyMissionItem* newItem = new SurveyMissionItem(_activeVehicle, _visualItems);
+    if (itemName == _surveyMissionItemName) {
+        newItem = new SurveyMissionItem(_activeVehicle, _visualItems);
+    } else if (itemName == _fwLandingMissionItemName) {
+        newItem = new FixedWingLandingComplexItem(_activeVehicle, _visualItems);
+    } else {
+        qWarning() << "Internal error: Unknown complex item:" << itemName;
+        return sequenceNumber;
+    }
     newItem->setSequenceNumber(sequenceNumber);
-    newItem->setCoordinate(coordinate);
+    newItem->setCoordinate(mapCenterCoordinate);
     _initVisualItem(newItem);
 
     _visualItems->insert(i, newItem);
diff --git a/src/MissionManager/MissionController.h b/src/MissionManager/MissionController.h
index 5a341ad..f1b45fb 100644
--- a/src/MissionManager/MissionController.h
+++ b/src/MissionManager/MissionController.h
@@ -39,6 +39,8 @@ public:
     Q_PROPERTY(QmlObjectListModel*  complexVisualItems  READ complexVisualItems     NOTIFY complexVisualItemsChanged)
     Q_PROPERTY(QmlObjectListModel*  waypointLines       READ waypointLines          NOTIFY waypointLinesChanged)
 
+    Q_PROPERTY(QStringList          complexMissionItemNames MEMBER _complexMissionItemNames CONSTANT)
+
     Q_PROPERTY(double               missionDistance         READ missionDistance        NOTIFY missionDistanceChanged)
     Q_PROPERTY(double               missionTime             READ missionTime            NOTIFY missionTimeChanged)
     Q_PROPERTY(double               missionHoverDistance    READ missionHoverDistance   NOTIFY missionHoverDistanceChanged)
@@ -55,9 +57,11 @@ public:
     Q_INVOKABLE int insertSimpleMissionItem(QGeoCoordinate coordinate, int i);
 
     /// Add a new complex mission item to the list
+    ///     @param itemName: Name of complex item to create (from complexMissionItemNames)
+    ///     @param mapCenterCoordinate: coordinate for current center of map
     ///     @param i: index to insert at
     /// @return Sequence number for new item
-    Q_INVOKABLE int insertComplexMissionItem(QGeoCoordinate coordinate, int i);
+    Q_INVOKABLE int insertComplexMissionItem(QString itemName, QGeoCoordinate mapCenterCoordinate, int i);
 
     /// Loads the mission items from the specified file
     ///     @param[in] vehicle Vehicle we are loading items for
@@ -180,7 +184,10 @@ private:
     double              _missionHoverTime;
     double              _missionCruiseDistance;
     double              _missionCruiseTime;
-    double              _missionMaxTelemetry;
+    double              _missionMaxTelemetry;    
+    QString             _surveyMissionItemName;
+    QString             _fwLandingMissionItemName;
+    QStringList         _complexMissionItemNames;
 
     static const char*  _settingsGroup;
     static const char*  _jsonFileTypeValue;
diff --git a/src/MissionManager/SimpleMissionItem.cc b/src/MissionManager/SimpleMissionItem.cc
index 355a59c..5464ddf 100644
--- a/src/MissionManager/SimpleMissionItem.cc
+++ b/src/MissionManager/SimpleMissionItem.cc
@@ -64,6 +64,8 @@ SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, QObject* parent)
     , _syncingAltitudeRelativeToHomeAndFrame    (false)
     , _syncingHeadingDegreesAndParam4           (false)
 {
+    _editorQml = "qrc:/qml/SimpleItemEditor.qml";
+
     _altitudeRelativeToHomeFact.setRawValue(true);
 
     _setupMetaData();
diff --git a/src/MissionManager/SurveyMissionItem.cc b/src/MissionManager/SurveyMissionItem.cc
index 03a8f43..954fc3c 100644
--- a/src/MissionManager/SurveyMissionItem.cc
+++ b/src/MissionManager/SurveyMissionItem.cc
@@ -86,6 +86,8 @@ SurveyMissionItem::SurveyMissionItem(Vehicle* vehicle, QObject* parent)
     , _cameraResolutionHeightFact   (0, _cameraResolutionHeightFactName,    FactMetaData::valueTypeUint32)
     , _cameraFocalLengthFact        (0, _cameraFocalLengthFactName,         FactMetaData::valueTypeDouble)
 {
+    _editorQml = "qrc:/qml/SurveyItemEditor.qml";
+
     if (_metaDataMap.isEmpty()) {
         _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/Survey.FactMetaData.json"), NULL /* metaDataParent */);
     }
diff --git a/src/MissionManager/VisualMissionItem.h b/src/MissionManager/VisualMissionItem.h
index ab2612b..a4ad941 100644
--- a/src/MissionManager/VisualMissionItem.h
+++ b/src/MissionManager/VisualMissionItem.h
@@ -78,6 +78,7 @@ public:
     Q_PROPERTY(bool     specifiesCoordinate     READ specifiesCoordinate                                NOTIFY specifiesCoordinateChanged)      ///< Item is associated with a coordinate position
     Q_PROPERTY(bool     isStandaloneCoordinate  READ isStandaloneCoordinate                             NOTIFY isStandaloneCoordinateChanged)   ///< Waypoint line does not go through item
     Q_PROPERTY(bool     isSimpleItem            READ isSimpleItem                                       NOTIFY isSimpleItemChanged)             ///< Simple or Complex MissionItem
+    Q_PROPERTY(QString  editorQml               MEMBER _editorQml                                       CONSTANT)                               ///< Qml code for editing this item
 
     /// List of child mission items. Child mission item are subsequent mision items which do not specify a coordinate. They
     /// are shown next to the exitCoordinate indidcator in the ui.
@@ -161,6 +162,7 @@ protected:
     double      _altPercent;                ///< Percent of total altitude change in mission
     double      _azimuth;                   ///< Azimuth to previous waypoint
     double      _distance;                  ///< Distance to previous waypoint
+    QString     _editorQml;                 ///< Qml resource for editing item
 
     /// This is used to reference any subsequent mission items which do not specify a coordinate.
     QmlObjectListModel  _childItems;