Commit 82aa7678 authored by DonLakeFlyer's avatar DonLakeFlyer

Use a master controller for all Plan elements

Update the user model to a single controller instead of multiple
parent da022f97
...@@ -472,6 +472,7 @@ HEADERS += \ ...@@ -472,6 +472,7 @@ HEADERS += \
src/MissionManager/MissionManager.h \ src/MissionManager/MissionManager.h \
src/MissionManager/MissionSettingsItem.h \ src/MissionManager/MissionSettingsItem.h \
src/MissionManager/PlanElementController.h \ src/MissionManager/PlanElementController.h \
src/MissionManager/PlanMasterController.h \
src/MissionManager/QGCMapPolygon.h \ src/MissionManager/QGCMapPolygon.h \
src/MissionManager/RallyPoint.h \ src/MissionManager/RallyPoint.h \
src/MissionManager/RallyPointController.h \ src/MissionManager/RallyPointController.h \
...@@ -654,6 +655,7 @@ SOURCES += \ ...@@ -654,6 +655,7 @@ SOURCES += \
src/MissionManager/MissionManager.cc \ src/MissionManager/MissionManager.cc \
src/MissionManager/MissionSettingsItem.cc \ src/MissionManager/MissionSettingsItem.cc \
src/MissionManager/PlanElementController.cc \ src/MissionManager/PlanElementController.cc \
src/MissionManager/PlanMasterController.cc \
src/MissionManager/QGCMapPolygon.cc \ src/MissionManager/QGCMapPolygon.cc \
src/MissionManager/RallyPoint.cc \ src/MissionManager/RallyPoint.cc \
src/MissionManager/RallyPointController.cc \ src/MissionManager/RallyPointController.cc \
......
...@@ -38,14 +38,18 @@ QGCView { ...@@ -38,14 +38,18 @@ QGCView {
property bool activeVehicleJoystickEnabled: _activeVehicle ? _activeVehicle.joystickEnabled : false property bool activeVehicleJoystickEnabled: _activeVehicle ? _activeVehicle.joystickEnabled : false
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _planMasterController: masterController
property bool _mainIsMap: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_mainIsMapKey, true) : true property var _missionController: _planMasterController.missionController
property bool _isPipVisible: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_PIPVisibleKey, true) : false property var _geoFenceController: _planMasterController.geoFenceController
property real _savedZoomLevel: 0 property var _rallyPointController: _planMasterController.rallyPointController
property real _margins: ScreenTools.defaultFontPixelWidth / 2 property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property real _pipSize: mainWindow.width * 0.2 property bool _mainIsMap: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_mainIsMapKey, true) : true
property alias _guidedController: guidedActionsController property bool _isPipVisible: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_PIPVisibleKey, true) : false
property alias _altitudeSlider: altitudeSlider property real _savedZoomLevel: 0
property real _margins: ScreenTools.defaultFontPixelWidth / 2
property real _pipSize: mainWindow.width * 0.2
property alias _guidedController: guidedActionsController
property alias _altitudeSlider: altitudeSlider
readonly property bool isBackgroundDark: _mainIsMap ? (_flightMap ? _flightMap.isSatelliteMap : true) : true readonly property bool isBackgroundDark: _mainIsMap ? (_flightMap ? _flightMap.isSatelliteMap : true) : true
...@@ -92,20 +96,14 @@ QGCView { ...@@ -92,20 +96,14 @@ QGCView {
} }
} }
MissionController { PlanElemementMasterController {
id: flyMissionController id: masterController
Component.onCompleted: start(false /* editMode */) Component.onCompleted: start(false /* editMode */)
onResumeMissionReady: guidedActionsController.confirmAction(guidedActionsController.actionResumeMissionReady)
}
GeoFenceController {
id: flyGeoFenceController
Component.onCompleted: start(false /* editMode */)
} }
RallyPointController { Connections {
id: flyRallyPointController target: _missionController
Component.onCompleted: start(false /* editMode */) onResumeMissionReady: guidedActionsController.confirmAction(guidedActionsController.actionResumeMissionReady)
} }
MessageDialog { MessageDialog {
...@@ -116,7 +114,7 @@ QGCView { ...@@ -116,7 +114,7 @@ QGCView {
} }
Connections { Connections {
target: QGroundControl.multiVehicleManager target: QGroundControl.multiVehicleManager
onActiveVehicleChanged: px4JoystickCheck() onActiveVehicleChanged: px4JoystickCheck()
} }
...@@ -149,7 +147,7 @@ QGCView { ...@@ -149,7 +147,7 @@ QGCView {
vehicleWasArmed = true vehicleWasArmed = true
} }
} else { } else {
if (promptForMissionRemove && (flyMissionController.containsItems || flyGeoFenceController.containsItems || flyRallyPointController.containsItems)) { if (promptForMissionRemove && (_missionController.containsItems || _geoFenceController.containsItems || _rallyPointController.containsItems)) {
root.showDialog(removeMissionDialogComponent, qsTr("Flight complete"), showDialogDefaultWidth, StandardButton.No | StandardButton.Yes) root.showDialog(removeMissionDialogComponent, qsTr("Flight complete"), showDialogDefaultWidth, StandardButton.No | StandardButton.Yes)
} }
promptForMissionRemove = false promptForMissionRemove = false
...@@ -169,9 +167,9 @@ QGCView { ...@@ -169,9 +167,9 @@ QGCView {
message: qsTr("Do you want to remove the mission from the vehicle?") message: qsTr("Do you want to remove the mission from the vehicle?")
function accept() { function accept() {
flyMissionController.removeAllFromVehicle() _missionController.removeAllFromVehicle()
flyGeoFenceController.removeAllFromVehicle() _geoFenceController.removeAllFromVehicle()
flyRallyPointController.removeAllFromVehicle() _rallyPointController.removeAllFromVehicle()
hideDialog() hideDialog()
} }
...@@ -214,9 +212,7 @@ QGCView { ...@@ -214,9 +212,7 @@ QGCView {
FlightDisplayViewMap { FlightDisplayViewMap {
id: _flightMap id: _flightMap
anchors.fill: parent anchors.fill: parent
missionController: flyMissionController planMasterController: masterController
geoFenceController: flyGeoFenceController
rallyPointController: flyRallyPointController
guidedActionsController: _guidedController guidedActionsController: _guidedController
flightWidgets: flightDisplayViewWidgets flightWidgets: flightDisplayViewWidgets
rightPanelWidth: ScreenTools.defaultFontPixelHeight * 9 rightPanelWidth: ScreenTools.defaultFontPixelHeight * 9
...@@ -320,7 +316,7 @@ QGCView { ...@@ -320,7 +316,7 @@ QGCView {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
qgcView: root qgcView: root
useLightColors: isBackgroundDark useLightColors: isBackgroundDark
missionController: _flightMap.missionController missionController: _missionController
visible: singleVehicleView.checked visible: singleVehicleView.checked
} }
...@@ -511,7 +507,7 @@ QGCView { ...@@ -511,7 +507,7 @@ QGCView {
GuidedActionsController { GuidedActionsController {
id: guidedActionsController id: guidedActionsController
missionController: flyMissionController missionController: _missionController
confirmDialog: guidedActionConfirm confirmDialog: guidedActionConfirm
z: _flightVideoPipControl.z + 1 z: _flightVideoPipControl.z + 1
......
...@@ -34,9 +34,7 @@ FlightMap { ...@@ -34,9 +34,7 @@ FlightMap {
property alias scaleState: mapScale.state property alias scaleState: mapScale.state
// The following properties must be set by the consumer // The following properties must be set by the consumer
property var missionController property var planMasterController
property var geoFenceController
property var rallyPointController
property var guidedActionsController property var guidedActionsController
property var flightWidgets property var flightWidgets
property var rightPanelWidth property var rightPanelWidth
...@@ -44,6 +42,10 @@ FlightMap { ...@@ -44,6 +42,10 @@ FlightMap {
property rect centerViewport: Qt.rect(0, 0, width, height) property rect centerViewport: Qt.rect(0, 0, width, height)
property var _planMasterController: planMasterController
property var _missionController: _planMasterController.missionController
property var _geoFenceController: _planMasterController.geoFenceController
property var _rallyPointController: _planMasterController.rallyPointController
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
property var _gotoHereCoordinate: QtPositioning.coordinate() property var _gotoHereCoordinate: QtPositioning.coordinate()
...@@ -132,10 +134,10 @@ FlightMap { ...@@ -132,10 +134,10 @@ FlightMap {
QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } QGCMapPalette { id: mapPal; lightColors: isSatelliteMap }
Connections { Connections {
target: missionController target: _missionController
onNewItemsFromVehicle: { onNewItemsFromVehicle: {
var visualItems = missionController.visualItems var visualItems = _missionController.visualItems
if (visualItems && visualItems.count != 1) { if (visualItems && visualItems.count != 1) {
mapFitFunctions.fitMapViewportToMissionItems() mapFitFunctions.fitMapViewportToMissionItems()
firstVehiclePositionReceived = true firstVehiclePositionReceived = true
...@@ -151,9 +153,7 @@ FlightMap { ...@@ -151,9 +153,7 @@ FlightMap {
id: mapFitFunctions id: mapFitFunctions
map: _flightMap map: _flightMap
usePlannedHomePosition: false usePlannedHomePosition: false
mapMissionController: missionController planMasterController: _planMasterController
mapGeoFenceController: geoFenceController
mapRallyPointController: rallyPointController
property real leftToolWidth: toolStrip.x + toolStrip.width property real leftToolWidth: toolStrip.x + toolStrip.width
} }
...@@ -188,7 +188,7 @@ FlightMap { ...@@ -188,7 +188,7 @@ FlightMap {
// Add the mission item visuals to the map // Add the mission item visuals to the map
Repeater { Repeater {
model: _mainIsMap ? missionController.visualItems : 0 model: _mainIsMap ? _missionController.visualItems : 0
delegate: MissionItemMapVisual { delegate: MissionItemMapVisual {
map: flightMap map: flightMap
...@@ -198,12 +198,12 @@ FlightMap { ...@@ -198,12 +198,12 @@ FlightMap {
// Add lines between waypoints // Add lines between waypoints
MissionLineView { MissionLineView {
model: _mainIsMap ? missionController.waypointLines : 0 model: _mainIsMap ? _missionController.waypointLines : 0
} }
GeoFenceMapVisuals { GeoFenceMapVisuals {
map: flightMap map: flightMap
myGeoFenceController: geoFenceController myGeoFenceController: _geoFenceController
interactive: false interactive: false
planView: false planView: false
homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : undefined homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : undefined
...@@ -211,7 +211,7 @@ FlightMap { ...@@ -211,7 +211,7 @@ FlightMap {
// Rally points on map // Rally points on map
MapItemView { MapItemView {
model: rallyPointController.points model: _rallyPointController.points
delegate: MapQuickItem { delegate: MapQuickItem {
id: itemIndicator id: itemIndicator
...@@ -243,7 +243,7 @@ FlightMap { ...@@ -243,7 +243,7 @@ FlightMap {
// Camera points // Camera points
MapItemView { MapItemView {
model: missionController.cameraPoints model: _missionController.cameraPoints
delegate: CameraTriggerIndicator { delegate: CameraTriggerIndicator {
coordinate: object.coordinate coordinate: object.coordinate
......
...@@ -16,9 +16,11 @@ import QGroundControl 1.0 ...@@ -16,9 +16,11 @@ import QGroundControl 1.0
Item { Item {
property var map property var map
property bool usePlannedHomePosition ///< true: planned home position used for calculations, false: vehicle home position use for calculations property bool usePlannedHomePosition ///< true: planned home position used for calculations, false: vehicle home position use for calculations
property var mapGeoFenceController property var planMasterController
property var mapMissionController
property var mapRallyPointController property var _missionController: planMasterController.missionController
property var _geoFenceController: planMasterController.geoFenceController
property var _rallyPointController: planMasterController.rallyPointController
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
...@@ -26,7 +28,7 @@ Item { ...@@ -26,7 +28,7 @@ Item {
var homePosition = QtPositioning.coordinate() var homePosition = QtPositioning.coordinate()
var activeVehicle = QGroundControl.multiVehicleManager.activeVehicle var activeVehicle = QGroundControl.multiVehicleManager.activeVehicle
if (usePlannedHomePosition) { if (usePlannedHomePosition) {
homePosition = mapMissionController.visualItems.get(0).coordinate homePosition = _missionController.visualItems.get(0).coordinate
} else if (activeVehicle) { } else if (activeVehicle) {
homePosition = activeVehicle.homePosition homePosition = activeVehicle.homePosition
} }
...@@ -92,8 +94,8 @@ Item { ...@@ -92,8 +94,8 @@ Item {
if (homePosition.isValid) { if (homePosition.isValid) {
coordList.push(homePosition) coordList.push(homePosition)
} }
for (var i=1; i<mapMissionController.visualItems.count; i++) { for (var i=1; i<_missionController.visualItems.count; i++) {
var missionItem = mapMissionController.visualItems.get(i) var missionItem = _missionController.visualItems.get(i)
if (missionItem.specifiesCoordinate && !missionItem.isStandaloneCoordinate) { if (missionItem.specifiesCoordinate && !missionItem.isStandaloneCoordinate) {
coordList.push(missionItem.coordinate) coordList.push(missionItem.coordinate)
} }
...@@ -101,7 +103,7 @@ Item { ...@@ -101,7 +103,7 @@ Item {
} }
function fitMapViewportToMissionItems() { function fitMapViewportToMissionItems() {
if (!mapMissionController.visualItems) { if (!_missionController.visualItems) {
// Being called prior to controller.start // Being called prior to controller.start
return return
} }
...@@ -112,16 +114,16 @@ Item { ...@@ -112,16 +114,16 @@ Item {
function addFenceItemCoordsForFit(coordList) { function addFenceItemCoordsForFit(coordList) {
var homePosition = fitHomePosition() var homePosition = fitHomePosition()
if (homePosition.isValid && mapGeoFenceController.circleEnabled) { if (homePosition.isValid && _geoFenceController.circleEnabled) {
var azimuthList = [ 0, 180, 90, 270 ] var azimuthList = [ 0, 180, 90, 270 ]
for (var i=0; i<azimuthList.length; i++) { for (var i=0; i<azimuthList.length; i++) {
var edgeCoordinate = homePosition.atDistanceAndAzimuth(mapGeoFenceController.circleRadius, azimuthList[i]) var edgeCoordinate = homePosition.atDistanceAndAzimuth(_geoFenceController.circleRadius, azimuthList[i])
coordList.push(edgeCoordinate) coordList.push(edgeCoordinate)
} }
} }
if (mapGeoFenceController.polygonEnabled && mapGeoFenceController.mapPolygon.path.count > 2) { if (_geoFenceController.polygonEnabled && _geoFenceController.mapPolygon.path.count > 2) {
for (var i=0; i<mapGeoFenceController.mapPolygon.path.count; i++) { for (var i=0; i<_geoFenceController.mapPolygon.path.count; i++) {
coordList.push(mapGeoFenceController.mapPolygon.path[i]) coordList.push(_geoFenceController.mapPolygon.path[i])
} }
} }
} }
...@@ -133,8 +135,8 @@ Item { ...@@ -133,8 +135,8 @@ Item {
} }
function addRallyItemCoordsForFit(coordList) { function addRallyItemCoordsForFit(coordList) {
for (var i=0; i<mapRallyPointController.points.count; i++) { for (var i=0; i<_rallyPointController.points.count; i++) {
coordList.push(mapRallyPointController.points.get(i).coordinate) coordList.push(_rallyPointController.points.get(i).coordinate)
} }
} }
...@@ -145,7 +147,7 @@ Item { ...@@ -145,7 +147,7 @@ Item {
} }
function fitMapViewportToAllItems() { function fitMapViewportToAllItems() {
if (!mapMissionController.visualItems) { if (!_missionController.visualItems) {
// Being called prior to controller.start // Being called prior to controller.start
return return
} }
......
...@@ -125,7 +125,7 @@ bool JsonHelper::parseEnum(const QJsonObject& jsonObject, QStringList& enumStrin ...@@ -125,7 +125,7 @@ bool JsonHelper::parseEnum(const QJsonObject& jsonObject, QStringList& enumStrin
return true; return true;
} }
bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc) bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QString& errorString)
{ {
QJsonParseError error; QJsonParseError error;
...@@ -192,6 +192,15 @@ bool JsonHelper::validateQGCJsonFile(const QJsonObject& jsonObject, ...@@ -192,6 +192,15 @@ bool JsonHelper::validateQGCJsonFile(const QJsonObject& jsonObject,
return true; return true;
} }
void JsonHelper::saveQGCJsonFileHeader(QJsonObject& jsonObject,
const QString& fileType,
int version)
{
jsonObject[jsonGroundStationKey] = jsonGroundStationValue;
jsonObject[jsonFileTypeKey] = fileType;
jsonObject[jsonVersionKey] = version;
}
bool JsonHelper::loadGeoCoordinateArray(const QJsonValue& jsonValue, bool JsonHelper::loadGeoCoordinateArray(const QJsonValue& jsonValue,
bool altitudeRequired, bool altitudeRequired,
QVariantList& rgVarPoints, QVariantList& rgVarPoints,
......
...@@ -20,9 +20,15 @@ class JsonHelper ...@@ -20,9 +20,15 @@ class JsonHelper
{ {
public: public:
/// Determines is the specified data is a json file /// Determines is the specified data is a json file
/// @param jsonDoc Returned json document if json file
/// @return true: file is json, false: file is not json /// @return true: file is json, false: file is not json
static bool isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc); static bool isJsonFile(const QByteArray& bytes, ///< json bytes
QJsonDocument& jsonDoc, ///< returned json document
QString& errorString); ///< error on parse failure
/// Saves the standard file header the json object
static void saveQGCJsonFileHeader(QJsonObject& jsonObject, ///< root json object
const QString& fileType, ///< file type for file
int version); ///< version number for file
/// Validates the standard parts of a QGC json file: /// Validates the standard parts of a QGC json file:
/// jsonFileTypeKey - Required and checked to be equal to expectedFileType /// jsonFileTypeKey - Required and checked to be equal to expectedFileType
......
...@@ -89,13 +89,15 @@ void GeoFenceController::_signalAll(void) ...@@ -89,13 +89,15 @@ void GeoFenceController::_signalAll(void)
emit dirtyChanged(dirty()); emit dirtyChanged(dirty());
} }
void GeoFenceController::_activeVehicleBeingRemoved(void) void GeoFenceController::activeVehicleBeingRemoved(void)
{ {
_activeVehicle->geoFenceManager()->disconnect(this); _activeVehicle->geoFenceManager()->disconnect(this);
_activeVehicle = NULL;
} }
void GeoFenceController::_activeVehicleSet(void) void GeoFenceController::activeVehicleSet(Vehicle* vehicle)
{ {
_activeVehicle = vehicle;
GeoFenceManager* geoFenceManager = _activeVehicle->geoFenceManager(); GeoFenceManager* geoFenceManager = _activeVehicle->geoFenceManager();
connect(geoFenceManager, &GeoFenceManager::breachReturnSupportedChanged, this, &GeoFenceController::breachReturnSupportedChanged); connect(geoFenceManager, &GeoFenceManager::breachReturnSupportedChanged, this, &GeoFenceController::breachReturnSupportedChanged);
connect(geoFenceManager, &GeoFenceManager::circleEnabledChanged, this, &GeoFenceController::circleEnabledChanged); connect(geoFenceManager, &GeoFenceManager::circleEnabledChanged, this, &GeoFenceController::circleEnabledChanged);
...@@ -112,97 +114,40 @@ void GeoFenceController::_activeVehicleSet(void) ...@@ -112,97 +114,40 @@ void GeoFenceController::_activeVehicleSet(void)
_signalAll(); _signalAll();
} }
bool GeoFenceController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorString) bool GeoFenceController::load(const QJsonObject& json, QString& errorString)
{ {
QJsonObject json = jsonDoc.object(); QString errorStr;
QString errorMessage = tr("GeoFence: %1");
int fileVersion; if (json.contains(_jsonBreachReturnKey) &&
if (!JsonHelper::validateQGCJsonFile(json, !JsonHelper::loadGeoCoordinate(json[_jsonBreachReturnKey], false /* altitudeRequired */, _breachReturnPoint, errorStr)) {
_jsonFileTypeValue, // expected file type errorString = errorMessage.arg(errorStr);
1, // minimum supported version
1, // maximum supported version
fileVersion,
errorString)) {
return false; return false;
} }
if (!_activeVehicle->parameterManager()->loadFromJson(json, false /* required */, errorString)) { if (!_mapPolygon.loadFromJson(json, true, errorStr)) {
return false; errorString = errorMessage.arg(errorStr);
}
if (json.contains(_jsonBreachReturnKey)
&& !JsonHelper::loadGeoCoordinate(json[_jsonBreachReturnKey], false /* altitudeRequired */, _breachReturnPoint, errorString)) {
return false;
}
if (!_mapPolygon.loadFromJson(json, true, errorString)) {
return false; return false;
} }
_mapPolygon.setDirty(false); _mapPolygon.setDirty(false);
setDirty(false);
return true;
}
void GeoFenceController::loadFromFile(const QString& filename)
{
QString errorString;
if (filename.isEmpty()) {
return;
}
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorString = file.errorString() + QStringLiteral(" ") + filename;
} else {
QJsonDocument jsonDoc;
QByteArray bytes = file.readAll();
_loadJsonFile(jsonDoc, errorString);
}
if (!errorString.isEmpty()) {
qgcApp()->showMessage(errorString);
}
_signalAll(); _signalAll();
setDirty(true);
return true;
} }
void GeoFenceController::saveToFile(const QString& filename) void GeoFenceController::save(QJsonObject& json)
{ {
if (filename.isEmpty()) { json[JsonHelper::jsonVersionKey] = 1;
return;
}
QString fenceFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
fenceFilename += QString(".%1").arg(AppSettings::fenceFileExtension);
}
QFile file(fenceFilename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(file.errorString());
} else {
QJsonObject fenceFileObject; // top level json object
fenceFileObject[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
fenceFileObject[JsonHelper::jsonVersionKey] = 1;
fenceFileObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue;
if (_breachReturnPoint.isValid()) {
QJsonValue jsonBreachReturn; QJsonValue jsonBreachReturn;
JsonHelper::saveGeoCoordinate(_breachReturnPoint, false /* writeAltitude */, jsonBreachReturn); JsonHelper::saveGeoCoordinate(_breachReturnPoint, false /* writeAltitude */, jsonBreachReturn);
fenceFileObject[_jsonBreachReturnKey] = jsonBreachReturn; json[_jsonBreachReturnKey] = jsonBreachReturn;
_mapPolygon.saveToJson(fenceFileObject);
QJsonDocument saveDoc(fenceFileObject);
file.write(saveDoc.toJson());
} }
setDirty(false); _mapPolygon.saveToJson(json);
} }
void GeoFenceController::removeAll(void) void GeoFenceController::removeAll(void)
...@@ -323,11 +268,6 @@ void GeoFenceController::_loadComplete(const QGeoCoordinate& breachReturn, const ...@@ -323,11 +268,6 @@ void GeoFenceController::_loadComplete(const QGeoCoordinate& breachReturn, const
emit loadComplete(); emit loadComplete();
} }
QString GeoFenceController::fileExtension(void) const
{
return AppSettings::fenceFileExtension;
}
bool GeoFenceController::containsItems(void) const bool GeoFenceController::containsItems(void) const
{ {
return _mapPolygon.count() > 2; return _mapPolygon.count() > 2;
......
...@@ -46,18 +46,18 @@ public: ...@@ -46,18 +46,18 @@ public:
void start (bool editMode) final; void start (bool editMode) final;
void startStaticActiveVehicle (Vehicle* vehicle) final; void startStaticActiveVehicle (Vehicle* vehicle) final;
void save (QJsonObject& json) final;
bool load (const QJsonObject& json, QString& errorString) final;
void loadFromVehicle (void) final; void loadFromVehicle (void) final;
void sendToVehicle (void) final; void sendToVehicle (void) final;
void loadFromFile (const QString& filename) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final; void removeAll (void) final;
void removeAllFromVehicle (void) final; void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final; bool syncInProgress (void) const final;
bool dirty (void) const final; bool dirty (void) const final;
void setDirty (bool dirty) final; void setDirty (bool dirty) final;
bool containsItems (void) const final; bool containsItems (void) const final;
void activeVehicleBeingRemoved (void) final;
QString fileExtension(void) const final; void activeVehicleSet (Vehicle* vehicle) final;
bool circleEnabled (void) const; bool circleEnabled (void) const;
Fact* circleRadiusFact (void) const; Fact* circleRadiusFact (void) const;
...@@ -95,10 +95,6 @@ private slots: ...@@ -95,10 +95,6 @@ private slots:
private: private:
void _init(void); void _init(void);
void _signalAll(void); void _signalAll(void);
bool _loadJsonFile(QJsonDocument& jsonDoc, QString& errorString);
void _activeVehicleBeingRemoved(void) final;
void _activeVehicleSet(void) final;
bool _dirty; bool _dirty;
QGCMapPolygon _mapPolygon; QGCMapPolygon _mapPolygon;
......
...@@ -335,40 +335,7 @@ void MissionController::removeAll(void) ...@@ -335,40 +335,7 @@ void MissionController::removeAll(void)
_addMissionSettings(_activeVehicle, _visualItems, false /* addToCenter */); _addMissionSettings(_activeVehicle, _visualItems, false /* addToCenter */);
_initAllVisualItems(); _initAllVisualItems();
_visualItems->setDirty(true); _visualItems->setDirty(true);
_resetMissionFlightStatus(); _resetMissionFlightStatus();
}
}
bool MissionController::_loadJsonMissionFile(Vehicle* vehicle, const QByteArray& bytes, QmlObjectListModel* visualItems, QString& errorString)
{
QJsonParseError jsonParseError;
QJsonDocument jsonDoc(QJsonDocument::fromJson(bytes, &jsonParseError));
if (jsonParseError.error != QJsonParseError::NoError) {
errorString = jsonParseError.errorString();
return false;
}
QJsonObject json = jsonDoc.object();
// V1 file format has no file type key and version key is string. Convert to new format.
if (!json.contains(JsonHelper::jsonFileTypeKey)) {
json[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
}
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
2, // maximum supported version
fileVersion,
errorString)) {
return false;
}
if (fileVersion == 1) {
return _loadJsonMissionFileV1(vehicle, json, visualItems, errorString);
} else {
return _loadJsonMissionFileV2(vehicle, json, visualItems, errorString);
} }
} }
...@@ -612,6 +579,32 @@ bool MissionController::_loadJsonMissionFileV2(Vehicle* vehicle, const QJsonObje ...@@ -612,6 +579,32 @@ bool MissionController::_loadJsonMissionFileV2(Vehicle* vehicle, const QJsonObje
return true; return true;
} }
#if 0
bool MissionController::_loadItemsFromJson(const QJsonObject& json, QmlObjectListModel* visualItems, QString& errorString)
{
// V1 file format has no file type key and version key is string. Convert to new format.
if (!json.contains(JsonHelper::jsonFileTypeKey)) {
json[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue;
}
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
2, // maximum supported version
fileVersion,
errorString)) {
return false;
}
if (fileVersion == 1) {
return _loadJsonMissionFileV1(_activeVehicle, json, visualItems, errorString);
} else {
return _loadJsonMissionFileV2(_activeVehicle, json, visualItems, errorString);
}
}
#endif
bool MissionController::_loadTextMissionFile(Vehicle* vehicle, QTextStream& stream, QmlObjectListModel* visualItems, QString& errorString) bool MissionController::_loadTextMissionFile(Vehicle* vehicle, QTextStream& stream, QmlObjectListModel* visualItems, QString& errorString)
{ {
bool addPlannedHomePosition = false; bool addPlannedHomePosition = false;
...@@ -662,12 +655,15 @@ bool MissionController::_loadTextMissionFile(Vehicle* vehicle, QTextStream& stre ...@@ -662,12 +655,15 @@ bool MissionController::_loadTextMissionFile(Vehicle* vehicle, QTextStream& stre
return true; return true;
} }
void MissionController::loadFromFile(const QString& filename) bool MissionController::load(const QJsonObject& json, QString& errorString)
{ {
QmlObjectListModel* newVisualItems = NULL; QString errorStr;
QString errorMessage = tr("Mission: %1");
QmlObjectListModel* newVisualItems = new QmlObjectListModel(this);
if (!loadItemsFromFile(_activeVehicle, filename, &newVisualItems)) { if (!_loadJsonMissionFileV2(_activeVehicle, json, newVisualItems, errorStr)) {
return; errorString = errorMessage.arg(errorStr);
return false;
} }
if (_visualItems) { if (_visualItems) {
...@@ -690,117 +686,54 @@ void MissionController::loadFromFile(const QString& filename) ...@@ -690,117 +686,54 @@ void MissionController::loadFromFile(const QString& filename)
// Needs a sync to vehicle // Needs a sync to vehicle
setDirty(true); setDirty(true);
} }
}
bool MissionController::loadItemsFromFile(Vehicle* vehicle, const QString& filename, QmlObjectListModel** visualItems)
{
*visualItems = NULL;
QString errorString;
if (filename.isEmpty()) {
return false;
}
*visualItems = new QmlObjectListModel();
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorString = file.errorString() + QStringLiteral(" ") + filename;
} else {
QByteArray bytes = file.readAll();
QTextStream stream(&bytes);
QString firstLine = stream.readLine();
if (firstLine.contains(QRegExp("QGC.*WPL"))) {
stream.seek(0);
_loadTextMissionFile(vehicle, stream, *visualItems, errorString);
} else {
_loadJsonMissionFile(vehicle, bytes, *visualItems, errorString);
}
}
if (!errorString.isEmpty()) {
(*visualItems)->deleteLater();
qgcApp()->showMessage(errorString);
return false;
}
return true; return true;
} }
void MissionController::saveToFile(const QString& filename) void MissionController::save(QJsonObject& json)
{ {
if (filename.isEmpty()) { json[JsonHelper::jsonVersionKey] = _missionFileVersion;
return;
}
QString missionFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
missionFilename += QString(".%1").arg(AppSettings::missionFileExtension);
}
QFile file(missionFilename); // Mission settings
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { MissionSettingsItem* settingsItem = _visualItems->value<MissionSettingsItem*>(0);
qgcApp()->showMessage(tr("Mission save %1 : %2").arg(filename).arg(file.errorString())); if (!settingsItem) {
} else { qWarning() << "First item is not MissionSettingsItem";
QJsonObject missionFileObject; // top level json object return;
}
missionFileObject[JsonHelper::jsonVersionKey] = _missionFileVersion; QJsonValue coordinateValue;
missionFileObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue; JsonHelper::saveGeoCoordinate(settingsItem->coordinate(), true /* writeAltitude */, coordinateValue);
json[_jsonPlannedHomePositionKey] = coordinateValue;
json[_jsonFirmwareTypeKey] = _activeVehicle->firmwareType();
json[_jsonVehicleTypeKey] = _activeVehicle->vehicleType();
json[_jsonCruiseSpeedKey] = _activeVehicle->defaultCruiseSpeed();
json[_jsonHoverSpeedKey] = _activeVehicle->defaultHoverSpeed();
// Mission settings // Save the visual items
MissionSettingsItem* settingsItem = _visualItems->value<MissionSettingsItem*>(0); QJsonArray rgJsonMissionItems;
if (!settingsItem) { for (int i=0; i<_visualItems->count(); i++) {
qWarning() << "First item is not MissionSettingsItem"; VisualMissionItem* visualItem = qobject_cast<VisualMissionItem*>(_visualItems->get(i));
return;
}
QJsonValue coordinateValue;
JsonHelper::saveGeoCoordinate(settingsItem->coordinate(), true /* writeAltitude */, coordinateValue);
missionFileObject[_jsonPlannedHomePositionKey] = coordinateValue;
missionFileObject[_jsonFirmwareTypeKey] = _activeVehicle->firmwareType();
missionFileObject[_jsonVehicleTypeKey] = _activeVehicle->vehicleType();
missionFileObject[_jsonCruiseSpeedKey] = _activeVehicle->defaultCruiseSpeed();
missionFileObject[_jsonHoverSpeedKey] = _activeVehicle->defaultHoverSpeed();
// Save the visual items visualItem->save(rgJsonMissionItems);
}
QJsonArray rgJsonMissionItems; // Mission settings has a special case for end mission action
for (int i=0; i<_visualItems->count(); i++) { if (settingsItem) {
VisualMissionItem* visualItem = qobject_cast<VisualMissionItem*>(_visualItems->get(i)); QList<MissionItem*> rgMissionItems;
visualItem->save(rgJsonMissionItems); if (_convertToMissionItems(_visualItems, rgMissionItems, this /* missionItemParent */)) {
QJsonObject saveObject;
MissionItem* missionItem = rgMissionItems[rgMissionItems.count() - 1];
missionItem->save(saveObject);
rgJsonMissionItems.append(saveObject);
} }
for (int i=0; i<rgMissionItems.count(); i++) {
// Mission settings has a special case for end mission action rgMissionItems[i]->deleteLater();
if (settingsItem) {
QList<MissionItem*> rgMissionItems;
if (_convertToMissionItems(_visualItems, rgMissionItems, this /* missionItemParent */)) {
QJsonObject saveObject;
MissionItem* missionItem = rgMissionItems[rgMissionItems.count() - 1];
missionItem->save(saveObject);
rgJsonMissionItems.append(saveObject);
}
for (int i=0; i<rgMissionItems.count(); i++) {
rgMissionItems[i]->deleteLater();
}
} }
missionFileObject[_jsonItemsKey] = rgJsonMissionItems;
QJsonDocument saveDoc(missionFileObject);
file.write(saveDoc.toJson());
} }
// If we are connected to a real vehicle, don't clear dirty bit on saving to file since vehicle is still out of date json[_jsonItemsKey] = rgJsonMissionItems;
if (_activeVehicle->isOfflineEditingVehicle()) {
_visualItems->setDirty(false);
}
} }
void MissionController::_calcPrevWaypointValues(double homeAlt, VisualMissionItem* currentItem, VisualMissionItem* prevItem, double* azimuth, double* distance, double* altDifference) void MissionController::_calcPrevWaypointValues(double homeAlt, VisualMissionItem* currentItem, VisualMissionItem* prevItem, double* azimuth, double* distance, double* altDifference)
...@@ -1320,7 +1253,7 @@ void MissionController::_itemCommandChanged(void) ...@@ -1320,7 +1253,7 @@ void MissionController::_itemCommandChanged(void)
_recalcWaypointLines(); _recalcWaypointLines();
} }
void MissionController::_activeVehicleBeingRemoved(void) void MissionController::activeVehicleBeingRemoved(void)
{ {
qCDebug(MissionControllerLog) << "MissionController::_activeVehicleBeingRemoved"; qCDebug(MissionControllerLog) << "MissionController::_activeVehicleBeingRemoved";
...@@ -1337,10 +1270,14 @@ void MissionController::_activeVehicleBeingRemoved(void) ...@@ -1337,10 +1270,14 @@ void MissionController::_activeVehicleBeingRemoved(void)
// We always remove all items on vehicle change. This leaves a user model hole: // We always remove all items on vehicle change. This leaves a user model hole:
// If the user has unsaved changes in the Plan view they will lose them // If the user has unsaved changes in the Plan view they will lose them
removeAll(); removeAll();
_activeVehicle = NULL;
} }
void MissionController::_activeVehicleSet(void) void MissionController::activeVehicleSet(Vehicle* activeVehicle)
{ {
_activeVehicle = activeVehicle;
// We always remove all items on vehicle change. This leaves a user model hole: // We always remove all items on vehicle change. This leaves a user model hole:
// If the user has unsaved changes in the Plan view they will lose them // If the user has unsaved changes in the Plan view they will lose them
removeAll(); removeAll();
...@@ -1529,11 +1466,6 @@ void MissionController::setDirty(bool dirty) ...@@ -1529,11 +1466,6 @@ void MissionController::setDirty(bool dirty)
} }
} }
QString MissionController::fileExtension(void) const
{
return AppSettings::missionFileExtension;
}
void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualItems, Vehicle* vehicle) void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualItems, Vehicle* vehicle)
{ {
// First we look for a Fixed Wing Landing Pattern which is at the end // First we look for a Fixed Wing Landing Pattern which is at the end
......
...@@ -98,13 +98,6 @@ public: ...@@ -98,13 +98,6 @@ public:
/// Updates the altitudes of the items in the current mission to the new default altitude /// Updates the altitudes of the items in the current mission to the new default altitude
Q_INVOKABLE void applyDefaultMissionAltitude(void); Q_INVOKABLE void applyDefaultMissionAltitude(void);
/// Loads the mission items from the specified file
/// @param[in] vehicle Vehicle we are loading items for
/// @param[in] filename File to load from
/// @param[out] visualItems Visual items loaded, returns NULL if error
/// @return success/fail
static bool loadItemsFromFile(Vehicle* vehicle, const QString& filename, QmlObjectListModel** visualItems);
/// Sends the mission items to the specified vehicle /// Sends the mission items to the specified vehicle
static void sendItemsToVehicle(Vehicle* vehicle, QmlObjectListModel* visualMissionItems); static void sendItemsToVehicle(Vehicle* vehicle, QmlObjectListModel* visualMissionItems);
...@@ -113,18 +106,21 @@ public: ...@@ -113,18 +106,21 @@ public:
// Overrides from PlanElementController // Overrides from PlanElementController
void start (bool editMode) final; void start (bool editMode) final;
void startStaticActiveVehicle (Vehicle* vehicle) final; void startStaticActiveVehicle (Vehicle* vehicle) final;
void save (QJsonObject& json) final;
bool load (const QJsonObject& json, QString& errorString) final;
void loadFromVehicle (void) final; void loadFromVehicle (void) final;
void sendToVehicle (void) final; void sendToVehicle (void) final;
#if 0
void loadFromFile (const QString& filename) final; void loadFromFile (const QString& filename) final;
void saveToFile (const QString& filename) final; #endif
void removeAll (void) final; void removeAll (void) final;
void removeAllFromVehicle (void) final; void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final; bool syncInProgress (void) const final;
bool dirty (void) const final; bool dirty (void) const final;
void setDirty (bool dirty) final; void setDirty (bool dirty) final;
bool containsItems (void) const final; bool containsItems (void) const final;
void activeVehicleBeingRemoved (void) final;
QString fileExtension(void) const final; void activeVehicleSet (Vehicle* vehicle) final;
// Property accessors // Property accessors
...@@ -205,10 +201,7 @@ private: ...@@ -205,10 +201,7 @@ private:
void _addHoverTime(double hoverTime, double hoverDistance, int waypointIndex); void _addHoverTime(double hoverTime, double hoverDistance, int waypointIndex);
void _addCruiseTime(double cruiseTime, double cruiseDistance, int wayPointIndex); void _addCruiseTime(double cruiseTime, double cruiseDistance, int wayPointIndex);
void _updateBatteryInfo(int waypointIndex); void _updateBatteryInfo(int waypointIndex);
bool _loadItemsFromJson(const QJsonObject& json, QmlObjectListModel* visualItems, QString& errorString);
// Overrides from PlanElementController
void _activeVehicleBeingRemoved(void) final;
void _activeVehicleSet(void) final;
private: private:
QmlObjectListModel* _visualItems; QmlObjectListModel* _visualItems;
......
...@@ -28,32 +28,9 @@ PlanElementController::~PlanElementController() ...@@ -28,32 +28,9 @@ PlanElementController::~PlanElementController()
void PlanElementController::start(bool editMode) void PlanElementController::start(bool editMode)
{ {
_editMode = editMode; _editMode = editMode;
connect(_multiVehicleMgr, &MultiVehicleManager::activeVehicleChanged, this, &PlanElementController::_activeVehicleChanged);
_activeVehicleChanged(_multiVehicleMgr->activeVehicle());
} }
void PlanElementController::startStaticActiveVehicle(Vehicle* vehicle) void PlanElementController::startStaticActiveVehicle(Vehicle* vehicle)
{ {
_editMode = false; _editMode = false;
_activeVehicleChanged(vehicle);
}
void PlanElementController::_activeVehicleChanged(Vehicle* activeVehicle)
{
if (_activeVehicle) {
_activeVehicleBeingRemoved();
_activeVehicle = NULL;
}
if (activeVehicle) {
_activeVehicle = activeVehicle;
} else {
_activeVehicle = _multiVehicleMgr->offlineEditingVehicle();
}
_activeVehicleSet();
// Whenever vehicle changes we need to update syncInProgress
emit syncInProgressChanged(syncInProgress());
emit vehicleChanged(_activeVehicle);
} }
...@@ -25,34 +25,35 @@ public: ...@@ -25,34 +25,35 @@ public:
PlanElementController(QObject* parent = NULL); PlanElementController(QObject* parent = NULL);
~PlanElementController(); ~PlanElementController();
Q_PROPERTY(bool containsItems READ containsItems NOTIFY containsItemsChanged) ///< true: Elemement is non-empty Q_PROPERTY(bool containsItems READ containsItems NOTIFY containsItemsChanged) ///< true: Elemement is non-empty
Q_PROPERTY(bool syncInProgress READ syncInProgress NOTIFY syncInProgressChanged) ///< true: information is currently being saved/sent, false: no active save/send in progress Q_PROPERTY(bool syncInProgress READ syncInProgress NOTIFY syncInProgressChanged) ///< true: information is currently being saved/sent, false: no active save/send in progress
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) ///< true: unsaved/sent changes are present, false: no changes since last save/send Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) ///< true: unsaved/sent changes are present, false: no changes since last save/send
Q_PROPERTY(QString fileExtension READ fileExtension CONSTANT) ///< Returns the file extention for plan element file type. Q_PROPERTY(Vehicle* vehicle READ vehicle NOTIFY vehicleChanged)
Q_PROPERTY(Vehicle* vehicle READ vehicle NOTIFY vehicleChanged)
virtual QString fileExtension(void) const = 0;
/// Should be called immediately upon Component.onCompleted. /// Should be called immediately upon Component.onCompleted.
/// @param editMode true: controller being used in Plan view, false: controller being used in Fly view /// @param editMode true: controller being used in Plan view, false: controller being used in Fly view
Q_INVOKABLE virtual void start(bool editMode); virtual void start(bool editMode);
/// Starts the controller using a single static active vehicle. Will not track global active vehicle changes. /// Starts the controller using a single static active vehicle. Will not track global active vehicle changes.
/// @param editMode true: controller being used in Plan view, false: controller being used in Fly view virtual void startStaticActiveVehicle(Vehicle* vehicle);
Q_INVOKABLE virtual void startStaticActiveVehicle(Vehicle* vehicle);
virtual void save(QJsonObject& json) = 0;
virtual bool load(const QJsonObject& json, QString& errorString) = 0;
virtual void loadFromVehicle(void) = 0;
virtual void sendToVehicle(void) = 0;
virtual void removeAll(void) = 0; ///< Removes all from controller only, synce required to remove from vehicle
virtual void removeAllFromVehicle(void) = 0; ///< Removes all from vehicle and controller
Q_INVOKABLE virtual void loadFromVehicle(void) = 0; virtual bool containsItems (void) const = 0;
Q_INVOKABLE virtual void sendToVehicle(void) = 0; virtual bool syncInProgress (void) const = 0;
Q_INVOKABLE virtual void loadFromFile(const QString& filename) = 0; virtual bool dirty (void) const = 0;
Q_INVOKABLE virtual void saveToFile(const QString& filename) = 0; virtual void setDirty (bool dirty) = 0;
Q_INVOKABLE virtual void removeAll(void) = 0; ///< Removes all from controller only, synce required to remove from vehicle
Q_INVOKABLE virtual void removeAllFromVehicle(void) = 0; ///< Removes all from vehicle and controller
virtual bool containsItems (void) const = 0; /// Called when the current active vehicle is about to be removed. Derived classes should override to implement custom behavior.
virtual bool syncInProgress (void) const = 0; virtual void activeVehicleBeingRemoved(void) = 0;
virtual bool dirty (void) const = 0;
virtual void setDirty (bool dirty) = 0; /// Called when a new active vehicle has been set. Derived classes should override to implement custom behavior.
virtual void activeVehicleSet(Vehicle* activeVehicle) = 0;
Vehicle* vehicle(void) { return _activeVehicle; } Vehicle* vehicle(void) { return _activeVehicle; }
...@@ -66,17 +67,6 @@ protected: ...@@ -66,17 +67,6 @@ protected:
MultiVehicleManager* _multiVehicleMgr; MultiVehicleManager* _multiVehicleMgr;
Vehicle* _activeVehicle; ///< Currently active vehicle, can be disconnected offline editing vehicle Vehicle* _activeVehicle; ///< Currently active vehicle, can be disconnected offline editing vehicle
bool _editMode; bool _editMode;
/// Called when the current active vehicle is about to be removed. Derived classes should override
/// to implement custom behavior.
virtual void _activeVehicleBeingRemoved(void) = 0;
/// Called when a new active vehicle has been set. Derived classes should override
/// to implement custom behavior.
virtual void _activeVehicleSet(void) = 0;
private slots:
void _activeVehicleChanged(Vehicle* activeVehicle);
}; };
#endif #endif
/****************************************************************************
*
* (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 "PlanMasterController.h"
#include "QGCApplication.h"
#include "MultiVehicleManager.h"
#include "AppSettings.h"
#include "JsonHelper.h"
#include <QJsonDocument>
const int PlanMasterController::_planFileVersion = 1;
const char* PlanMasterController::_planFileType = "Plan";
const char* PlanMasterController::_jsonMissionObjectKey = "mission";
const char* PlanMasterController::_jsonGeoFenceObjectKey = "geoFence";
const char* PlanMasterController::_jsonRallyPointsObjectKey = "rallyPoints";
PlanMasterController::PlanMasterController(QObject* parent)
: QObject(parent)
, _multiVehicleMgr(qgcApp()->toolbox()->multiVehicleManager())
, _activeVehicle(_multiVehicleMgr->offlineEditingVehicle())
, _editMode(false)
{
connect(&_missionController, &MissionController::dirtyChanged, this, &PlanMasterController::dirtyChanged);
connect(&_geoFenceController, &GeoFenceController::dirtyChanged, this, &PlanMasterController::dirtyChanged);
connect(&_rallyPointController, &RallyPointController::dirtyChanged, this, &PlanMasterController::dirtyChanged);
connect(&_missionController, &MissionController::containsItemsChanged, this, &PlanMasterController::containsItemsChanged);
connect(&_geoFenceController, &GeoFenceController::containsItemsChanged, this, &PlanMasterController::containsItemsChanged);
connect(&_rallyPointController, &RallyPointController::containsItemsChanged, this, &PlanMasterController::containsItemsChanged);
connect(&_missionController, &MissionController::syncInProgressChanged, this, &PlanMasterController::syncInProgressChanged);
connect(&_geoFenceController, &GeoFenceController::syncInProgressChanged, this, &PlanMasterController::syncInProgressChanged);
connect(&_rallyPointController, &RallyPointController::syncInProgressChanged, this, &PlanMasterController::syncInProgressChanged);
}
PlanMasterController::~PlanMasterController()
{
}
void PlanMasterController::start(bool editMode)
{
_editMode = editMode;
_missionController.start(editMode);
_geoFenceController.start(editMode);
_rallyPointController.start(editMode);
connect(_multiVehicleMgr, &MultiVehicleManager::activeVehicleChanged, this, &PlanMasterController::_activeVehicleChanged);
_activeVehicleChanged(_multiVehicleMgr->activeVehicle());
}
void PlanMasterController::startStaticActiveVehicle(Vehicle* vehicle)
{
_editMode = false;
_missionController.startStaticActiveVehicle(vehicle);
_geoFenceController.startStaticActiveVehicle(vehicle);
_rallyPointController.startStaticActiveVehicle(vehicle);
_activeVehicleChanged(vehicle);
}
void PlanMasterController::_activeVehicleChanged(Vehicle* activeVehicle)
{
if (_activeVehicle) {
_missionController.activeVehicleBeingRemoved();
_geoFenceController.activeVehicleBeingRemoved();
_rallyPointController.activeVehicleBeingRemoved();
_activeVehicle = NULL;
}
if (activeVehicle) {
_activeVehicle = activeVehicle;
} else {
_activeVehicle = _multiVehicleMgr->offlineEditingVehicle();
}
_missionController.activeVehicleSet(_activeVehicle);
_geoFenceController.activeVehicleSet(_activeVehicle);
_rallyPointController.activeVehicleSet(_activeVehicle);
// Whenever vehicle changes we need to update syncInProgress
emit syncInProgressChanged(syncInProgress());
emit vehicleChanged(_activeVehicle);
}
void PlanMasterController::loadFromVehicle(void)
{
// FIXME: Hack implementation
_missionController.loadFromVehicle();
_geoFenceController.loadFromVehicle();
_rallyPointController.loadFromVehicle();
}
void PlanMasterController::sendToVehicle(void)
{
// FIXME: Hack implementation
_missionController.sendToVehicle();
_geoFenceController.sendToVehicle();
_rallyPointController.sendToVehicle();
}
void PlanMasterController::loadFromFile(const QString& filename)
{
QString errorString;
QString errorMessage = tr("Error reading Plan file (%1). %2").arg(filename).arg("%1");
if (filename.isEmpty()) {
return;
}
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorString = file.errorString() + QStringLiteral(" ") + filename;
return;
}
QJsonDocument jsonDoc;
QByteArray bytes = file.readAll();
if (!JsonHelper::isJsonFile(bytes, jsonDoc, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return;
}
int version;
QJsonObject json = jsonDoc.object();
if (!JsonHelper::validateQGCJsonFile(json, _planFileType, _planFileVersion, _planFileVersion, version, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return;
}
QList<JsonHelper::KeyValidateInfo> rgKeyInfo = {
{ _jsonMissionObjectKey, QJsonValue::Object, true },
{ _jsonGeoFenceObjectKey, QJsonValue::Object, true },
{ _jsonRallyPointsObjectKey, QJsonValue::Object, true },
};
if (!JsonHelper::validateKeys(json, rgKeyInfo, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return;
}
if (!_missionController.load(json[_jsonMissionObjectKey].toObject(), errorString) ||
!_geoFenceController.load(json[_jsonGeoFenceObjectKey].toObject(), errorString) ||
!_rallyPointController.load(json[_jsonRallyPointsObjectKey].toObject(), errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString));
return;
}
setDirty(true);
}
void PlanMasterController::saveToFile(const QString& filename)
{
if (filename.isEmpty()) {
return;
}
QString planFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
planFilename += QString(".%1").arg(fileExtension());
}
QFile file(planFilename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(tr("Plan save error %1 : %2").arg(filename).arg(file.errorString()));
} else {
QJsonObject planJson;
QJsonObject missionJson;
QJsonObject fenceJson;
QJsonObject rallyJson;
JsonHelper::saveQGCJsonFileHeader(planJson, _planFileType, _planFileVersion);
_missionController.save(missionJson);
_geoFenceController.save(fenceJson);
_rallyPointController.save(rallyJson);
planJson[_jsonMissionObjectKey] = missionJson;
planJson[_jsonGeoFenceObjectKey] = fenceJson;
planJson[_jsonRallyPointsObjectKey] = rallyJson;
QJsonDocument saveDoc(planJson);
file.write(saveDoc.toJson());
}
// If we are connected to a real vehicle, don't clear dirty bit on saving to file since vehicle is still out of date
if (_activeVehicle->isOfflineEditingVehicle()) {
setDirty(false);
}
}
void PlanMasterController::removeAll(void)
{
}
void PlanMasterController::removeAllFromVehicle(void)
{
_missionController.removeAllFromVehicle();
_geoFenceController.removeAllFromVehicle();
_rallyPointController.removeAllFromVehicle();
}
bool PlanMasterController::containsItems(void) const
{
return _missionController.containsItems() || _geoFenceController.containsItems() || _rallyPointController.containsItems();
}
bool PlanMasterController::syncInProgress(void) const
{
return _missionController.syncInProgress() || _geoFenceController.syncInProgress() || _rallyPointController.syncInProgress();
}
bool PlanMasterController::dirty(void) const
{
return _missionController.dirty() || _geoFenceController.dirty() || _rallyPointController.dirty();
}
void PlanMasterController::setDirty(bool dirty)
{
_missionController.setDirty(dirty);
_geoFenceController.setDirty(dirty);
_rallyPointController.setDirty(dirty);
}
QString PlanMasterController::fileExtension(void) const
{
return AppSettings::planFileExtension;
}
QStringList PlanMasterController::loadNameFilters(void) const
{
QStringList filters;
filters << tr("Plan Files (*.%1)").arg(AppSettings::planFileExtension) <<
tr("Mission Files (*.%1)").arg(AppSettings::missionFileExtension) <<
tr("Waypoint Files (*.waypoints)") <<
tr("All Files (*.*)");
return filters;
}
QStringList PlanMasterController::saveNameFilters(void) const
{
QStringList filters;
filters << tr("Plan Files (*.%1)").arg(fileExtension()) << tr("All Files (*.*)");
return filters;
}
void PlanMasterController::sendPlanToVehicle(Vehicle* vehicle, const QString& filename)
{
// Use a transient PlanMasterController to accomplish this
PlanMasterController* controller = new PlanMasterController();
controller->startStaticActiveVehicle(vehicle);
controller->loadFromFile(filename);
delete controller;
}
/****************************************************************************
*
* (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.
*
****************************************************************************/
#pragma once
#include <QObject>
#include "MissionController.h"
#include "GeoFenceController.h"
#include "RallyPointController.h"
#include "Vehicle.h"
#include "MultiVehicleManager.h"
/// Master controller for mission, fence, rally
class PlanMasterController : public QObject
{
Q_OBJECT
public:
PlanMasterController(QObject* parent = NULL);
~PlanMasterController();
Q_PROPERTY(MissionController* missionController READ missionController CONSTANT)
Q_PROPERTY(GeoFenceController* geoFenceController READ geoFenceController CONSTANT)
Q_PROPERTY(RallyPointController* rallyPointController READ rallyPointController CONSTANT)
Q_PROPERTY(bool containsItems READ containsItems NOTIFY containsItemsChanged) ///< true: Elemement is non-empty
Q_PROPERTY(bool syncInProgress READ syncInProgress NOTIFY syncInProgressChanged) ///< true: Information is currently being saved/sent, false: no active save/send in progress
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) ///< true: Unsaved/sent changes are present, false: no changes since last save/send
Q_PROPERTY(Vehicle* vehicle READ vehicle NOTIFY vehicleChanged)
Q_PROPERTY(QString fileExtension READ fileExtension CONSTANT) ///< File extention for missions
Q_PROPERTY(QStringList loadNameFilters READ loadNameFilters CONSTANT) ///< File filter list loading plan files
Q_PROPERTY(QStringList saveNameFilters READ saveNameFilters CONSTANT) ///< File filter list saving plan files
/// Should be called immediately upon Component.onCompleted.
/// @param editMode true: controller being used in Plan view, false: controller being used in Fly view
Q_INVOKABLE virtual void start(bool editMode);
/// Starts the controller using a single static active vehicle. Will not track global active vehicle changes.
Q_INVOKABLE virtual void startStaticActiveVehicle(Vehicle* vehicle);
/// Sends a plan to the specified file
/// @param[in] vehicle Vehicle we are sending a plan to
/// @param[in] filename Plan file to load
static void sendPlanToVehicle(Vehicle* vehicle, const QString& filename);
Q_INVOKABLE void loadFromVehicle(void);
Q_INVOKABLE void sendToVehicle(void);
Q_INVOKABLE void loadFromFile(const QString& filename);
Q_INVOKABLE void saveToFile(const QString& filename);
Q_INVOKABLE void removeAll(void); ///< Removes all from controller only, synce required to remove from vehicle
Q_INVOKABLE void removeAllFromVehicle(void); ///< Removes all from vehicle and controller
MissionController* missionController(void) { return &_missionController; }
GeoFenceController* geoFenceController(void) { return &_geoFenceController; }
RallyPointController* rallyPointController(void) { return &_rallyPointController; }
bool containsItems (void) const;
bool syncInProgress (void) const;
bool dirty (void) const;
void setDirty (bool dirty);
QString fileExtension (void) const;
QStringList loadNameFilters (void) const;
QStringList saveNameFilters (void) const;
Vehicle* vehicle(void) { return _activeVehicle; }
signals:
void containsItemsChanged (bool containsItems);
void syncInProgressChanged (bool syncInProgress);
void dirtyChanged (bool dirty);
void vehicleChanged (Vehicle* vehicle);
private slots:
void _activeVehicleChanged(Vehicle* activeVehicle);
private:
MultiVehicleManager* _multiVehicleMgr;
Vehicle* _activeVehicle; ///< Currently active vehicle, can be disconnected offline editing vehicle
bool _editMode;
MissionController _missionController;
GeoFenceController _geoFenceController;
RallyPointController _rallyPointController;
static const int _planFileVersion;
static const char* _planFileType;
static const char* _jsonMissionObjectKey;
static const char* _jsonGeoFenceObjectKey;
static const char* _jsonRallyPointsObjectKey;
};
...@@ -49,14 +49,16 @@ RallyPointController::~RallyPointController() ...@@ -49,14 +49,16 @@ RallyPointController::~RallyPointController()
} }
void RallyPointController::_activeVehicleBeingRemoved(void) void RallyPointController::activeVehicleBeingRemoved(void)
{ {
_activeVehicle->rallyPointManager()->disconnect(this); _activeVehicle->rallyPointManager()->disconnect(this);
_points.clearAndDeleteContents(); _points.clearAndDeleteContents();
_activeVehicle = NULL;
} }
void RallyPointController::_activeVehicleSet(void) void RallyPointController::activeVehicleSet(Vehicle* activeVehicle)
{ {
_activeVehicle = activeVehicle;
RallyPointManager* rallyPointManager = _activeVehicle->rallyPointManager(); RallyPointManager* rallyPointManager = _activeVehicle->rallyPointManager();
connect(rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_loadComplete); connect(rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_loadComplete);
connect(rallyPointManager, &RallyPointManager::inProgressChanged, this, &RallyPointController::syncInProgressChanged); connect(rallyPointManager, &RallyPointManager::inProgressChanged, this, &RallyPointController::syncInProgressChanged);
...@@ -67,32 +69,23 @@ void RallyPointController::_activeVehicleSet(void) ...@@ -67,32 +69,23 @@ void RallyPointController::_activeVehicleSet(void)
emit rallyPointsSupportedChanged(rallyPointsSupported()); emit rallyPointsSupportedChanged(rallyPointsSupported());
} }
bool RallyPointController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorString) bool RallyPointController::load(const QJsonObject& json, QString& errorString)
{ {
QJsonObject json = jsonDoc.object(); QString errorStr;
QString errorMessage = tr("Rally: %1");
int fileVersion;
if (!JsonHelper::validateQGCJsonFile(json,
_jsonFileTypeValue, // expected file type
1, // minimum supported version
1, // maximum supported version
fileVersion,
errorString)) {
return false;
}
// Check for required keys // Check for required keys
QStringList requiredKeys = { _jsonPointsKey }; QStringList requiredKeys = { _jsonPointsKey };
if (!JsonHelper::validateRequiredKeys(json, requiredKeys, errorString)) { if (!JsonHelper::validateRequiredKeys(json, requiredKeys, errorStr)) {
errorString = errorMessage.arg(errorStr);
return false; return false;
} }
// Load points
QList<QGeoCoordinate> rgPoints; QList<QGeoCoordinate> rgPoints;
if (!JsonHelper::loadGeoCoordinateArray(json[_jsonPointsKey], true /* altitudeRequired */, rgPoints, errorString)) { if (!JsonHelper::loadGeoCoordinateArray(json[_jsonPointsKey], true /* altitudeRequired */, rgPoints, errorStr)) {
errorString = errorMessage.arg(errorStr);
return false; return false;
} }
_points.clearAndDeleteContents(); _points.clearAndDeleteContents();
QObjectList pointList; QObjectList pointList;
for (int i=0; i<rgPoints.count(); i++) { for (int i=0; i<rgPoints.count(); i++) {
...@@ -100,77 +93,23 @@ bool RallyPointController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorS ...@@ -100,77 +93,23 @@ bool RallyPointController::_loadJsonFile(QJsonDocument& jsonDoc, QString& errorS
} }
_points.swapObjectList(pointList); _points.swapObjectList(pointList);
return true; setDirty(false);
}
void RallyPointController::loadFromFile(const QString& filename)
{
QString errorString;
if (filename.isEmpty()) {
return;
}
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorString = file.errorString() + QStringLiteral(" ") + filename;
} else {
QJsonDocument jsonDoc;
QByteArray bytes = file.readAll();
if (JsonHelper::isJsonFile(bytes, jsonDoc)) {
_loadJsonFile(jsonDoc, errorString);
} else {
// FIXME: No MP file format support
qgcApp()->showMessage("Rall Point file is in incorrect format.");
return;
}
}
if (!errorString.isEmpty()) {
qgcApp()->showMessage(errorString);
}
setDirty(true);
_setFirstPointCurrent(); _setFirstPointCurrent();
return true;
} }
void RallyPointController::saveToFile(const QString& filename) void RallyPointController::save(QJsonObject& json)
{ {
if (filename.isEmpty()) { json[JsonHelper::jsonVersionKey] = 1;
return;
}
QString rallyFilename = filename;
if (!QFileInfo(filename).fileName().contains(".")) {
rallyFilename += QString(".%1").arg(AppSettings::rallyPointFileExtension);
}
QFile file(rallyFilename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(file.errorString());
} else {
QJsonObject jsonObject;
jsonObject[JsonHelper::jsonFileTypeKey] = _jsonFileTypeValue; QJsonArray rgPoints;
jsonObject[JsonHelper::jsonVersionKey] = 1; QJsonValue jsonPoint;
jsonObject[JsonHelper::jsonGroundStationKey] = JsonHelper::jsonGroundStationValue; for (int i=0; i<_points.count(); i++) {
JsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
QJsonArray rgPoints; rgPoints.append(jsonPoint);
QJsonValue jsonPoint;
for (int i=0; i<_points.count(); i++) {
JsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
rgPoints.append(jsonPoint);
}
jsonObject[_jsonPointsKey] = QJsonValue(rgPoints);
QJsonDocument saveDoc(jsonObject);
file.write(saveDoc.toJson());
} }
json[_jsonPointsKey] = QJsonValue(rgPoints);
setDirty(false);
} }
void RallyPointController::removeAll(void) void RallyPointController::removeAll(void)
...@@ -234,11 +173,6 @@ void RallyPointController::_loadComplete(const QList<QGeoCoordinate> rgPoints) ...@@ -234,11 +173,6 @@ void RallyPointController::_loadComplete(const QList<QGeoCoordinate> rgPoints)
emit loadComplete(); emit loadComplete();
} }
QString RallyPointController::fileExtension(void) const
{
return AppSettings::rallyPointFileExtension;
}
void RallyPointController::addPoint(QGeoCoordinate point) void RallyPointController::addPoint(QGeoCoordinate point)
{ {
double defaultAlt; double defaultAlt;
......
...@@ -37,18 +37,18 @@ public: ...@@ -37,18 +37,18 @@ public:
Q_INVOKABLE void addPoint(QGeoCoordinate point); Q_INVOKABLE void addPoint(QGeoCoordinate point);
Q_INVOKABLE void removePoint(QObject* rallyPoint); Q_INVOKABLE void removePoint(QObject* rallyPoint);
void save (QJsonObject& json) final;
bool load (const QJsonObject& json, QString& errorString) final;
void loadFromVehicle (void) final; void loadFromVehicle (void) final;
void sendToVehicle (void) final; void sendToVehicle (void) final;
void loadFromFile (const QString& filename) final;
void saveToFile (const QString& filename) final;
void removeAll (void) final; void removeAll (void) final;
void removeAllFromVehicle (void) final; void removeAllFromVehicle (void) final;
bool syncInProgress (void) const final; bool syncInProgress (void) const final;
bool dirty (void) const final { return _dirty; } bool dirty (void) const final { return _dirty; }
void setDirty (bool dirty) final; void setDirty (bool dirty) final;
bool containsItems (void) const final; bool containsItems (void) const final;
void activeVehicleBeingRemoved (void) final;
QString fileExtension(void) const final; void activeVehicleSet (Vehicle* vehicle) final;
bool rallyPointsSupported (void) const; bool rallyPointsSupported (void) const;
QmlObjectListModel* points (void) { return &_points; } QmlObjectListModel* points (void) { return &_points; }
...@@ -68,11 +68,6 @@ private slots: ...@@ -68,11 +68,6 @@ private slots:
void _updateContainsItems(void); void _updateContainsItems(void);
private: private:
bool _loadJsonFile(QJsonDocument& jsonDoc, QString& errorString);
void _activeVehicleBeingRemoved(void) final;
void _activeVehicleSet(void) final;
bool _dirty; bool _dirty;
QmlObjectListModel _points; QmlObjectListModel _points;
QObject* _currentRallyPoint; QObject* _currentRallyPoint;
......
...@@ -19,9 +19,10 @@ Rectangle { ...@@ -19,9 +19,10 @@ Rectangle {
color: _currentItem ? qgcPal.primaryButton : qgcPal.windowShade color: _currentItem ? qgcPal.primaryButton : qgcPal.windowShade
radius: _radius radius: _radius
property var map ///< Map control property var map ///< Map control
property var missionItem ///< MissionItem associated with this editor property var missionController
property bool readOnly ///< true: read only view, false: full editing view property var missionItem ///< MissionItem associated with this editor
property bool readOnly ///< true: read only view, false: full editing view
property var rootQgcView property var rootQgcView
signal clicked signal clicked
......
...@@ -23,21 +23,22 @@ Rectangle { ...@@ -23,21 +23,22 @@ Rectangle {
signal showFlyView signal showFlyView
property var missionController property var planMasterController
property var currentMissionItem ///< Mission item to display status for property var currentMissionItem ///< Mission item to display status for
property var missionItems: _controllerValid ? missionController.visualItems : undefined property var missionItems: _controllerValid ? planMasterController.missionController.visualItems : undefined
property real missionDistance: _controllerValid ? missionController.missionDistance : NaN property real missionDistance: _controllerValid ? planMasterController.missionController.missionDistance : NaN
property real missionTime: _controllerValid ? missionController.missionTime : NaN property real missionTime: _controllerValid ? planMasterController.missionController.missionTime : NaN
property real missionMaxTelemetry: _controllerValid ? missionController.missionMaxTelemetry : NaN property real missionMaxTelemetry: _controllerValid ? planMasterController.missionController.missionMaxTelemetry : NaN
property bool missionDirty: _controllerValid ? missionController.dirty : false property bool missionDirty: _controllerValid ? planMasterController.missionController.dirty : false
property bool _controllerValid: planMasterController != undefined
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _controllerDirty: planMasterController ? planMasterController.dirty : false
property var _controllerSyncInProgress: planMasterController ? planMasterController.syncInProgress : false
property bool _statusValid: currentMissionItem != undefined property bool _statusValid: currentMissionItem != undefined
property bool _missionValid: missionItems != undefined property bool _missionValid: missionItems != undefined
property bool _controllerValid: missionController != undefined
property bool _manualUpload: QGroundControl.settingsManager.appSettings.automaticMissionUpload.rawValue == 0
property real _dataFontSize: ScreenTools.defaultFontPointSize property real _dataFontSize: ScreenTools.defaultFontPointSize
property real _largeValueWidth: ScreenTools.defaultFontPixelWidth * 8 property real _largeValueWidth: ScreenTools.defaultFontPixelWidth * 8
...@@ -54,8 +55,8 @@ Rectangle { ...@@ -54,8 +55,8 @@ Rectangle {
property real _missionDistance: _missionValid ? missionDistance : NaN property real _missionDistance: _missionValid ? missionDistance : NaN
property real _missionMaxTelemetry: _missionValid ? missionMaxTelemetry : NaN property real _missionMaxTelemetry: _missionValid ? missionMaxTelemetry : NaN
property real _missionTime: _missionValid ? missionTime : NaN property real _missionTime: _missionValid ? missionTime : NaN
property int _batteryChangePoint: _controllerValid ? missionController.batteryChangePoint : -1 property int _batteryChangePoint: _controllerValid ? planMasterController.missionController.batteryChangePoint : -1
property int _batteriesRequired: _controllerValid ? missionController.batteriesRequired : -1 property int _batteriesRequired: _controllerValid ? planMasterController.missionController.batteriesRequired : -1
property string _distanceText: isNaN(_distance) ? "-.-" : QGroundControl.metersToAppSettingsDistanceUnits(_distance).toFixed(1) + " " + QGroundControl.appSettingsDistanceUnitsString property string _distanceText: isNaN(_distance) ? "-.-" : QGroundControl.metersToAppSettingsDistanceUnits(_distance).toFixed(1) + " " + QGroundControl.appSettingsDistanceUnitsString
property string _altDifferenceText: isNaN(_altDifference) ? "-.-" : QGroundControl.metersToAppSettingsDistanceUnits(_altDifference).toFixed(1) + " " + QGroundControl.appSettingsDistanceUnitsString property string _altDifferenceText: isNaN(_altDifference) ? "-.-" : QGroundControl.metersToAppSettingsDistanceUnits(_altDifference).toFixed(1) + " " + QGroundControl.appSettingsDistanceUnitsString
...@@ -104,9 +105,7 @@ Rectangle { ...@@ -104,9 +105,7 @@ Rectangle {
checked: false checked: false
onClicked: { onClicked: {
checked = false checked = false
if (missionController.uploadOnSwitch()) { showFlyView()
showFlyView()
}
} }
} }
} }
...@@ -245,17 +244,17 @@ Rectangle { ...@@ -245,17 +244,17 @@ Rectangle {
anchors.rightMargin: _margins anchors.rightMargin: _margins
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: missionController ? (missionController.dirty ? qsTr("Upload Required") : qsTr("Upload")) : "" text: _controllerDirty ? qsTr("Upload Required") : qsTr("Upload")
enabled: _activeVehicle && !missionController.syncInProgress enabled: _activeVehicle && !_controllerSyncInProgress
visible: _activeVehicle && _manualUpload visible: _activeVehicle
onClicked: missionController.upload() onClicked: planMasterController.upload()
PropertyAnimation on opacity { PropertyAnimation on opacity {
easing.type: Easing.OutQuart easing.type: Easing.OutQuart
from: 0.5 from: 0.5
to: 1 to: 1
loops: Animation.Infinite loops: Animation.Infinite
running: missionController ? missionController.dirty : false running: _controllerDirty
alwaysRunToEnd: true alwaysRunToEnd: true
duration: 2000 duration: 2000
} }
......
...@@ -42,19 +42,18 @@ QGCView { ...@@ -42,19 +42,18 @@ QGCView {
readonly property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) readonly property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
readonly property var _defaultVehicleCoordinate: QtPositioning.coordinate(37.803784, -122.462276) readonly property var _defaultVehicleCoordinate: QtPositioning.coordinate(37.803784, -122.462276)
property var _visualItems: missionController.visualItems property var _planMasterController: masterController
property var _missionController: _planMasterController.missionController
property var _geoFenceController: _planMasterController.geoFenceController
property var _rallyPointController: _planMasterController.rallyPointController
property var _visualItems: _missionController.visualItems
property var _currentMissionItem property var _currentMissionItem
property int _currentMissionIndex: 0 property int _currentMissionIndex: 0
property bool _lightWidgetBorders: editorMap.isSatelliteMap property bool _lightWidgetBorders: editorMap.isSatelliteMap
property bool _addWaypointOnClick: false property bool _addWaypointOnClick: false
property bool _singleComplexItem: missionController.complexMissionItemNames.length === 1 property bool _singleComplexItem: _missionController.complexMissionItemNames.length === 1
property real _toolbarHeight: _qgcView.height - ScreenTools.availableHeight property real _toolbarHeight: _qgcView.height - ScreenTools.availableHeight
property int _editingLayer: _layerMission property int _editingLayer: _layerMission
property bool _autoSync: QGroundControl.settingsManager.appSettings.automaticMissionUpload.rawValue != 0
property bool _switchToFlyAfterUpload: false
/// The controller which should be called for load/save, send to/from vehicle calls
property var _syncDropDownController: missionController
readonly property int _layerMission: 1 readonly property int _layerMission: 1
readonly property int _layerGeoFence: 2 readonly property int _layerGeoFence: 2
...@@ -62,7 +61,7 @@ QGCView { ...@@ -62,7 +61,7 @@ QGCView {
readonly property string _armedVehicleUploadPrompt: qsTr("Vehicle is currently armed. Do you want to upload the mission to the vehicle?") readonly property string _armedVehicleUploadPrompt: qsTr("Vehicle is currently armed. Do you want to upload the mission to the vehicle?")
Component.onCompleted: { Component.onCompleted: {
toolbar.missionController = Qt.binding(function () { return missionController }) toolbar.planMasterController = Qt.binding(function () { return _planMasterController })
toolbar.currentMissionItem = Qt.binding(function () { return _currentMissionItem }) toolbar.currentMissionItem = Qt.binding(function () { return _currentMissionItem })
} }
...@@ -71,11 +70,11 @@ QGCView { ...@@ -71,11 +70,11 @@ QGCView {
coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces) coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces) coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces) coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
insertComplexMissionItem(complexItemName, coordinate, missionController.visualItems.count) insertComplexMissionItem(complexItemName, coordinate, _missionController.visualItems.count)
} }
function insertComplexMissionItem(complexItemName, coordinate, index) { function insertComplexMissionItem(complexItemName, coordinate, index) {
var sequenceNumber = missionController.insertComplexMissionItem(complexItemName, coordinate, index) var sequenceNumber = _missionController.insertComplexMissionItem(complexItemName, coordinate, index)
setCurrentItem(sequenceNumber, true) setCurrentItem(sequenceNumber, true)
} }
...@@ -88,9 +87,7 @@ QGCView { ...@@ -88,9 +87,7 @@ QGCView {
id: mapFitFunctions id: mapFitFunctions
map: editorMap map: editorMap
usePlannedHomePosition: true usePlannedHomePosition: true
mapGeoFenceController: geoFenceController planMasterController: _planMasterController
mapMissionController: missionController
mapRallyPointController: rallyPointController
} }
Connections { Connections {
...@@ -111,7 +108,7 @@ QGCView { ...@@ -111,7 +108,7 @@ QGCView {
function accept() { function accept() {
hideDialog() hideDialog()
missionController.applyDefaultMissionAltitude() _missionController.applyDefaultMissionAltitude()
} }
} }
} }
...@@ -141,83 +138,51 @@ QGCView { ...@@ -141,83 +138,51 @@ QGCView {
text: qsTr("Pause and Upload") text: qsTr("Pause and Upload")
onClicked: { onClicked: {
_activeVehicle.flightMode = _activeVehicle.pauseFlightMode _activeVehicle.flightMode = _activeVehicle.pauseFlightMode
missionController.sendToVehicle() _missionController.sendToVehicle()
hideDialog()
if (_switchToFlyAfterUpload) {
toolbar.showFlyView()
}
}
}
QGCButton {
text: qsTr("Exit planning (no upload)")
visible: _switchToFlyAfterUpload
onClicked: {
hideDialog() hideDialog()
toolbar.showFlyView()
} }
} }
} }
} }
} }
MissionController { PlanElemementMasterController {
id: missionController id: masterController
property var nameFilters: [ qsTr("Mission Files (*.%1)").arg(missionController.fileExtension) , qsTr("All Files (*.*)") ]
Component.onCompleted: { Component.onCompleted: {
start(true /* editMode */) start(true /* editMode */)
setCurrentItem(0, true) setCurrentItem(0, true)
} }
function _denyUpload(switchToFly) { function upload() {
if (_activeVehicle && _activeVehicle.armed && _activeVehicle.flightMode === _activeVehicle.missionFlightMode) { if (_activeVehicle && _activeVehicle.armed && _activeVehicle.flightMode === _activeVehicle.missionFlightMode) {
_switchToFlyAfterUpload = switchToFly _qgcView.showDialog(activeMissionUploadDialogComponent, qsTr("Plan Upload"), _qgcView.showDialogDefaultWidth, StandardButton.Cancel)
_qgcView.showDialog(activeMissionUploadDialogComponent, qsTr("Mission Upload"), _qgcView.showDialogDefaultWidth, StandardButton.Cancel)
return true
} else { } else {
return false
}
}
// Users is switching away from Plan View
function uploadOnSwitch() {
if (missionController.dirty && _autoSync) {
if (_denyUpload(true /* switchToFly */)) {
return false
} else {
sendToVehicle()
}
}
return true
}
function upload() {
if (!_denyUpload(false /* switchToFly */)) {
sendToVehicle() sendToVehicle()
} }
} }
function loadFromSelectedFile() { function loadFromSelectedFile() {
fileDialog.title = qsTr("Select Mission File") fileDialog.title = qsTr("Select Plan File")
fileDialog.selectExisting = true fileDialog.selectExisting = true
fileDialog.nameFilters = missionController.nameFilters fileDialog.nameFilters = masterController.loadNameFilters
fileDialog.openForLoad() fileDialog.openForLoad()
} }
function saveToSelectedFile() { function saveToSelectedFile() {
fileDialog.title = qsTr("Save Mission") fileDialog.title = qsTr("Save Plan")
fileDialog.selectExisting = false fileDialog.selectExisting = false
fileDialog.nameFilters = missionController.nameFilters fileDialog.nameFilters = masterController.saveNameFilters
fileDialog.openForSave() fileDialog.openForSave()
} }
function fitViewportToItems() { function fitViewportToItems() {
mapFitFunctions.fitMapViewportToMissionItems() mapFitFunctions.fitMapViewportToMissionItems()
} }
}
onVisualItemsChanged: itemDragger.clearItem() Connections {
target: _missionController
onNewItemsFromVehicle: { onNewItemsFromVehicle: {
if (_visualItems && _visualItems.count != 1) { if (_visualItems && _visualItems.count != 1) {
...@@ -227,76 +192,6 @@ QGCView { ...@@ -227,76 +192,6 @@ QGCView {
} }
} }
GeoFenceController {
id: geoFenceController
property var nameFilters: [ qsTr("GeoFence Files (*.%1)").arg(geoFenceController.fileExtension) , qsTr("All Files (*.*)") ]
Component.onCompleted: start(true /* editMode */)
function saveToSelectedFile() {
fileDialog.title = qsTr("Save GeoFence")
fileDialog.selectExisting = false
fileDialog.nameFilters = geoFenceController.nameFilters
fileDialog.openForSave()
}
function loadFromSelectedFile() {
fileDialog.title = qsTr("Select GeoFence File")
fileDialog.selectExisting = true
fileDialog.nameFilters = geoFenceController.nameFilters
fileDialog.openForLoad()
///mapFitFunctions.fitMapViewportToFenceItems()
}
function fitViewportToItems() {
mapFitFunctions.fitMapViewportToFenceItems()
}
function upload() {
sendToVehicle()
}
}
RallyPointController {
id: rallyPointController
property var nameFilters: [ qsTr("Rally Point Files (*.%1)").arg(rallyPointController.fileExtension) , qsTr("All Files (*.*)") ]
onCurrentRallyPointChanged: {
if (_editingLayer == _layerRallyPoints && !currentRallyPoint) {
itemDragger.visible = false
itemDragger.coordinateItem = undefined
itemDragger.mapCoordinateIndicator = undefined
}
}
Component.onCompleted: start(true /* editMode */)
function saveToSelectedFile() {
fileDialog.title = qsTr("Save Rally Points")
fileDialog.selectExisting = false
fileDialog.nameFilters = rallyPointController.nameFilters
fileDialog.openForSave()
}
function loadFromSelectedFile() {
fileDialog.title = qsTr("Select Rally Point File")
fileDialog.selectExisting = true
fileDialog.nameFilters = rallyPointController.nameFilters
fileDialog.openForLoad()
//mapFitFunctions.fitMapViewportToRallyItems()
}
function fitViewportToItems() {
mapFitFunctions.fitMapViewportToRallyItems()
}
function upload() {
sendToVehicle()
}
}
QGCPalette { id: qgcPal; colorGroupEnabled: enabled } QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
ExclusiveGroup { ExclusiveGroup {
...@@ -326,7 +221,7 @@ QGCView { ...@@ -326,7 +221,7 @@ QGCView {
/// @param coordinate Location to insert item /// @param coordinate Location to insert item
/// @param index Insert item at this index /// @param index Insert item at this index
function insertSimpleMissionItem(coordinate, index) { function insertSimpleMissionItem(coordinate, index) {
var sequenceNumber = missionController.insertSimpleMissionItem(coordinate, index) var sequenceNumber = _missionController.insertSimpleMissionItem(coordinate, index)
setCurrentItem(sequenceNumber, true) setCurrentItem(sequenceNumber, true)
} }
...@@ -336,16 +231,16 @@ QGCView { ...@@ -336,16 +231,16 @@ QGCView {
id: fileDialog id: fileDialog
qgcView: _qgcView qgcView: _qgcView
folder: QGroundControl.settingsManager.appSettings.missionSavePath folder: QGroundControl.settingsManager.appSettings.missionSavePath
fileExtension: _syncDropDownController.fileExtension fileExtension: masterController.fileExtension
onAcceptedForSave: { onAcceptedForSave: {
_syncDropDownController.saveToFile(file) masterController.saveToFile(file)
close() close()
} }
onAcceptedForLoad: { onAcceptedForLoad: {
_syncDropDownController.loadFromFile(file) masterController.loadFromFile(file)
_syncDropDownController.fitViewportToItems() masterController.fitViewportToItems()
setCurrentItem(0, true) setCurrentItem(0, true)
close() close()
} }
...@@ -361,7 +256,7 @@ QGCView { ...@@ -361,7 +256,7 @@ QGCView {
if (toIndex == 0) { if (toIndex == 0) {
toIndex = 1 toIndex = 1
} }
missionController.moveMissionItem(_moveDialogMissionItemIndex, toIndex) _missionController.moveMissionItem(_moveDialogMissionItemIndex, toIndex)
hideDialog() hideDialog()
} }
...@@ -437,71 +332,21 @@ QGCView { ...@@ -437,71 +332,21 @@ QGCView {
switch (_editingLayer) { switch (_editingLayer) {
case _layerMission: case _layerMission:
if (_addWaypointOnClick) { if (_addWaypointOnClick) {
insertSimpleMissionItem(coordinate, missionController.visualItems.count) insertSimpleMissionItem(coordinate, _missionController.visualItems.count)
} }
break break
case _layerRallyPoints: case _layerRallyPoints:
if (rallyPointController.rallyPointsSupported) { if (_rallyPointController.rallyPointsSupported) {
rallyPointController.addPoint(coordinate) _rallyPointController.addPoint(coordinate)
} }
break break
} }
} }
} }
// We use this item to support dragging since dragging a MapQuickItem just doesn't seem to work
Rectangle {
id: itemDragger
x: mapCoordinateIndicator ? (mapCoordinateIndicator.x + mapCoordinateIndicator.anchorPoint.x - (itemDragger.width / 2)) : 100
y: mapCoordinateIndicator ? (mapCoordinateIndicator.y + mapCoordinateIndicator.anchorPoint.y - (itemDragger.height / 2)) : 100
width: ScreenTools.defaultFontPixelHeight * 3
height: ScreenTools.defaultFontPixelHeight * 3
color: "transparent"
visible: false
z: QGroundControl.zOrderMapItems + 1 // Above item icons
property var coordinateItem
property var mapCoordinateIndicator
property bool preventCoordinateBindingLoop: false
onXChanged: liveDrag()
onYChanged: liveDrag()
function liveDrag() {
if (!itemDragger.preventCoordinateBindingLoop && Drag.active) {
var point = Qt.point(itemDragger.x + (itemDragger.width / 2), itemDragger.y + (itemDragger.height / 2))
var coordinate = editorMap.toCoordinate(point, false /* clipToViewPort */)
coordinate.altitude = itemDragger.coordinateItem.coordinate.altitude
itemDragger.preventCoordinateBindingLoop = true
itemDragger.coordinateItem.coordinate = coordinate
itemDragger.preventCoordinateBindingLoop = false
}
}
function clearItem() {
itemDragger.visible = false
itemDragger.coordinateItem = undefined
itemDragger.mapCoordinateIndicator = undefined
}
Drag.active: itemDrag.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
MouseArea {
id: itemDrag
anchors.fill: parent
drag.target: parent
drag.minimumX: 0
drag.minimumY: 0
drag.maximumX: itemDragger.parent.width - parent.width
drag.maximumY: itemDragger.parent.height - parent.height
}
}
// Add the mission item visuals to the map // Add the mission item visuals to the map
Repeater { Repeater {
model: missionController.visualItems model: _missionController.visualItems
delegate: MissionItemMapVisual { delegate: MissionItemMapVisual {
map: editorMap map: editorMap
...@@ -511,7 +356,7 @@ QGCView { ...@@ -511,7 +356,7 @@ QGCView {
// Add lines between waypoints // Add lines between waypoints
MissionLineView { MissionLineView {
model: _editingLayer == _layerMission ? missionController.waypointLines : undefined model: _editingLayer == _layerMission ? _missionController.waypointLines : undefined
} }
// Add the vehicles to the map // Add the vehicles to the map
...@@ -529,15 +374,15 @@ QGCView { ...@@ -529,15 +374,15 @@ QGCView {
GeoFenceMapVisuals { GeoFenceMapVisuals {
map: editorMap map: editorMap
myGeoFenceController: geoFenceController myGeoFenceController: _geoFenceController
interactive: _editingLayer == _layerGeoFence interactive: _editingLayer == _layerGeoFence
homePosition: missionController.plannedHomePosition homePosition: _missionController.plannedHomePosition
planView: true planView: true
} }
RallyPointMapVisuals { RallyPointMapVisuals {
map: editorMap map: editorMap
myRallyPointController: rallyPointController myRallyPointController: _rallyPointController
interactive: _editingLayer == _layerRallyPoints interactive: _editingLayer == _layerRallyPoints
planView: true planView: true
} }
...@@ -551,10 +396,10 @@ QGCView { ...@@ -551,10 +396,10 @@ QGCView {
color: qgcPal.window color: qgcPal.window
title: qsTr("Plan") title: qsTr("Plan")
z: QGroundControl.zOrderWidgets z: QGroundControl.zOrderWidgets
showAlternateIcon: [ false, false, !_autoSync && _syncDropDownController.dirty, false, false, false ] showAlternateIcon: [ false, false, !_autoSync && masterController.dirty, false, false, false ]
rotateImage: [ false, false, _syncDropDownController.syncInProgress, false, false, false ] rotateImage: [ false, false, masterController.syncInProgress, false, false, false ]
animateImage: [ false, false, !_autoSync && _syncDropDownController.dirty, false, false, false ] animateImage: [ false, false, !_autoSync && masterController.dirty, false, false, false ]
buttonEnabled: [ true, true, !_syncDropDownController.syncInProgress, true, true, true ] buttonEnabled: [ true, true, !masterController.syncInProgress, true, true, true ]
buttonVisible: [ true, true, true, true, _showZoom, _showZoom ] buttonVisible: [ true, true, true, true, _showZoom, _showZoom ]
maxHeight: mapScale.y - toolStrip.y maxHeight: mapScale.y - toolStrip.y
...@@ -567,7 +412,7 @@ QGCView { ...@@ -567,7 +412,7 @@ QGCView {
toggle: true toggle: true
}, },
{ {
name: _singleComplexItem ? missionController.complexMissionItemNames[0] : "Pattern", name: _singleComplexItem ? _missionController.complexMissionItemNames[0] : "Pattern",
iconSource: "/qmlimages/MapDrawShape.svg", iconSource: "/qmlimages/MapDrawShape.svg",
dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel
}, },
...@@ -599,7 +444,7 @@ QGCView { ...@@ -599,7 +444,7 @@ QGCView {
break break
case 1: case 1:
if (_singleComplexItem) { if (_singleComplexItem) {
addComplexItem(missionController.complexMissionItemNames[0]) addComplexItem(_missionController.complexMissionItemNames[0])
} }
break break
case 4: case 4:
...@@ -645,15 +490,12 @@ QGCView { ...@@ -645,15 +490,12 @@ QGCView {
switch (current) { switch (current) {
case planElementMission: case planElementMission:
_editingLayer = _layerMission _editingLayer = _layerMission
_syncDropDownController = missionController
break break
case planElementGeoFence: case planElementGeoFence:
_editingLayer = _layerGeoFence _editingLayer = _layerGeoFence
_syncDropDownController = geoFenceController
break break
case planElementRallyPoints: case planElementRallyPoints:
_editingLayer = _layerRallyPoints _editingLayer = _layerRallyPoints
_syncDropDownController = rallyPointController
break break
} }
} }
...@@ -707,26 +549,26 @@ QGCView { ...@@ -707,26 +549,26 @@ QGCView {
anchors.fill: parent anchors.fill: parent
spacing: _margin / 2 spacing: _margin / 2
orientation: ListView.Vertical orientation: ListView.Vertical
model: missionController.visualItems model: _missionController.visualItems
cacheBuffer: Math.max(height * 2, 0) cacheBuffer: Math.max(height * 2, 0)
clip: true clip: true
currentIndex: _currentMissionIndex currentIndex: _currentMissionIndex
highlightMoveDuration: 250 highlightMoveDuration: 250
delegate: MissionItemEditor { delegate: MissionItemEditor {
map: editorMap map: editorMap
missionItem: object missionController: _missionController
width: parent.width missionItem: object
readOnly: false width: parent.width
rootQgcView: _qgcView readOnly: false
rootQgcView: _qgcView
onClicked: setCurrentItem(object.sequenceNumber, false) onClicked: setCurrentItem(object.sequenceNumber, false)
onRemove: { onRemove: {
var removeIndex = index var removeIndex = index
itemDragger.clearItem() _missionController.removeMissionItem(removeIndex)
missionController.removeMissionItem(removeIndex) if (removeIndex >= _missionController.visualItems.count) {
if (removeIndex >= missionController.visualItems.count) {
removeIndex-- removeIndex--
} }
_currentMissionIndex = -1 _currentMissionIndex = -1
...@@ -746,7 +588,7 @@ QGCView { ...@@ -746,7 +588,7 @@ QGCView {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
availableHeight: ScreenTools.availableHeight availableHeight: ScreenTools.availableHeight
myGeoFenceController: geoFenceController myGeoFenceController: _geoFenceController
flightMap: editorMap flightMap: editorMap
visible: _editingLayer == _layerGeoFence visible: _editingLayer == _layerGeoFence
} }
...@@ -760,7 +602,7 @@ QGCView { ...@@ -760,7 +602,7 @@ QGCView {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
visible: _editingLayer == _layerRallyPoints visible: _editingLayer == _layerRallyPoints
controller: rallyPointController controller: _rallyPointController
} }
RallyPointItemEditor { RallyPointItemEditor {
...@@ -769,9 +611,9 @@ QGCView { ...@@ -769,9 +611,9 @@ QGCView {
anchors.top: rallyPointHeader.bottom anchors.top: rallyPointHeader.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
visible: _editingLayer == _layerRallyPoints && rallyPointController.points.count visible: _editingLayer == _layerRallyPoints && _rallyPointController.points.count
rallyPoint: rallyPointController.currentRallyPoint rallyPoint: _rallyPointController.currentRallyPoint
controller: rallyPointController controller: _rallyPointController
} }
} // Right panel } // Right panel
...@@ -790,7 +632,7 @@ QGCView { ...@@ -790,7 +632,7 @@ QGCView {
anchors.left: parent.left anchors.left: parent.left
anchors.right: rightPanel.left anchors.right: rightPanel.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
missionItems: missionController.visualItems missionItems: _missionController.visualItems
visible: _editingLayer === _layerMission && !ScreenTools.isShortScreen visible: _editingLayer === _layerMission && !ScreenTools.isShortScreen
} }
} // QGCViewPanel } // QGCViewPanel
...@@ -802,7 +644,7 @@ QGCView { ...@@ -802,7 +644,7 @@ QGCView {
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?") 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?")
function accept() { function accept() {
hideDialog() hideDialog()
_syncDropDownController.loadFromVehicle() masterController.loadFromVehicle()
} }
} }
} }
...@@ -814,7 +656,7 @@ QGCView { ...@@ -814,7 +656,7 @@ QGCView {
message: qsTr("You have unsaved/unsent changes. Loading a from a file will lose these changes. Are you sure you want to load from a file?") message: qsTr("You have unsaved/unsent changes. Loading a from a file will lose these changes. Are you sure you want to load from a file?")
function accept() { function accept() {
hideDialog() hideDialog()
_syncDropDownController.loadFromSelectedFile() masterController.loadFromSelectedFile()
} }
} }
} }
...@@ -824,8 +666,7 @@ QGCView { ...@@ -824,8 +666,7 @@ QGCView {
QGCViewMessage { QGCViewMessage {
message: qsTr("Are you sure you want to remove all items? This will also remove all items from the vehicle.") message: qsTr("Are you sure you want to remove all items? This will also remove all items from the vehicle.")
function accept() { function accept() {
itemDragger.clearItem() masterController.removeAllFromVehicle()
_syncDropDownController.removeAllFromVehicle()
hideDialog() hideDialog()
} }
} }
...@@ -851,7 +692,7 @@ QGCView { ...@@ -851,7 +692,7 @@ QGCView {
QGCLabel { text: qsTr("Create complex pattern:") } QGCLabel { text: qsTr("Create complex pattern:") }
Repeater { Repeater {
model: missionController.complexMissionItemNames model: _missionController.complexMissionItemNames
QGCButton { QGCButton {
text: modelData text: modelData
...@@ -878,7 +719,7 @@ QGCView { ...@@ -878,7 +719,7 @@ QGCView {
QGCLabel { QGCLabel {
width: sendSaveGrid.width width: sendSaveGrid.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: _syncDropDownController.dirty ? text: masterController.dirty ?
qsTr("You have unsaved changes. You should upload to your vehicle, or save to a file:") : qsTr("You have unsaved changes. You should upload to your vehicle, or save to a file:") :
qsTr("Sync:") qsTr("Sync:")
} }
...@@ -893,23 +734,23 @@ QGCView { ...@@ -893,23 +734,23 @@ QGCView {
QGCButton { QGCButton {
text: qsTr("Upload") text: qsTr("Upload")
Layout.fillWidth: true Layout.fillWidth: true
enabled: _activeVehicle && !_syncDropDownController.syncInProgress enabled: _activeVehicle && !masterController.syncInProgress
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
_syncDropDownController.upload() masterController.upload()
} }
} }
QGCButton { QGCButton {
text: qsTr("Download") text: qsTr("Download")
Layout.fillWidth: true Layout.fillWidth: true
enabled: _activeVehicle && !_syncDropDownController.syncInProgress enabled: _activeVehicle && !masterController.syncInProgress
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
if (_syncDropDownController.dirty) { if (masterController.dirty) {
_qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) _qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else { } else {
_syncDropDownController.loadFromVehicle() masterController.loadFromVehicle()
} }
} }
} }
...@@ -917,23 +758,23 @@ QGCView { ...@@ -917,23 +758,23 @@ QGCView {
QGCButton { QGCButton {
text: qsTr("Save To File...") text: qsTr("Save To File...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !_syncDropDownController.syncInProgress enabled: !masterController.syncInProgress
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
_syncDropDownController.saveToSelectedFile() masterController.saveToSelectedFile()
} }
} }
QGCButton { QGCButton {
text: qsTr("Load From File...") text: qsTr("Load From File...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !_syncDropDownController.syncInProgress enabled: !masterController.syncInProgress
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
if (_syncDropDownController.dirty) { if (masterController.dirty) {
_qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) _qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else { } else {
_syncDropDownController.loadFromSelectedFile() masterController.loadFromSelectedFile()
} }
} }
} }
...@@ -947,14 +788,6 @@ QGCView { ...@@ -947,14 +788,6 @@ QGCView {
} }
} }
} }
FactCheckBox {
text: qsTr("Automatic upload to vehicle")
fact: autoSyncFact
visible: autoSyncFact.visible
property Fact autoSyncFact: QGroundControl.settingsManager.appSettings.automaticMissionUpload
}
} }
} }
} // QGCVIew } // QGCVIew
...@@ -64,9 +64,7 @@ ...@@ -64,9 +64,7 @@
#include "QGroundControlQmlGlobal.h" #include "QGroundControlQmlGlobal.h"
#include "FlightMapSettings.h" #include "FlightMapSettings.h"
#include "CoordinateVector.h" #include "CoordinateVector.h"
#include "MissionController.h" #include "PlanMasterController.h"
#include "GeoFenceController.h"
#include "RallyPointController.h"
#include "VideoManager.h" #include "VideoManager.h"
#include "VideoSurface.h" #include "VideoSurface.h"
#include "VideoReceiver.h" #include "VideoReceiver.h"
...@@ -384,6 +382,7 @@ void QGCApplication::_initCommon(void) ...@@ -384,6 +382,7 @@ void QGCApplication::_initCommon(void)
qmlRegisterType<ParameterEditorController> ("QGroundControl.Controllers", 1, 0, "ParameterEditorController"); qmlRegisterType<ParameterEditorController> ("QGroundControl.Controllers", 1, 0, "ParameterEditorController");
qmlRegisterType<ESP8266ComponentController> ("QGroundControl.Controllers", 1, 0, "ESP8266ComponentController"); qmlRegisterType<ESP8266ComponentController> ("QGroundControl.Controllers", 1, 0, "ESP8266ComponentController");
qmlRegisterType<ScreenToolsController> ("QGroundControl.Controllers", 1, 0, "ScreenToolsController"); qmlRegisterType<ScreenToolsController> ("QGroundControl.Controllers", 1, 0, "ScreenToolsController");
qmlRegisterType<PlanMasterController> ("QGroundControl.Controllers", 1, 0, "PlanElemementMasterController");
qmlRegisterType<MissionController> ("QGroundControl.Controllers", 1, 0, "MissionController"); qmlRegisterType<MissionController> ("QGroundControl.Controllers", 1, 0, "MissionController");
qmlRegisterType<GeoFenceController> ("QGroundControl.Controllers", 1, 0, "GeoFenceController"); qmlRegisterType<GeoFenceController> ("QGroundControl.Controllers", 1, 0, "GeoFenceController");
qmlRegisterType<RallyPointController> ("QGroundControl.Controllers", 1, 0, "RallyPointController"); qmlRegisterType<RallyPointController> ("QGroundControl.Controllers", 1, 0, "RallyPointController");
......
...@@ -34,6 +34,7 @@ const char* AppSettings::autoLoadMissionsName = "AutoLoa ...@@ -34,6 +34,7 @@ const char* AppSettings::autoLoadMissionsName = "AutoLoa
const char* AppSettings::automaticMissionUploadName = "AutomaticMissionUpload"; const char* AppSettings::automaticMissionUploadName = "AutomaticMissionUpload";
const char* AppSettings::parameterFileExtension = "params"; const char* AppSettings::parameterFileExtension = "params";
const char* AppSettings::planFileExtension = "plan";
const char* AppSettings::missionFileExtension = "mission"; const char* AppSettings::missionFileExtension = "mission";
const char* AppSettings::fenceFileExtension = "fence"; const char* AppSettings::fenceFileExtension = "fence";
const char* AppSettings::rallyPointFileExtension = "rally"; const char* AppSettings::rallyPointFileExtension = "rally";
......
...@@ -40,6 +40,7 @@ public: ...@@ -40,6 +40,7 @@ public:
Q_PROPERTY(QString parameterSavePath READ parameterSavePath NOTIFY savePathsChanged) Q_PROPERTY(QString parameterSavePath READ parameterSavePath NOTIFY savePathsChanged)
Q_PROPERTY(QString telemetrySavePath READ telemetrySavePath NOTIFY savePathsChanged) Q_PROPERTY(QString telemetrySavePath READ telemetrySavePath NOTIFY savePathsChanged)
Q_PROPERTY(QString planFileExtension MEMBER planFileExtension CONSTANT)
Q_PROPERTY(QString missionFileExtension MEMBER missionFileExtension CONSTANT) Q_PROPERTY(QString missionFileExtension MEMBER missionFileExtension CONSTANT)
Q_PROPERTY(QString parameterFileExtension MEMBER parameterFileExtension CONSTANT) Q_PROPERTY(QString parameterFileExtension MEMBER parameterFileExtension CONSTANT)
Q_PROPERTY(QString telemetryFileExtension MEMBER telemetryFileExtension CONSTANT) Q_PROPERTY(QString telemetryFileExtension MEMBER telemetryFileExtension CONSTANT)
...@@ -86,6 +87,7 @@ public: ...@@ -86,6 +87,7 @@ public:
// Application wide file extensions // Application wide file extensions
static const char* parameterFileExtension; static const char* parameterFileExtension;
static const char* planFileExtension;
static const char* missionFileExtension; static const char* missionFileExtension;
static const char* fenceFileExtension; static const char* fenceFileExtension;
static const char* rallyPointFileExtension; static const char* rallyPointFileExtension;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "JoystickManager.h" #include "JoystickManager.h"
#include "MissionManager.h" #include "MissionManager.h"
#include "MissionController.h" #include "MissionController.h"
#include "PlanMasterController.h"
#include "GeoFenceManager.h" #include "GeoFenceManager.h"
#include "RallyPointManager.h" #include "RallyPointManager.h"
#include "CoordinateVector.h" #include "CoordinateVector.h"
...@@ -1627,11 +1628,10 @@ void Vehicle::_startMissionRequest(void) ...@@ -1627,11 +1628,10 @@ void Vehicle::_startMissionRequest(void)
if (_settingsManager->appSettings()->autoLoadMissions()->rawValue().toBool()) { if (_settingsManager->appSettings()->autoLoadMissions()->rawValue().toBool()) {
QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionSavePath(); QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionSavePath();
if (!missionAutoLoadDirPath.isEmpty()) { if (!missionAutoLoadDirPath.isEmpty()) {
QmlObjectListModel* visualItems = NULL;
QDir missionAutoLoadDir(missionAutoLoadDirPath); QDir missionAutoLoadDir(missionAutoLoadDirPath);
QString autoloadFilename = missionAutoLoadDir.absoluteFilePath(tr("AutoLoad%1.%2").arg(_id).arg(AppSettings::missionFileExtension)); QString autoloadFilename = missionAutoLoadDir.absoluteFilePath(tr("AutoLoad%1.%2").arg(_id).arg(AppSettings::planFileExtension));
if (MissionController::loadItemsFromFile(this, autoloadFilename, &visualItems)) { if (QFile(autoloadFilename).exists()) {
MissionController::sendItemsToVehicle(this, visualItems); PlanMasterController::sendPlanToVehicle(this, autoloadFilename);
return; return;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment