diff --git a/src/MissionEditor/MissionEditor.cc b/src/MissionEditor/MissionEditor.cc index 3aa1f1a8e624c8492404478806c8ab0b148daef9..688ee145ce66848936d8fddaee5a1eb41227f079 100644 --- a/src/MissionEditor/MissionEditor.cc +++ b/src/MissionEditor/MissionEditor.cc @@ -26,6 +26,7 @@ This file is part of the QGROUNDCONTROL project #include "MultiVehicleManager.h" #include "MissionManager.h" #include "QGCFileDialog.h" +#include "CoordinateVector.h" #include #include @@ -51,6 +52,7 @@ MissionEditor::MissionEditor(QWidget *parent) _newMissionItemsAvailable(); } else { _missionItems = new QmlObjectListModel(this); + connect(_missionItems, &QmlObjectListModel::dirtyChanged, this, &MissionEditor::_missionListDirtyChanged); } setContextPropertyObject("controller", this); @@ -75,6 +77,9 @@ void MissionEditor::_newMissionItemsAvailable(void) _reSequence(); _missionItems->setDirty(false); + connect(_missionItems, &QmlObjectListModel::dirtyChanged, this, &MissionEditor::_missionListDirtyChanged); + _rebuildWaypointLines(); + emit missionItemsChanged(); emit canEditChanged(_canEdit); } @@ -190,7 +195,11 @@ void MissionEditor::loadMissionFromFile(void) return; } - _missionItems->clear(); + if (_missionItems) { + _missionItems->deleteLater(); + } + _missionItems = new QmlObjectListModel(this); + _canEdit = true; QFile file(filename); @@ -229,6 +238,9 @@ void MissionEditor::loadMissionFromFile(void) _missionItems->setDirty(false); emit canEditChanged(_canEdit); + + connect(_missionItems, &QmlObjectListModel::dirtyChanged, this, &MissionEditor::_missionListDirtyChanged); + _rebuildWaypointLines(); } void MissionEditor::saveMissionToFile(void) @@ -256,3 +268,21 @@ void MissionEditor::saveMissionToFile(void) _missionItems->setDirty(false); } + +void MissionEditor::_rebuildWaypointLines(void) +{ + _waypointLines.clear(); + for (int i=1; i<_missionItems->count(); i++) { + MissionItem* item1 = qobject_cast(_missionItems->get(i-1)); + MissionItem* item2 = qobject_cast(_missionItems->get(i)); + + _waypointLines.append(new CoordinateVector(item1->coordinate(), item2->coordinate())); + } + emit waypointLinesChanged(); +} + +void MissionEditor::_missionListDirtyChanged(bool dirty) +{ + Q_UNUSED(dirty); + _rebuildWaypointLines(); +} diff --git a/src/MissionEditor/MissionEditor.h b/src/MissionEditor/MissionEditor.h index dc8821826f28a1ce20ecbccfc85da3681066173a..eed09fc199d7db85054205e70cdbe194373274aa 100644 --- a/src/MissionEditor/MissionEditor.h +++ b/src/MissionEditor/MissionEditor.h @@ -35,7 +35,8 @@ public: MissionEditor(QWidget* parent = NULL); ~MissionEditor(); - Q_PROPERTY(QmlObjectListModel* missionItems READ missionItemsModel NOTIFY missionItemsChanged) + Q_PROPERTY(QmlObjectListModel* missionItems READ missionItems NOTIFY missionItemsChanged) + Q_PROPERTY(QmlObjectListModel* waypointLines READ waypointLines NOTIFY waypointLinesChanged) Q_PROPERTY(bool canEdit READ canEdit NOTIFY canEditChanged) Q_INVOKABLE int addMissionItem(QGeoCoordinate coordinate); @@ -49,21 +50,26 @@ public: // Property accessors - QmlObjectListModel* missionItemsModel(void) { return _missionItems; } + QmlObjectListModel* missionItems(void) { return _missionItems; } + QmlObjectListModel* waypointLines(void) { return &_waypointLines; } bool canEdit(void) { return _canEdit; } signals: void missionItemsChanged(void); void canEditChanged(bool canEdit); + void waypointLinesChanged(void); private slots: void _newMissionItemsAvailable(); + void _missionListDirtyChanged(bool dirty); private: void _reSequence(void); - + void _rebuildWaypointLines(void); + private: QmlObjectListModel* _missionItems; + QmlObjectListModel _waypointLines; bool _canEdit; ///< true: UI can edit these items, false: can't edit, can only send to vehicle or save static const char* _settingsGroup; diff --git a/src/MissionEditor/MissionEditor.qml b/src/MissionEditor/MissionEditor.qml index 1751e19dd71cef96816d62d781577c4ed3d9eb50..28b0e3a984d8e46371121e0753d5c2ae7ed8e1d3 100644 --- a/src/MissionEditor/MissionEditor.qml +++ b/src/MissionEditor/MissionEditor.qml @@ -383,6 +383,7 @@ This code will need to wait for Qml 5.5 support since Map.visibleRegion is only label: "H" isCurrentItem: _showHomePositionManager coordinate: _homePositionCoordinate + z: 2 onClicked: _showHomePositionManager = true } @@ -396,13 +397,59 @@ This code will need to wait for Qml 5.5 support since Map.visibleRegion is only label: object.sequenceNumber isCurrentItem: !_showHomePositionManager && object.isCurrentItem coordinate: object.coordinate + z: 2 onClicked: { _showHomePositionManager = false setCurrentItem(object.sequenceNumber) } + } + } + + MapPolyline { + id: homePositionLine + line.width: 3 + line.color: "orange" + z: 1 + + property var homePositionCoordinate: _homePositionCoordinate + + function update() { + while (homePositionLine.path.length != 0) { + homePositionLine.removeCoordinate(homePositionLine.path[0]) + } + if (_missionItems && _missionItems.count != 0) { + homePositionLine.addCoordinate(homePositionCoordinate) + homePositionLine.addCoordinate(_missionItems.get(0).coordinate) + } + } + + onHomePositionCoordinateChanged: update() - Component.onCompleted: console.log("Indicator", object.coordinate) + Connections { + target: controller + + onWaypointLinesChanged: homePositionLine.update() + } + + Component.onCompleted: homePositionLine.update() + } + + + // Add lines between waypoints + MapItemView { + model: controller.waypointLines + + delegate: + MapPolyline { + line.width: 3 + line.color: "orange" + z: 1 + + path: [ + { latitude: object.coordinate1.latitude, longitude: object.coordinate1.longitude }, + { latitude: object.coordinate2.latitude, longitude: object.coordinate2.longitude }, + ] } } @@ -630,7 +677,8 @@ This code will need to wait for Qml 5.5 support since Map.visibleRegion is only text: "Add/Update" onClicked: { - _homePositionManager.updateHomePosition(nameField.text, QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text)) + _homePositionCoordinate = QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text) + _homePositionManager.updateHomePosition(nameField.text, _homePositionCoordinate) homePosCombo.currentIndex = homePosCombo.find(nameField.text) } } diff --git a/src/MissionItem.cc b/src/MissionItem.cc index 9a9a059bfa1b4bd505ba82b34d75364832ea8f87..febbfed487d509794362dac8d0132b3f9b657162 100644 --- a/src/MissionItem.cc +++ b/src/MissionItem.cc @@ -158,6 +158,11 @@ MissionItem::MissionItem(QObject* parent, connect(_param1Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); connect(_param2Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); connect(_altitudeRelativeToHomeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + + // Connect valueChanged signals so we can output coordinateChanged signal + connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); + connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); + connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); } MissionItem::MissionItem(const MissionItem& other, QObject* parent) @@ -182,6 +187,21 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent) _jumpSequenceMetaData = new FactMetaData(this); _jumpRepeatMetaData = new FactMetaData(this); + // Connect to valueChanged to track dirty state + connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_yawRadiansFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_loiterOrbitRadiusFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_param1Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_param2Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + connect(_altitudeRelativeToHomeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged); + + // Connect valueChanged signals so we can output coordinateChanged signal + connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); + connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); + connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged); + *this = other; } @@ -752,7 +772,6 @@ void MissionItem::setYawRadians(double yaw) if (yawRadians() != yaw) { _yawRadiansFact->setValue(yaw); - emit yawChanged(yaw); emit changed(this); emit valueStringsChanged(valueStrings()); } @@ -813,6 +832,8 @@ bool MissionItem::canEdit(void) void MissionItem::setDirty(bool dirty) { _dirty = dirty; + // We want to emit dirtyChanged even if _dirty didn't change. This can be handy signal for + // any value within the item changing. emit dirtyChanged(_dirty); } @@ -821,3 +842,9 @@ void MissionItem::_factValueChanged(QVariant value) Q_UNUSED(value); setDirty(true); } + +void MissionItem::_coordinateFactChanged(QVariant value) +{ + Q_UNUSED(value); + emit coordinateChanged(coordinate()); +} diff --git a/src/MissionItem.h b/src/MissionItem.h index 5b350318ec07d2f378479218465a442ecfdee274..514816f6195b3748d26e7c16f3357e85808f4bdc 100644 --- a/src/MissionItem.h +++ b/src/MissionItem.h @@ -68,7 +68,6 @@ public: Q_PROPERTY(bool isCurrentItem READ isCurrentItem WRITE setIsCurrentItem NOTIFY isCurrentItemChanged) Q_PROPERTY(bool specifiesCoordinate READ specifiesCoordinate NOTIFY commandChanged) Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged) - Q_PROPERTY(double yaw READ yawDegrees WRITE setYawDegrees NOTIFY yawChanged) Q_PROPERTY(QStringList commandNames READ commandNames CONSTANT) Q_PROPERTY(QString commandName READ commandName NOTIFY commandChanged) Q_PROPERTY(QStringList valueLabels READ valueLabels NOTIFY commandChanged) @@ -189,7 +188,6 @@ signals: void sequenceNumberChanged(int sequenceNumber); void isCurrentItemChanged(bool isCurrentItem); void coordinateChanged(const QGeoCoordinate& coordinate); - void yawChanged(double yaw); void dirtyChanged(bool dirty); /** @brief Announces a change to the waypoint data */ @@ -229,6 +227,7 @@ public: private slots: void _factValueChanged(QVariant value); + void _coordinateFactChanged(QVariant value); private: QString _oneDecimalString(double value); diff --git a/src/QmlControls/QGCCanvas.qml b/src/QmlControls/QGCCanvas.qml index 1b7d6e3b9808e49e9ce3c3e351bb201ac3393e9d..c7f0a12d935606ef803012452333d4b7448b1e46 100644 --- a/src/QmlControls/QGCCanvas.qml +++ b/src/QmlControls/QGCCanvas.qml @@ -9,9 +9,11 @@ import QGroundControl.ScreenTools 1.0 /// are switched. In order to fix this we ahve a signal hacked into ScreenTools to force /// a repaint. Canvas { + id: _root + Connections { target: ScreenTools - onRepaintRequested: arrowCanvas.requestPaint() + onRepaintRequested: _root.requestPaint() } } diff --git a/src/QmlControls/QmlObjectListModel.cc b/src/QmlControls/QmlObjectListModel.cc index b9f1da05303a1aa8cbcaa3af6e3a83065850af1e..98421f0b15a33ed99ee45bc752a104f71af42e32 100644 --- a/src/QmlControls/QmlObjectListModel.cc +++ b/src/QmlControls/QmlObjectListModel.cc @@ -149,20 +149,18 @@ void QmlObjectListModel::clear(void) void QmlObjectListModel::removeAt(int i) { - setDirty(true); - // Look for a dirtyChanged signal on the object if (_objectList[i]->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) { QObject::disconnect(_objectList[i], SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool))); } removeRows(i, 1); + + setDirty(true); } void QmlObjectListModel::insert(int i, QObject* object) { - setDirty(true); - if (i < 0 || i > _objectList.count()) { qWarning() << "Invalid index index:count" << i << _objectList.count(); } @@ -176,6 +174,8 @@ void QmlObjectListModel::insert(int i, QObject* object) _objectList.insert(i, object); insertRows(i, 1); + + setDirty(true); } void QmlObjectListModel::append(QObject* object) @@ -212,5 +212,7 @@ void QmlObjectListModel::setDirty(bool dirty) void QmlObjectListModel::_childDirtyChanged(bool dirty) { _dirty |= dirty; + // We want to emit dirtyChanged even if the actual value of _dirty didn't change. It can be a useful + // signal to know when a child has changed dirty state emit dirtyChanged(_dirty); }