Commit e7c88789 authored by Don Gagne's avatar Don Gagne

Correctly handle large numbers of waypoints

parent 4aff4121
......@@ -383,8 +383,7 @@ QGCView {
spacing: _margin / 2
orientation: ListView.Vertical
model: controller.missionItems
property real _maxItemHeight: 0
cacheBuffer: height * 2
delegate: MissionItemEditor {
missionItem: object
......@@ -399,11 +398,6 @@ QGCView {
controller.removeMissionItem(object.sequenceNumber)
}
onRemoveAll: {
itemDragger.clearItem()
controller.removeAllMissionItems()
}
onInsert: {
controller.insertMissionItem(editorMap.center, i)
setCurrentItem(i)
......@@ -601,6 +595,20 @@ QGCView {
}
}
Component {
id: removeAllPromptDialog
QGCViewMessage {
message: "Are you sure you want to delete all mission items?"
function accept() {
itemDragger.clearItem()
controller.removeAllMissionItems()
hideDialog()
}
}
}
Component {
id: syncDropDownComponent
......@@ -671,6 +679,15 @@ QGCView {
}
}
}
QGCButton {
text: "Remove all"
onClicked: {
syncButton.hideDropDown()
_root.showDialog(removeAllPromptDialog, "Delete all", _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
}
}
/*
FIXME: autoSync is temporarily disconnected since it's still buggy
......
......@@ -72,7 +72,7 @@ void MissionController::start(bool editMode)
// We start with an empty mission
_missionItems = new QmlObjectListModel(this);
_addPlannedHomePosition(false /* addToCenter */);
_addPlannedHomePosition(_missionItems, false /* addToCenter */);
_initAllMissionItems();
}
......@@ -94,7 +94,7 @@ void MissionController::_newMissionItemsAvailableFromVehicle(void)
qCDebug(MissionControllerLog) << "loading from vehicle count"<< _missionItems->count();
if (!_activeVehicle->firmwarePlugin()->sendHomePositionToVehicle() || _missionItems->count() == 0) {
_addPlannedHomePosition(true /* addToCenter */);
_addPlannedHomePosition(_missionItems,true /* addToCenter */);
}
_missionItemsRequested = false;
......@@ -176,14 +176,16 @@ void MissionController::removeMissionItem(int index)
void MissionController::removeAllMissionItems(void)
{
if (_missionItems) {
while (_missionItems->count() != 1) {
removeMissionItem(_missionItems->count() - 1);
}
QmlObjectListModel* oldItems = _missionItems;
_missionItems = new QmlObjectListModel(this);
_addPlannedHomePosition(_missionItems, false /* addToCenter */);
_initAllMissionItems();
oldItems->deleteLater();
}
}
#ifndef __mobile__
bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QString& errorString)
bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QmlObjectListModel* missionItems, QString& errorString)
{
QJsonParseError jsonParseError;
QJsonDocument jsonDoc(QJsonDocument::fromJson(bytes, &jsonParseError));
......@@ -219,7 +221,7 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QString& e
MissionItem* item = new MissionItem(_activeVehicle, this);
if (item->load(itemValue.toObject(), errorString)) {
_missionItems->append(item);
missionItems->append(item);
} else {
return false;
}
......@@ -230,12 +232,12 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QString& e
MissionItem* item = new MissionItem(_activeVehicle, this);
if (item->load(json[_jsonPlannedHomePositionKey].toObject(), errorString)) {
_missionItems->insert(0, item);
missionItems->insert(0, item);
} else {
return false;
}
} else {
_addPlannedHomePosition(true /* addToCenter */);
_addPlannedHomePosition(missionItems, true /* addToCenter */);
}
return true;
......@@ -243,7 +245,7 @@ bool MissionController::_loadJsonMissionFile(const QByteArray& bytes, QString& e
#endif
#ifndef __mobile__
bool MissionController::_loadTextMissionFile(QTextStream& stream, QString& errorString)
bool MissionController::_loadTextMissionFile(QTextStream& stream, QmlObjectListModel* missionItems, QString& errorString)
{
bool addPlannedHomePosition = false;
......@@ -267,7 +269,7 @@ bool MissionController::_loadTextMissionFile(QTextStream& stream, QString& error
MissionItem* item = new MissionItem(_activeVehicle, this);
if (item->load(stream)) {
_missionItems->append(item);
missionItems->append(item);
} else {
errorString = QStringLiteral("The mission file is corrupted.");
return false;
......@@ -278,12 +280,12 @@ bool MissionController::_loadTextMissionFile(QTextStream& stream, QString& error
return false;
}
if (addPlannedHomePosition || _missionItems->count() == 0) {
_addPlannedHomePosition(true /* addToCenter */);
if (addPlannedHomePosition || missionItems->count() == 0) {
_addPlannedHomePosition(missionItems, true /* addToCenter */);
// Update sequence numbers in DO_JUMP commands to take into account added home position
for (int i=1; i<_missionItems->count(); i++) {
MissionItem* item = qobject_cast<MissionItem*>(_missionItems->get(i));
for (int i=1; i<missionItems->count(); i++) {
MissionItem* item = qobject_cast<MissionItem*>(missionItems->get(i));
if (item->command() == MavlinkQmlSingleton::MAV_CMD_DO_JUMP) {
// Home is in position 0
item->setParam1((int)item->param1() + 1);
......@@ -305,11 +307,7 @@ void MissionController::loadMissionFromFile(void)
return;
}
if (_missionItems) {
_deinitAllMissionItems();
_missionItems->deleteLater();
}
_missionItems = new QmlObjectListModel(this);
QmlObjectListModel* newMissionItems = new QmlObjectListModel(this);
QFile file(filename);
......@@ -322,19 +320,25 @@ void MissionController::loadMissionFromFile(void)
QString firstLine = stream.readLine();
if (firstLine.contains(QRegExp("QGC.*WPL"))) {
stream.seek(0);
_loadTextMissionFile(stream, errorString);
_loadTextMissionFile(stream, newMissionItems, errorString);
} else {
_loadJsonMissionFile(bytes, errorString);
_loadJsonMissionFile(bytes, newMissionItems, errorString);
}
}
if (!errorString.isEmpty()) {
_missionItems->clear();
delete newMissionItems;
qgcApp()->showMessage(errorString);
return;
}
if (_missionItems) {
_deinitAllMissionItems();
_missionItems->deleteLater();
}
_missionItems = newMissionItems;
if (_missionItems->count() == 0) {
_addPlannedHomePosition(true /* addToCenter */);
_addPlannedHomePosition(_missionItems, true /* addToCenter */);
}
_initAllMissionItems();
......@@ -786,21 +790,21 @@ double MissionController::_normalizeLon(double lon)
}
/// Add the home position item to the front of the list
void MissionController::_addPlannedHomePosition(bool addToCenter)
void MissionController::_addPlannedHomePosition(QmlObjectListModel* missionItems, bool addToCenter)
{
MissionItem* homeItem = new MissionItem(_activeVehicle, this);
_missionItems->insert(0, homeItem);
missionItems->insert(0, homeItem);
if (_missionItems->count() > 1 && addToCenter) {
MissionItem* item = qobject_cast<MissionItem*>(_missionItems->get(1));
if (missionItems->count() > 1 && addToCenter) {
MissionItem* item = qobject_cast<MissionItem*>(missionItems->get(1));
double north = _normalizeLat(item->coordinate().latitude());
double south = north;
double east = _normalizeLon(item->coordinate().longitude());
double west = east;
for (int i=2; i<_missionItems->count(); i++) {
item = qobject_cast<MissionItem*>(_missionItems->get(i));
for (int i=2; i<missionItems->count(); i++) {
item = qobject_cast<MissionItem*>(missionItems->get(i));
double lat = _normalizeLat(item->coordinate().latitude());
double lon = _normalizeLon(item->coordinate().longitude());
......
......@@ -94,12 +94,12 @@ private:
void _calcPrevWaypointValues(double homeAlt, MissionItem* currentItem, MissionItem* prevItem, double* azimuth, double* distance, double* altDifference);
bool _findLastAltitude(double* lastAltitude);
bool _findLastAcceptanceRadius(double* lastAcceptanceRadius);
void _addPlannedHomePosition(bool addToCenter);
void _addPlannedHomePosition(QmlObjectListModel* missionItems, bool addToCenter);
double _normalizeLat(double lat);
double _normalizeLon(double lon);
#ifndef __mobile__
bool _loadJsonMissionFile(const QByteArray& bytes, QString& errorString);
bool _loadTextMissionFile(QTextStream& stream, QString& errorString);
bool _loadJsonMissionFile(const QByteArray& bytes, QmlObjectListModel* missionItems, QString& errorString);
bool _loadTextMissionFile(QTextStream& stream, QmlObjectListModel* missionItems, QString& errorString);
#endif
private:
......
......@@ -20,7 +20,6 @@ Rectangle {
signal clicked
signal remove
signal removeAll
signal insert(int i)
signal moveHomeToMapCenter
......@@ -32,22 +31,123 @@ Rectangle {
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2
property bool _showValues: missionItem.isCurrentItem
QGCPalette {
id: qgcPal
colorGroupEnabled: enabled
}
Component {
id: deleteAllPromptDialog
id: valuesComponent
QGCViewMessage {
message: "Are you sure you want to delete all mission items?"
Rectangle {
id: valuesRect
height: valuesItem.height
color: qgcPal.windowShadeDark
visible: missionItem.isCurrentItem
radius: _radius
Item {
id: valuesItem
anchors.margins: _margin
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: valuesColumn.height + _margin
Column {
id: valuesColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: _margin
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: missionItem.sequenceNumber == 0 ?
"Planned home position." :
(missionItem.rawEdit ?
"Provides advanced access to all commands/parameters. Be very careful!" :
missionItem.commandDescription)
}
Repeater {
model: missionItem.comboboxFacts
Item {
width: valuesColumn.width
height: comboBoxFact.height
QGCLabel {
id: comboBoxLabel
anchors.baseline: comboBoxFact.baseline
text: object.name
visible: object.name != ""
}
FactComboBox {
id: comboBoxFact
anchors.right: parent.right
width: comboBoxLabel.visible ? _editFieldWidth : parent.width
indexModel: false
model: object.enumStrings
fact: object
}
}
}
Repeater {
model: missionItem.textFieldFacts
Item {
width: valuesColumn.width
height: textField.height
QGCLabel {
id: textFieldLabel
anchors.baseline: textField.baseline
text: object.name
}
FactTextField {
id: textField
anchors.right: parent.right
width: _editFieldWidth
showUnits: true
fact: object
visible: !_root.readOnly
}
FactLabel {
anchors.baseline: textFieldLabel.baseline
anchors.right: parent.right
fact: object
visible: _root.readOnly
}
}
}
Repeater {
model: missionItem.checkboxFacts
FactCheckBox {
text: object.name
fact: object
}
}
QGCButton {
text: "Move Home to map center"
visible: missionItem.homePosition
onClicked: moveHomeToMapCenter()
anchors.horizontalCenter: parent.horizontalCenter
}
} // Column
} // Item
} // Rectangle
function accept() {
removeAll()
hideDialog()
}
}
}
Item {
......@@ -56,7 +156,7 @@ Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: valuesRect.visible ? valuesRect.y + valuesRect.height : valuesRect.y
height: _showValues ? valuesLoader.y + valuesLoader.height : valuesLoader.y
MouseArea {
anchors.fill: parent
......@@ -99,12 +199,6 @@ Rectangle {
onTriggered: remove()
}
MenuItem {
text: "Delete all"
onTriggered: qgcView.showDialog(deleteAllPromptDialog, "Delete all", qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
}
MenuSeparator { }
MenuItem {
......@@ -157,115 +251,13 @@ Rectangle {
color: qgcPal.buttonText
}
Rectangle {
id: valuesRect
Loader {
id: valuesLoader
anchors.topMargin: _margin
anchors.top: commandPicker.bottom
anchors.left: parent.left
anchors.right: parent.right
height: valuesItem.height
color: qgcPal.windowShadeDark
visible: missionItem.isCurrentItem
radius: _radius
Item {
id: valuesItem
anchors.margins: _margin
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: valuesColumn.height + _margin
Column {
id: valuesColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: _margin
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: missionItem.sequenceNumber == 0 ?
"Planned home position." :
(missionItem.rawEdit ?
"Provides advanced access to all commands/parameters. Be very careful!" :
missionItem.commandDescription)
}
Repeater {
model: missionItem.comboboxFacts
Item {
width: valuesColumn.width
height: comboBoxFact.height
QGCLabel {
id: comboBoxLabel
anchors.baseline: comboBoxFact.baseline
text: object.name
visible: object.name != ""
}
FactComboBox {
id: comboBoxFact
anchors.right: parent.right
width: comboBoxLabel.visible ? _editFieldWidth : parent.width
indexModel: false
model: object.enumStrings
fact: object
}
}
}
Repeater {
model: missionItem.textFieldFacts
Item {
width: valuesColumn.width
height: textField.height
QGCLabel {
id: textFieldLabel
anchors.baseline: textField.baseline
text: object.name
}
FactTextField {
id: textField
anchors.right: parent.right
width: _editFieldWidth
showUnits: true
fact: object
visible: !_root.readOnly
}
FactLabel {
anchors.baseline: textFieldLabel.baseline
anchors.right: parent.right
fact: object
visible: _root.readOnly
}
}
}
Repeater {
model: missionItem.checkboxFacts
FactCheckBox {
text: object.name
fact: object
}
}
QGCButton {
text: "Move Home to map center"
visible: missionItem.homePosition
onClicked: moveHomeToMapCenter()
anchors.horizontalCenter: parent.horizontalCenter
}
} // Column
} // Item
} // Rectangle
sourceComponent: _showValues ? valuesComponent : undefined
}
} // Item
} // Rectangle
{
"MAV_AUTOPILOT": 3,
"groundStation": "QGroundControl",
"items": [
{
"autoContinue": true,
"command": 22,
"coordinate": [
0,
0,
30
],
"frame": 2,
"id": 1,
"param1": 20,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.469586999999997,
-112.534801,
90
],
"frame": 3,
"id": 2,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 206,
"coordinate": [
0,
0,
0
],
"frame": 2,
"id": 3,
"param1": 21.059999000000001,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.462736,
-112.53540099999999,
90
],
"frame": 3,
"id": 4,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.462833000000003,
-112.535104,
90
],
"frame": 3,
"id": 5,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.484993000000003,
-112.533163,
90
],
"frame": 3,
"id": 6,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.500399000000002,
-112.531524,
90
],
"frame": 3,
"id": 7,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.46293,
-112.534807,
90
],
"frame": 3,
"id": 8,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.463026999999997,
-112.53451,
90
],
"frame": 3,
"id": 9,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.515805,
-112.529884,
90
],
"frame": 3,
"id": 10,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.531210999999999,
-112.528244,
90
],
"frame": 3,
"id": 11,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.463124000000001,
-112.53421299999999,
90
],
"frame": 3,
"id": 12,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.463220999999997,
-112.533916,
90
],
"frame": 3,
"id": 13,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
34.546616,
-112.52660400000001,