Browse Source

Merge pull request #6606 from mavlink/syncRework

Turn "Sync" menu into a proper "File" menu
QGC4.4
Gus Grubba 7 years ago committed by GitHub
parent
commit
a99d190a6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      src/MissionManager/PlanMasterController.cc
  2. 5
      src/MissionManager/PlanMasterController.h
  3. 120
      src/PlanView/PlanView.qml
  4. 4
      src/QmlControls/DropPanel.qml
  5. 10
      src/QmlControls/ToolStrip.qml
  6. 2
      src/api/QGCOptions.h

41
src/MissionManager/PlanMasterController.cc

@ -280,6 +280,7 @@ void PlanMasterController::loadFromFile(const QString& filename)
return; return;
} }
QFileInfo fileInfo(filename);
QFile file(filename); QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
@ -288,8 +289,8 @@ void PlanMasterController::loadFromFile(const QString& filename)
return; return;
} }
QString fileExtension(".%1"); bool success = false;
if (filename.endsWith(fileExtension.arg(AppSettings::planFileExtension))) { if(fileInfo.suffix() == AppSettings::planFileExtension) {
QJsonDocument jsonDoc; QJsonDocument jsonDoc;
QByteArray bytes = file.readAll(); QByteArray bytes = file.readAll();
@ -319,17 +320,31 @@ void PlanMasterController::loadFromFile(const QString& filename)
!_geoFenceController.load(json[_jsonGeoFenceObjectKey].toObject(), errorString) || !_geoFenceController.load(json[_jsonGeoFenceObjectKey].toObject(), errorString) ||
!_rallyPointController.load(json[_jsonRallyPointsObjectKey].toObject(), errorString)) { !_rallyPointController.load(json[_jsonRallyPointsObjectKey].toObject(), errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString)); qgcApp()->showMessage(errorMessage.arg(errorString));
} else {
success = true;
} }
} else if (filename.endsWith(fileExtension.arg(AppSettings::missionFileExtension))) { } else if (fileInfo.suffix() == AppSettings::missionFileExtension) {
if (!_missionController.loadJsonFile(file, errorString)) { if (!_missionController.loadJsonFile(file, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString)); qgcApp()->showMessage(errorMessage.arg(errorString));
} else {
success = true;
} }
} else if (filename.endsWith(fileExtension.arg(AppSettings::waypointsFileExtension)) || } else if (fileInfo.suffix() == AppSettings::waypointsFileExtension || fileInfo.suffix() == QStringLiteral("txt")) {
filename.endsWith(fileExtension.arg(QStringLiteral("txt")))) {
if (!_missionController.loadTextFile(file, errorString)) { if (!_missionController.loadTextFile(file, errorString)) {
qgcApp()->showMessage(errorMessage.arg(errorString)); qgcApp()->showMessage(errorMessage.arg(errorString));
} else {
success = true;
} }
} else {
//-- TODO: What then?
}
if(success){
_currentPlanFile.sprintf("%s/%s.%s", fileInfo.path().toLocal8Bit().data(), fileInfo.completeBaseName().toLocal8Bit().data(), AppSettings::planFileExtension);
} else {
_currentPlanFile.clear();
} }
emit currentPlanFileChanged();
if (!offline()) { if (!offline()) {
setDirty(true); setDirty(true);
@ -352,6 +367,14 @@ QJsonDocument PlanMasterController::saveToJson()
return QJsonDocument(planJson); return QJsonDocument(planJson);
} }
void
PlanMasterController::saveToCurrent()
{
if(!_currentPlanFile.isEmpty()) {
saveToFile(_currentPlanFile);
}
}
void PlanMasterController::saveToFile(const QString& filename) void PlanMasterController::saveToFile(const QString& filename)
{ {
if (filename.isEmpty()) { if (filename.isEmpty()) {
@ -367,9 +390,15 @@ void PlanMasterController::saveToFile(const QString& filename)
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qgcApp()->showMessage(tr("Plan save error %1 : %2").arg(filename).arg(file.errorString())); qgcApp()->showMessage(tr("Plan save error %1 : %2").arg(filename).arg(file.errorString()));
_currentPlanFile.clear();
emit currentPlanFileChanged();
} else { } else {
QJsonDocument saveDoc = saveToJson(); QJsonDocument saveDoc = saveToJson();
file.write(saveDoc.toJson()); file.write(saveDoc.toJson());
if(_currentPlanFile != planFilename) {
_currentPlanFile = planFilename;
emit currentPlanFileChanged();
}
} }
// Only clear dirty bit if we are offline // Only clear dirty bit if we are offline
@ -411,6 +440,8 @@ void PlanMasterController::removeAll(void)
_missionController.setDirty(false); _missionController.setDirty(false);
_geoFenceController.setDirty(false); _geoFenceController.setDirty(false);
_rallyPointController.setDirty(false); _rallyPointController.setDirty(false);
_currentPlanFile.clear();
emit currentPlanFileChanged();
} }
} }

5
src/MissionManager/PlanMasterController.h

@ -40,6 +40,7 @@ public:
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) ///< File extension for missions Q_PROPERTY(QString fileExtension READ fileExtension CONSTANT) ///< File extension for missions
Q_PROPERTY(QString kmlFileExtension READ kmlFileExtension CONSTANT) Q_PROPERTY(QString kmlFileExtension READ kmlFileExtension CONSTANT)
Q_PROPERTY(QString currentPlanFile READ currentPlanFile NOTIFY currentPlanFileChanged)
///< kml file extension for missions ///< kml file extension for missions
Q_PROPERTY(QStringList loadNameFilters READ loadNameFilters CONSTANT) ///< File filter list loading plan files 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 Q_PROPERTY(QStringList saveNameFilters READ saveNameFilters CONSTANT) ///< File filter list saving plan files
@ -63,6 +64,7 @@ public:
Q_INVOKABLE void loadFromVehicle(void); Q_INVOKABLE void loadFromVehicle(void);
Q_INVOKABLE void sendToVehicle(void); Q_INVOKABLE void sendToVehicle(void);
Q_INVOKABLE void loadFromFile(const QString& filename); Q_INVOKABLE void loadFromFile(const QString& filename);
Q_INVOKABLE void saveToCurrent();
Q_INVOKABLE void saveToFile(const QString& filename); Q_INVOKABLE void saveToFile(const QString& filename);
Q_INVOKABLE void saveToKml(const QString& filename); Q_INVOKABLE void saveToKml(const QString& filename);
Q_INVOKABLE void removeAll(void); ///< Removes all from controller only, synce required to remove from vehicle Q_INVOKABLE void removeAll(void); ///< Removes all from controller only, synce required to remove from vehicle
@ -79,6 +81,7 @@ public:
void setDirty (bool dirty); void setDirty (bool dirty);
QString fileExtension (void) const; QString fileExtension (void) const;
QString kmlFileExtension(void) const; QString kmlFileExtension(void) const;
QString currentPlanFile (void) const { return _currentPlanFile; }
QStringList loadNameFilters (void) const; QStringList loadNameFilters (void) const;
QStringList saveNameFilters (void) const; QStringList saveNameFilters (void) const;
QStringList fileKmlFilters (void) const; QStringList fileKmlFilters (void) const;
@ -93,6 +96,7 @@ signals:
void syncInProgressChanged (void); void syncInProgressChanged (void);
void dirtyChanged (bool dirty); void dirtyChanged (bool dirty);
void offlineChanged (bool offlineEditing); void offlineChanged (bool offlineEditing);
void currentPlanFileChanged ();
private slots: private slots:
void _activeVehicleChanged(Vehicle* activeVehicle); void _activeVehicleChanged(Vehicle* activeVehicle);
@ -118,6 +122,7 @@ private:
bool _loadRallyPoints; bool _loadRallyPoints;
bool _sendGeoFence; bool _sendGeoFence;
bool _sendRallyPoints; bool _sendRallyPoints;
QString _currentPlanFile;
static const int _planFileVersion; static const int _planFileVersion;
static const char* _planFileType; static const char* _planFileType;

120
src/PlanView/PlanView.qml

@ -524,17 +524,23 @@ QGCView {
color: qgcPal.window color: qgcPal.window
title: qsTr("Plan") title: qsTr("Plan")
z: QGroundControl.zOrderWidgets z: QGroundControl.zOrderWidgets
showAlternateIcon: [ false, false, false, masterController.dirty, false, false, false ] showAlternateIcon: [ masterController.dirty, false, false, false, false, false, false ]
rotateImage: [ false, false, false, masterController.syncInProgress, false, false, false ] rotateImage: [ masterController.syncInProgress, false, false, false, false, false, false ]
animateImage: [ false, false, false, masterController.dirty, false, false, false ] animateImage: [ masterController.dirty, false, false, false, false, false, false ]
buttonEnabled: [ true, true, true, !masterController.syncInProgress, true, true, true ] buttonEnabled: [ !masterController.syncInProgress, true, true, true, true, true, true ]
buttonVisible: [ true, _waypointsOnlyMode, true, true, true, _showZoom, _showZoom ] buttonVisible: [ true, true, _waypointsOnlyMode, true, true, _showZoom, _showZoom ]
maxHeight: mapScale.y - toolStrip.y maxHeight: mapScale.y - toolStrip.y
property bool _showZoom: !ScreenTools.isMobile property bool _showZoom: !ScreenTools.isMobile
model: [ model: [
{ {
name: "File",
iconSource: "/qmlimages/MapSync.svg",
alternateIconSource: "/qmlimages/MapSyncChanged.svg",
dropPanelComponent: syncDropPanel
},
{
name: "Waypoint", name: "Waypoint",
iconSource: "/qmlimages/MapAddMission.svg", iconSource: "/qmlimages/MapAddMission.svg",
toggle: true toggle: true
@ -550,12 +556,6 @@ QGCView {
dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel
}, },
{ {
name: "Sync",
iconSource: "/qmlimages/MapSync.svg",
alternateIconSource: "/qmlimages/MapSyncChanged.svg",
dropPanelComponent: syncDropPanel
},
{
name: "Center", name: "Center",
iconSource: "/qmlimages/MapCenter.svg", iconSource: "/qmlimages/MapCenter.svg",
dropPanelComponent: centerMapDropPanel dropPanelComponent: centerMapDropPanel
@ -802,7 +802,7 @@ QGCView {
Component { Component {
id: removeAllPromptDialog id: removeAllPromptDialog
QGCViewMessage { QGCViewMessage {
message: qsTr("Are you sure you want to remove all items? ") + message: qsTr("Are you sure you want to remove all items and create a new plan? ") +
(_planMasterController.offline ? "" : qsTr("This will also remove all items from the vehicle.")) (_planMasterController.offline ? "" : qsTr("This will also remove all items from the vehicle."))
function accept() { function accept() {
if (_planMasterController.offline) { if (_planMasterController.offline) {
@ -815,6 +815,17 @@ QGCView {
} }
} }
Component {
id: clearVehicleMissionDialog
QGCViewMessage {
message: qsTr("Are you sure you want to remove all mission items and clear the mission from the vehicle?")
function accept() {
masterController.removeAllFromVehicle()
hideDialog()
}
}
}
//- ToolStrip DropPanel Components //- ToolStrip DropPanel Components
Component { Component {
@ -863,8 +874,11 @@ QGCView {
width: sendSaveGrid.width width: sendSaveGrid.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: masterController.dirty ? text: masterController.dirty ?
(_activeVehicle ?
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("You have unsaved changes.")
) :
qsTr("Plan File:")
} }
GridLayout { GridLayout {
@ -875,50 +889,50 @@ QGCView {
columnSpacing: ScreenTools.defaultFontPixelWidth columnSpacing: ScreenTools.defaultFontPixelWidth
QGCButton { QGCButton {
text: qsTr("Upload") text: qsTr("New...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.offline && !masterController.syncInProgress enabled: _visualItems.count > 1
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
masterController.upload() _qgcView.showDialog(removeAllPromptDialog, qsTr("New Plan"), _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
} }
} }
QGCButton { QGCButton {
text: qsTr("Download") text: qsTr("Open...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.offline && !masterController.syncInProgress enabled: !masterController.syncInProgress
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
if (masterController.dirty) { if (masterController.dirty) {
_qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) _qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else { } else {
masterController.loadFromVehicle() masterController.loadFromSelectedFile()
} }
} }
} }
QGCButton { QGCButton {
text: qsTr("Save Plan...") text: qsTr("Save")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.syncInProgress enabled: !masterController.syncInProgress && masterController.currentPlanFile !== ""
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
if(masterController.currentPlanFile !== "") {
masterController.saveToCurrent()
} else {
masterController.saveToSelectedFile() masterController.saveToSelectedFile()
} }
} }
}
QGCButton { QGCButton {
text: qsTr("Load Plan...") text: qsTr("Save As...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.syncInProgress enabled: !masterController.syncInProgress && _visualItems.count > 1
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
if (masterController.dirty) { masterController.saveToSelectedFile()
_qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else {
masterController.loadFromSelectedFile()
}
} }
} }
@ -936,9 +950,9 @@ QGCView {
QGCButton { QGCButton {
text: qsTr("Save KML...") text: qsTr("Save KML...")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.syncInProgress enabled: !masterController.syncInProgress && _visualItems.count > 1
onClicked: { onClicked: {
// First point do not count // First point does not count
if (_visualItems.count < 2) { if (_visualItems.count < 2) {
_qgcView.showDialog(noItemForKML, qsTr("KML"), _qgcView.showDialogDefaultWidth, StandardButton.Cancel) _qgcView.showDialog(noItemForKML, qsTr("KML"), _qgcView.showDialogDefaultWidth, StandardButton.Cancel)
return return
@ -948,15 +962,55 @@ QGCView {
} }
} }
Rectangle {
width: parent.width * 0.8
height: 1
color: qgcPal.text
opacity: 0.5
visible: !QGroundControl.corePlugin.options.disableVehicleConnection
Layout.fillWidth: true
Layout.columnSpan: 2
}
QGCButton {
text: qsTr("Upload")
Layout.fillWidth: true
enabled: !masterController.offline && !masterController.syncInProgress && _visualItems.count > 1
visible: !QGroundControl.corePlugin.options.disableVehicleConnection
onClicked: {
dropPanel.hide()
masterController.upload()
}
}
QGCButton { QGCButton {
text: qsTr("Remove All") text: qsTr("Download")
Layout.fillWidth: true Layout.fillWidth: true
enabled: !masterController.offline && !masterController.syncInProgress
visible: !QGroundControl.corePlugin.options.disableVehicleConnection
onClicked: { onClicked: {
dropPanel.hide() dropPanel.hide()
_qgcView.showDialog(removeAllPromptDialog, qsTr("Remove all"), _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No) if (masterController.dirty) {
_qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else {
masterController.loadFromVehicle()
} }
} }
} }
QGCButton {
text: qsTr("Clear Vehicle Mission")
Layout.fillWidth: true
Layout.columnSpan: 2
enabled: !masterController.offline && !masterController.syncInProgress
visible: !QGroundControl.corePlugin.options.disableVehicleConnection
onClicked: {
dropPanel.hide()
_qgcView.showDialog(clearVehicleMissionDialog, text, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
}
}
}
} }
} }
} // QGCVIew } // QGCVIew

4
src/QmlControls/DropPanel.qml

@ -74,8 +74,8 @@ Item {
var panelComponentWidth = panelLoader.item.width var panelComponentWidth = panelLoader.item.width
var panelComponentHeight = panelLoader.item.height var panelComponentHeight = panelLoader.item.height
dropDownItem.width = panelComponentWidth + _dropMarginX2 + _arrowPointWidth dropDownItem.width = panelComponentWidth + (_dropMarginX2 * 2) + _arrowPointWidth
dropDownItem.height = panelComponentHeight + _dropMarginX2 dropDownItem.height = panelComponentHeight + (_dropMarginX2 * 2)
dropDownItem.x = _dropEdgeTopPoint.x + _dropMargin dropDownItem.x = _dropEdgeTopPoint.x + _dropMargin
dropDownItem.y = _dropEdgeTopPoint.y -(dropDownItem.height / 2) + radius dropDownItem.y = _dropEdgeTopPoint.y -(dropDownItem.height / 2) + radius

10
src/QmlControls/ToolStrip.qml

@ -16,7 +16,7 @@ import QGroundControl.Palette 1.0
Rectangle { Rectangle {
id: _root id: _root
color: qgcPal.window color: qgcPal.window
width: ScreenTools.isMobile ? ScreenTools.minTouchPixels : ScreenTools.defaultFontPixelWidth * 6 width: ScreenTools.isMobile ? ScreenTools.minTouchPixels : ScreenTools.defaultFontPixelWidth * 7
height: buttonStripColumn.height + (buttonStripColumn.anchors.margins * 2) height: buttonStripColumn.height + (buttonStripColumn.anchors.margins * 2)
radius: _radius radius: _radius
border.width: 1 border.width: 1
@ -133,7 +133,7 @@ Rectangle {
id: scope id: scope
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: width height: width * 0.8
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -141,9 +141,11 @@ Rectangle {
QGCColoredImage { QGCColoredImage {
id: button id: button
anchors.fill: parent height: parent.height
width: height
anchors.centerIn: parent
source: _source source: _source
sourceSize.height: parent.height sourceSize.height: height
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
mipmap: true mipmap: true
smooth: true smooth: true

2
src/api/QGCOptions.h

@ -49,6 +49,7 @@ public:
Q_PROPERTY(bool guidedActionsRequireRCRSSI READ guidedActionsRequireRCRSSI CONSTANT) Q_PROPERTY(bool guidedActionsRequireRCRSSI READ guidedActionsRequireRCRSSI CONSTANT)
Q_PROPERTY(bool showMissionAbsoluteAltitude READ showMissionAbsoluteAltitude NOTIFY showMissionAbsoluteAltitudeChanged) Q_PROPERTY(bool showMissionAbsoluteAltitude READ showMissionAbsoluteAltitude NOTIFY showMissionAbsoluteAltitudeChanged)
Q_PROPERTY(bool showSimpleMissionStart READ showSimpleMissionStart NOTIFY showSimpleMissionStartChanged) Q_PROPERTY(bool showSimpleMissionStart READ showSimpleMissionStart NOTIFY showSimpleMissionStartChanged)
Q_PROPERTY(bool disableVehicleConnection READ disableVehicleConnection CONSTANT)
/// Should QGC hide its settings menu and colapse it into one single menu (Settings and Vehicle Setup)? /// Should QGC hide its settings menu and colapse it into one single menu (Settings and Vehicle Setup)?
/// @return true if QGC should consolidate both menus into one. /// @return true if QGC should consolidate both menus into one.
@ -90,6 +91,7 @@ public:
virtual bool showOfflineMapImport () const { return true; } virtual bool showOfflineMapImport () const { return true; }
virtual bool showMissionAbsoluteAltitude () const { return true; } virtual bool showMissionAbsoluteAltitude () const { return true; }
virtual bool showSimpleMissionStart () const { return false; } virtual bool showSimpleMissionStart () const { return false; }
virtual bool disableVehicleConnection () const { return false; } ///< true: vehicle connection is disabled
#if defined(__mobile__) #if defined(__mobile__)
virtual bool useMobileFileDialog () const { return true;} virtual bool useMobileFileDialog () const { return true;}

Loading…
Cancel
Save