From da1296ef2dc3e55c37e17d9269bd75323370cf91 Mon Sep 17 00:00:00 2001 From: DonLakeFlyer Date: Sun, 26 Mar 2017 14:11:29 -0700 Subject: [PATCH] New file save settings and desktop/mobile file dialog capability --- qgroundcontrol.pro | 8 +- qgroundcontrol.qrc | 3 +- src/AnalyzeView/GeoTagController.cc | 8 +- src/AnalyzeView/LogDownloadController.cc | 6 +- src/FactSystem/SettingsFact.h | 3 + src/FlightMap/Widgets/CenterMapDropPanel.qml | 3 - src/MissionManager/GeoFenceController.cc | 31 +--- src/MissionManager/GeoFenceController.h | 2 - src/MissionManager/MissionController.cc | 31 +--- src/MissionManager/MissionController.h | 2 - src/MissionManager/PlanElementController.h | 2 - src/MissionManager/RallyPointController.cc | 31 +--- src/MissionManager/RallyPointController.h | 2 - src/PlanView/PlanView.qml | 110 ++++++------ src/QGCApplication.cc | 18 +- src/QGCApplication.h | 6 - src/QGCMobileFileDialogController.cc | 75 --------- src/QGCMobileFileDialogController.h | 43 ----- src/{QGCFileDialog.cc => QGCQFileDialog.cc} | 20 +-- src/{QGCFileDialog.h => QGCQFileDialog.h} | 6 +- src/QmlControls/ParameterEditor.qml | 56 +++--- src/QmlControls/ParameterEditorController.cc | 38 +---- src/QmlControls/ParameterEditorController.h | 2 - src/QmlControls/QFileDialogController.cc | 56 ++++++ src/QmlControls/QFileDialogController.h | 41 +++++ src/QmlControls/QGCFileDialog.qml | 159 ++++++++++++++++++ src/QmlControls/QGCMobileFileOpenDialog.qml | 56 ------ src/QmlControls/QGCMobileFileSaveDialog.qml | 79 --------- .../QGroundControl.Controls.qmldir | 3 +- src/QmlControls/QGroundControlQmlGlobal.h | 9 +- .../QMLControl/QGCMapEngineManager.cc | 6 +- src/Settings/App.SettingsGroup.json | 20 +-- src/Settings/AppSettings.cc | 118 +++++++++++-- src/Settings/AppSettings.h | 44 ++++- src/Vehicle/Vehicle.cc | 20 ++- src/VehicleSetup/FirmwareUpgradeController.cc | 4 +- .../CustomCommandWidgetController.cc | 4 +- src/comm/QGCFlightGearLink.cc | 4 +- src/qgcunittest/FileDialogTest.cc | 18 +- src/qgcunittest/FileDialogTest.h | 2 +- src/qgcunittest/UnitTest.h | 12 +- src/ui/QGCMAVLinkLogPlayer.cc | 4 +- src/ui/QGCUASFileView.cc | 8 +- src/ui/linechart/LinechartWidget.cc | 4 +- src/ui/preferences/GeneralSettings.qml | 113 +++++-------- 45 files changed, 626 insertions(+), 664 deletions(-) delete mode 100644 src/QGCMobileFileDialogController.cc delete mode 100644 src/QGCMobileFileDialogController.h rename src/{QGCFileDialog.cc => QGCQFileDialog.cc} (91%) rename src/{QGCFileDialog.h => QGCQFileDialog.h} (96%) create mode 100644 src/QmlControls/QFileDialogController.cc create mode 100644 src/QmlControls/QFileDialogController.h create mode 100644 src/QmlControls/QGCFileDialog.qml delete mode 100644 src/QmlControls/QGCMobileFileOpenDialog.qml delete mode 100644 src/QmlControls/QGCMobileFileSaveDialog.qml diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index f6e14e54d..0b38de569 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -482,7 +482,6 @@ HEADERS += \ src/QGCGeo.h \ src/QGCLoggingCategory.h \ src/QGCMapPalette.h \ - src/QGCMobileFileDialogController.h \ src/QGCPalette.h \ src/QGCQGeoCoordinate.h \ src/QGCQmlWidgetHolder.h \ @@ -493,6 +492,7 @@ HEADERS += \ src/QmlControls/CoordinateVector.h \ src/QmlControls/MavlinkQmlSingleton.h \ src/QmlControls/ParameterEditorController.h \ + src/QmlControls/QFileDialogController.h \ src/QmlControls/QGCImageProvider.h \ src/QmlControls/QGroundControlQmlGlobal.h \ src/QmlControls/QmlObjectListModel.h \ @@ -565,7 +565,7 @@ HEADERS += \ src/GPS/satellite_info.h \ src/GPS/vehicle_gps_position.h \ src/Joystick/JoystickSDL.h \ - src/QGCFileDialog.h \ + src/QGCQFileDialog.h \ src/QGCMessageBox.h \ src/RunGuard.h \ src/ViewWidgets/CustomCommandWidget.h \ @@ -659,7 +659,6 @@ SOURCES += \ src/QGCGeo.cc \ src/QGCLoggingCategory.cc \ src/QGCMapPalette.cc \ - src/QGCMobileFileDialogController.cc \ src/QGCPalette.cc \ src/QGCQGeoCoordinate.cc \ src/QGCQmlWidgetHolder.cpp \ @@ -669,6 +668,7 @@ SOURCES += \ src/QmlControls/AppMessages.cc \ src/QmlControls/CoordinateVector.cc \ src/QmlControls/ParameterEditorController.cc \ + src/QmlControls/QFileDialogController.cc \ src/QmlControls/QGCImageProvider.cc \ src/QmlControls/QGroundControlQmlGlobal.cc \ src/QmlControls/QmlObjectListModel.cc \ @@ -724,7 +724,7 @@ SOURCES += \ src/GPS/GPSProvider.cc \ src/GPS/RTCM/RTCMMavlink.cc \ src/Joystick/JoystickSDL.cc \ - src/QGCFileDialog.cc \ + src/QGCQFileDialog.cc \ src/RunGuard.cc \ src/ViewWidgets/CustomCommandWidget.cc \ src/ViewWidgets/CustomCommandWidgetController.cc \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index aa2e73503..93865fcb6 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -77,6 +77,7 @@ src/QmlControls/QGCCheckBox.qml src/QmlControls/QGCColoredImage.qml src/QmlControls/QGCComboBox.qml + src/QmlControls/QGCFileDialog.qml src/QmlControls/QGCFlickable.qml src/QmlControls/QGCFlickableHorizontalIndicator.qml src/QmlControls/QGCFlickableVerticalIndicator.qml @@ -84,8 +85,6 @@ src/QmlControls/QGCLabel.qml src/QmlControls/QGCListView.qml src/QmlControls/QGCMapLabel.qml - src/QmlControls/QGCMobileFileOpenDialog.qml - src/QmlControls/QGCMobileFileSaveDialog.qml src/QmlControls/QGCMouseArea.qml src/QmlControls/QGCMovableItem.qml src/QmlControls/QGCPipable.qml diff --git a/src/AnalyzeView/GeoTagController.cc b/src/AnalyzeView/GeoTagController.cc index 9c49c4f59..0fbab4ff2 100644 --- a/src/AnalyzeView/GeoTagController.cc +++ b/src/AnalyzeView/GeoTagController.cc @@ -9,7 +9,7 @@ #include "GeoTagController.h" #include "ExifParser.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCLoggingCategory.h" #include "MainWindow.h" #include @@ -35,7 +35,7 @@ GeoTagController::~GeoTagController() void GeoTagController::pickLogFile(void) { - QString filename = QGCFileDialog::getOpenFileName(MainWindow::instance(), "Select log file load", QString(), "PX4 log file (*.px4log);;All Files (*.*)"); + QString filename = QGCQFileDialog::getOpenFileName(MainWindow::instance(), "Select log file load", QString(), "PX4 log file (*.px4log);;All Files (*.*)"); if (!filename.isEmpty()) { _worker.setLogFile(filename); emit logFileChanged(filename); @@ -44,7 +44,7 @@ void GeoTagController::pickLogFile(void) void GeoTagController::pickImageDirectory(void) { - QString dir = QGCFileDialog::getExistingDirectory(MainWindow::instance(), "Select image directory"); + QString dir = QGCQFileDialog::getExistingDirectory(MainWindow::instance(), "Select image directory"); if (!dir.isEmpty()) { _worker.setImageDirectory(dir); emit imageDirectoryChanged(dir); @@ -53,7 +53,7 @@ void GeoTagController::pickImageDirectory(void) void GeoTagController::pickSaveDirectory(void) { - QString dir = QGCFileDialog::getExistingDirectory(MainWindow::instance(), "Select save directory"); + QString dir = QGCQFileDialog::getExistingDirectory(MainWindow::instance(), "Select save directory"); if (!dir.isEmpty()) { _worker.setSaveDirectory(dir); emit saveDirectoryChanged(dir); diff --git a/src/AnalyzeView/LogDownloadController.cc b/src/AnalyzeView/LogDownloadController.cc index 0abd0f497..50943863e 100644 --- a/src/AnalyzeView/LogDownloadController.cc +++ b/src/AnalyzeView/LogDownloadController.cc @@ -12,7 +12,7 @@ #include "MultiVehicleManager.h" #include "QGCMAVLink.h" #if !defined(__mobile__) -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "MainWindow.h" #endif #include "UAS.h" @@ -514,11 +514,11 @@ LogDownloadController::download(QString path) } #else if(dir.isEmpty()) { - dir = QGCFileDialog::getExistingDirectory( + dir = QGCQFileDialog::getExistingDirectory( MainWindow::instance(), "Log Download Directory", QDir::homePath(), - QGCFileDialog::ShowDirsOnly | QGCFileDialog::DontResolveSymlinks); + QGCQFileDialog::ShowDirsOnly | QGCQFileDialog::DontResolveSymlinks); } #endif downloadToDirectory(dir); diff --git a/src/FactSystem/SettingsFact.h b/src/FactSystem/SettingsFact.h index cb6e8330f..eba4a2417 100644 --- a/src/FactSystem/SettingsFact.h +++ b/src/FactSystem/SettingsFact.h @@ -30,6 +30,9 @@ public: Q_PROPERTY(bool visible MEMBER _visible CONSTANT) + // Must be called before any references to fact + void setVisible(bool visible) { _visible = visible; } + private slots: void _rawValueChanged(QVariant value); diff --git a/src/FlightMap/Widgets/CenterMapDropPanel.qml b/src/FlightMap/Widgets/CenterMapDropPanel.qml index 5c6485562..8bfade629 100644 --- a/src/FlightMap/Widgets/CenterMapDropPanel.qml +++ b/src/FlightMap/Widgets/CenterMapDropPanel.qml @@ -34,7 +34,6 @@ ColumnLayout { text: qsTr("Mission") Layout.fillWidth: true visible: showMission - enabled: !followVehicleCheckBox.checked onClicked: { dropPanel.hide() @@ -46,7 +45,6 @@ ColumnLayout { text: qsTr("All items") Layout.fillWidth: true visible: showAllItems - enabled: !followVehicleCheckBox.checked onClicked: { dropPanel.hide() @@ -57,7 +55,6 @@ ColumnLayout { QGCButton { text: qsTr("Home") Layout.fillWidth: true - enabled: !followVehicleCheckBox.checked onClicked: { dropPanel.hide() diff --git a/src/MissionManager/GeoFenceController.cc b/src/MissionManager/GeoFenceController.cc index df068f387..cfc493ee8 100644 --- a/src/MissionManager/GeoFenceController.cc +++ b/src/MissionManager/GeoFenceController.cc @@ -19,10 +19,11 @@ #include "ParameterManager.h" #include "JsonHelper.h" #include "QGCQGeoCoordinate.h" +#include "AppSettings.h" #ifndef __mobile__ #include "MainWindow.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #endif #include @@ -238,18 +239,6 @@ void GeoFenceController::loadFromFile(const QString& filename) setDirty(true); } -void GeoFenceController::loadFromFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getOpenFileName(MainWindow::instance(), "Select GeoFence File to load", QString(), "Fence file (*.fence);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - loadFromFile(filename); -#endif -} - void GeoFenceController::saveToFile(const QString& filename) { if (filename.isEmpty()) { @@ -258,7 +247,7 @@ void GeoFenceController::saveToFile(const QString& filename) QString fenceFilename = filename; if (!QFileInfo(filename).fileName().contains(".")) { - fenceFilename += QString(".%1").arg(QGCApplication::fenceFileExtension); + fenceFilename += QString(".%1").arg(AppSettings::fenceFileExtension); } QFile file(fenceFilename); @@ -301,18 +290,6 @@ void GeoFenceController::saveToFile(const QString& filename) setDirty(false); } -void GeoFenceController::saveToFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getSaveFileName(MainWindow::instance(), "Select file to save GeoFence to", QString(), "Fence file (*.fence);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - saveToFile(filename); -#endif -} - void GeoFenceController::removeAll(void) { setBreachReturnPoint(QGeoCoordinate()); @@ -433,7 +410,7 @@ void GeoFenceController::_loadComplete(const QGeoCoordinate& breachReturn, const QString GeoFenceController::fileExtension(void) const { - return QGCApplication::fenceFileExtension; + return AppSettings::fenceFileExtension; } bool GeoFenceController::containsItems(void) const diff --git a/src/MissionManager/GeoFenceController.h b/src/MissionManager/GeoFenceController.h index db76eafdd..523c04341 100644 --- a/src/MissionManager/GeoFenceController.h +++ b/src/MissionManager/GeoFenceController.h @@ -49,9 +49,7 @@ public: void startStaticActiveVehicle (Vehicle* vehicle) final; void loadFromVehicle (void) final; void sendToVehicle (void) final; - void loadFromFilePicker (void) final; void loadFromFile (const QString& filename) final; - void saveToFilePicker (void) final; void saveToFile (const QString& filename) final; void removeAll (void) final; void removeAllFromVehicle (void) final; diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index af5952447..335dc77ba 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -21,11 +21,12 @@ #include "ParameterManager.h" #include "QGroundControlQmlGlobal.h" #include "SettingsManager.h" +#include "AppSettings.h" #include "MissionSettingsItem.h" #ifndef __mobile__ #include "MainWindow.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #endif QGC_LOGGING_CATEGORY(MissionControllerLog, "MissionControllerLog") @@ -686,18 +687,6 @@ bool MissionController::loadItemsFromFile(Vehicle* vehicle, const QString& filen return true; } -void MissionController::loadFromFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getOpenFileName(MainWindow::instance(), "Select Mission File to load", QString(), "Mission file (*.mission);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - loadFromFile(filename); -#endif -} - void MissionController::saveToFile(const QString& filename) { qDebug() << filename; @@ -708,7 +697,7 @@ void MissionController::saveToFile(const QString& filename) QString missionFilename = filename; if (!QFileInfo(filename).fileName().contains(".")) { - missionFilename += QString(".%1").arg(QGCApplication::missionFileExtension); + missionFilename += QString(".%1").arg(AppSettings::missionFileExtension); } QFile file(missionFilename); @@ -769,18 +758,6 @@ void MissionController::saveToFile(const QString& filename) _visualItems->setDirty(false); } -void MissionController::saveToFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getSaveFileName(MainWindow::instance(), "Select file to save mission to", QString(), "Mission file (*.mission);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - saveToFile(filename); -#endif -} - void MissionController::_calcPrevWaypointValues(double homeAlt, VisualMissionItem* currentItem, VisualMissionItem* prevItem, double* azimuth, double* distance, double* altDifference) { QGeoCoordinate currentCoord = currentItem->coordinate(); @@ -1541,7 +1518,7 @@ void MissionController::setDirty(bool dirty) QString MissionController::fileExtension(void) const { - return QGCApplication::missionFileExtension; + return AppSettings::missionFileExtension; } void MissionController::_scanForAdditionalSettings(QmlObjectListModel* visualItems, Vehicle* vehicle) diff --git a/src/MissionManager/MissionController.h b/src/MissionManager/MissionController.h index 08c3d399d..e07ca14e1 100644 --- a/src/MissionManager/MissionController.h +++ b/src/MissionManager/MissionController.h @@ -93,9 +93,7 @@ public: void startStaticActiveVehicle (Vehicle* vehicle) final; void loadFromVehicle (void) final; void sendToVehicle (void) final; - void loadFromFilePicker (void) final; void loadFromFile (const QString& filename) final; - void saveToFilePicker (void) final; void saveToFile (const QString& filename) final; void removeAll (void) final; void removeAllFromVehicle (void) final; diff --git a/src/MissionManager/PlanElementController.h b/src/MissionManager/PlanElementController.h index 189b32b2c..2d1e24ec0 100644 --- a/src/MissionManager/PlanElementController.h +++ b/src/MissionManager/PlanElementController.h @@ -44,9 +44,7 @@ public: Q_INVOKABLE virtual void loadFromVehicle(void) = 0; Q_INVOKABLE virtual void sendToVehicle(void) = 0; - Q_INVOKABLE virtual void loadFromFilePicker(void) = 0; Q_INVOKABLE virtual void loadFromFile(const QString& filename) = 0; - Q_INVOKABLE virtual void saveToFilePicker(void) = 0; Q_INVOKABLE virtual void saveToFile(const QString& filename) = 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 diff --git a/src/MissionManager/RallyPointController.cc b/src/MissionManager/RallyPointController.cc index a14ef9f29..0e1a375e7 100644 --- a/src/MissionManager/RallyPointController.cc +++ b/src/MissionManager/RallyPointController.cc @@ -22,9 +22,10 @@ #include "SimpleMissionItem.h" #include "QGroundControlQmlGlobal.h" #include "SettingsManager.h" +#include "AppSettings.h" #ifndef __mobile__ -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #endif #include @@ -135,18 +136,6 @@ void RallyPointController::loadFromFile(const QString& filename) _setFirstPointCurrent(); } -void RallyPointController::loadFromFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getOpenFileName(NULL, "Select Rally Point File to load", QString(), "Rally point file (*.rally);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - loadFromFile(filename); -#endif -} - void RallyPointController::saveToFile(const QString& filename) { if (filename.isEmpty()) { @@ -155,7 +144,7 @@ void RallyPointController::saveToFile(const QString& filename) QString rallyFilename = filename; if (!QFileInfo(filename).fileName().contains(".")) { - rallyFilename += QString(".%1").arg(QGCApplication::rallyPointFileExtension); + rallyFilename += QString(".%1").arg(AppSettings::rallyPointFileExtension); } QFile file(rallyFilename); @@ -184,18 +173,6 @@ void RallyPointController::saveToFile(const QString& filename) setDirty(false); } -void RallyPointController::saveToFilePicker(void) -{ -#ifndef __mobile__ - QString filename = QGCFileDialog::getSaveFileName(NULL, "Select file to save Rally Points to", QString(), "Rally point file (*.rally);;All Files (*.*)"); - - if (filename.isEmpty()) { - return; - } - saveToFile(filename); -#endif -} - void RallyPointController::removeAll(void) { _points.clearAndDeleteContents(); @@ -259,7 +236,7 @@ void RallyPointController::_loadComplete(const QList rgPoints) QString RallyPointController::fileExtension(void) const { - return QGCApplication::rallyPointFileExtension; + return AppSettings::rallyPointFileExtension; } void RallyPointController::addPoint(QGeoCoordinate point) diff --git a/src/MissionManager/RallyPointController.h b/src/MissionManager/RallyPointController.h index a910a0390..54e37a151 100644 --- a/src/MissionManager/RallyPointController.h +++ b/src/MissionManager/RallyPointController.h @@ -39,9 +39,7 @@ public: void loadFromVehicle (void) final; void sendToVehicle (void) final; - void loadFromFilePicker (void) final; void loadFromFile (const QString& filename) final; - void saveToFilePicker (void) final; void saveToFile (const QString& filename) final; void removeAll (void) final; void removeAllFromVehicle (void) final; diff --git a/src/PlanView/PlanView.qml b/src/PlanView/PlanView.qml index 4de22013e..1bd2622aa 100644 --- a/src/PlanView/PlanView.qml +++ b/src/PlanView/PlanView.qml @@ -26,7 +26,7 @@ import QGroundControl.Controllers 1.0 /// Mission Editor QGCView { - id: qgcView + id: _qgcView viewPanel: panel // zOrder comes from the Loader in MainWindow.qml @@ -96,27 +96,29 @@ QGCView { MissionController { id: missionController + property var nameFilters: [ qsTr("Mission Files (*.%1)").arg(missionController.fileExtension) , qsTr("All Files (*.*)") ] + Component.onCompleted: { start(true /* editMode */) setCurrentItem(0) } function loadFromSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFilePicker, qsTr("Select Mission File"), qgcView.showDialogDefaultWidth, StandardButton.Cancel) - } else { - missionController.loadFromFilePicker() - mapFitFunctions.fitMapViewportToMissionItems() - _currentMissionItem = _visualItems.get(0) - } + fileDialog.title = qsTr("Select Mission File") + fileDialog.selectExisting = true + fileDialog.nameFilters = missionController.nameFilters + fileDialog.openForLoad() + + // FIXME: Hmm + //mapFitFunctions.fitMapViewportToMissionItems() + //_currentMissionItem = _visualItems.get(0) } function saveToSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFileSaver, qsTr("Save Mission File"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel) - } else { - missionController.saveToFilePicker() - } + fileDialog.title = qsTr("Save Mission") + fileDialog.selectExisting = false + fileDialog.nameFilters = missionController.nameFilters + fileDialog.openForSave() } function fitViewportToItems() { @@ -138,23 +140,23 @@ QGCView { GeoFenceController { id: geoFenceController + property var nameFilters: [ qsTr("GeoFence Files (*.%1)").arg(geoFenceController.fileExtension) , qsTr("All Files (*.*)") ] + Component.onCompleted: start(true /* editMode */) function saveToSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFileSaver, qsTr("Save Fence File"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel) - } else { - geoFenceController.saveToFilePicker() - } + fileDialog.title = qsTr("Save GeoFence") + fileDialog.selectExisting = false + fileDialog.nameFilters = geoFenceController.nameFilters + fileDialog.openForSave() } function loadFromSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFilePicker, qsTr("Select Fence File"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) - } else { - geoFenceController.loadFromFilePicker() - mapFitFunctions.fitMapViewportToFenceItems() - } + fileDialog.title = qsTr("Select GeoFence File") + fileDialog.selectExisting = true + fileDialog.nameFilters = geoFenceController.nameFilters + fileDialog.openForLoad() + ///mapFitFunctions.fitMapViewportToFenceItems() } function fitViewportToItems() { @@ -177,6 +179,8 @@ QGCView { 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 @@ -188,20 +192,18 @@ QGCView { Component.onCompleted: start(true /* editMode */) function saveToSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFileSaver, qsTr("Save Rally Point File"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel) - } else { - rallyPointController.saveToFilePicker() - } + fileDialog.title = qsTr("Save Rally Points") + fileDialog.selectExisting = false + fileDialog.nameFilters = rallyPointController.nameFilters + fileDialog.openForSave() } function loadFromSelectedFile() { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFilePicker, qsTr("Select Rally Point File"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) - } else { - rallyPointController.loadFromFilePicker() - mapFitFunctions.fitMapViewportToRallyItems() - } + fileDialog.title = qsTr("Select Rally Point File") + fileDialog.selectExisting = true + fileDialog.nameFilters = rallyPointController.nameFilters + fileDialog.openForLoad() + //mapFitFunctions.fitMapViewportToRallyItems() } function fitViewportToItems() { @@ -257,24 +259,22 @@ QGCView { property int _moveDialogMissionItemIndex - Component { - id: mobileFilePicker + QGCFileDialog { + id: fileDialog + qgcView: _qgcView + folder: QGroundControl.settingsManager.appSettings.missionSavePath + fileExtension: _syncDropDownController.fileExtension - QGCMobileFileOpenDialog { - fileExtension: _syncDropDownController.fileExtension - onFilenameReturned: { - _syncDropDownController.loadFromFile(filename) - _syncDropDownController.fitViewportToItems() - } + onAcceptedForSave: { + _syncDropDownController.saveToFile(file) + close() } - } - - Component { - id: mobileFileSaver - QGCMobileFileSaveDialog { - fileExtension: _syncDropDownController.fileExtension - onFilenameReturned: _syncDropDownController.saveToFile(filename) + onAcceptedForLoad: { + _syncDropDownController.loadFromFile(file) + _syncDropDownController.fitViewportToItems() + _currentMissionItem = _visualItems.get(0) + close() } } @@ -325,7 +325,7 @@ QGCView { FlightMap { id: editorMap - height: qgcView.height + height: _qgcView.height anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right @@ -334,7 +334,7 @@ QGCView { // This is the center rectangle of the map which is not obscured by tools property rect centerViewport: Qt.rect(_leftToolWidth, _toolbarHeight, editorMap.width - _leftToolWidth - _rightPanelWidth, editorMap.height - _statusHeight - _toolbarHeight) - property real _toolbarHeight: qgcView.height - ScreenTools.availableHeight + property real _toolbarHeight: _qgcView.height - ScreenTools.availableHeight property real _leftToolWidth: toolStrip.x + toolStrip.width property real _statusHeight: waypointValuesDisplay.visible ? editorMap.height - waypointValuesDisplay.y : 0 @@ -850,7 +850,7 @@ QGCView { onClicked: { dropPanel.hide() if (_syncDropDownController.dirty) { - qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) + _qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) } else { _syncDropDownController.loadFromVehicle() } @@ -874,7 +874,7 @@ QGCView { onClicked: { dropPanel.hide() if (_syncDropDownController.dirty) { - qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) + _qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel) } else { _syncDropDownController.loadFromSelectedFile() } @@ -886,7 +886,7 @@ QGCView { Layout.fillWidth: true onClicked: { dropPanel.hide() - qgcView.showDialog(removeAllPromptDialog, qsTr("Remove all"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No) + _qgcView.showDialog(removeAllPromptDialog, qsTr("Remove all"), _qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No) } } } diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 6e084001f..7bc96582b 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -49,7 +49,7 @@ #include "CustomCommandWidgetController.h" #include "ESP8266ComponentController.h" #include "ScreenToolsController.h" -#include "QGCMobileFileDialogController.h" +#include "QFileDialogController.h" #include "RCChannelMonitorController.h" #include "AutoPilotPlugin.h" #include "VehicleComponent.h" @@ -86,7 +86,7 @@ #endif #ifndef __mobile__ -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCMessageBox.h" #include "FirmwareUpgradeController.h" #include "MainWindow.h" @@ -108,12 +108,6 @@ QGCApplication* QGCApplication::_app = NULL; -const char* QGCApplication::parameterFileExtension = "params"; -const char* QGCApplication::missionFileExtension = "mission"; -const char* QGCApplication::fenceFileExtension = "fence"; -const char* QGCApplication::rallyPointFileExtension = "rally"; -const char* QGCApplication::telemetryFileExtension = "tlog"; - const char* QGCApplication::_deleteAllSettingsKey = "DeleteAllSettingsNextBoot"; const char* QGCApplication::_settingsVersionKey = "SettingsVersion"; @@ -374,7 +368,7 @@ void QGCApplication::_initCommon(void) qmlRegisterType ("QGroundControl.Controllers", 1, 0, "GeoFenceController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "RallyPointController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "ValuesWidgetController"); - qmlRegisterType ("QGroundControl.Controllers", 1, 0, "QGCMobileFileDialogController"); + qmlRegisterType ("QGroundControl.Controllers", 1, 0, "QFileDialogController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "RCChannelMonitorController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "JoystickConfigController"); qmlRegisterType ("QGroundControl.Controllers", 1, 0, "LogDownloadController"); @@ -495,7 +489,7 @@ void QGCApplication::saveTelemetryLogOnMainThread(QString tempLogfile) // The vehicle is gone now and we are shutting down so we need to use a message box for errors to hold shutdown and show the error if (_checkTelemetrySavePath(true /* useMessageBox */)) { - QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath()->rawValue().toString(); + QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath(); QDir saveDir(saveDirPath); QString nameFormat("%1%2.tlog"); @@ -527,9 +521,9 @@ bool QGCApplication::_checkTelemetrySavePath(bool useMessageBox) { QString errorTitle = tr("Telemetry save error"); - QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath()->rawValue().toString(); + QString saveDirPath = _toolbox->settingsManager()->appSettings()->telemetrySavePath(); if (saveDirPath.isEmpty()) { - QString error = tr("Unable to save telemetry log. Telemetry save directory is not set."); + QString error = tr("Unable to save telemetry log. Application save directory is not set."); if (useMessageBox) { QGCMessageBox::warning(errorTitle, error); } else { diff --git a/src/QGCApplication.h b/src/QGCApplication.h index 8a30838a1..0e9afdabd 100644 --- a/src/QGCApplication.h +++ b/src/QGCApplication.h @@ -63,12 +63,6 @@ public: QGCApplication(int &argc, char* argv[], bool unitTesting); ~QGCApplication(); - static const char* parameterFileExtension; - static const char* missionFileExtension; - static const char* fenceFileExtension; - static const char* rallyPointFileExtension; - static const char* telemetryFileExtension; - /// @brief Sets the persistent flag to delete all settings the next time QGroundControl is started. void deleteAllSettingsNextBoot(void); diff --git a/src/QGCMobileFileDialogController.cc b/src/QGCMobileFileDialogController.cc deleted file mode 100644 index f7e463015..000000000 --- a/src/QGCMobileFileDialogController.cc +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include "QGCMobileFileDialogController.h" - -#include -#include -#include - -QGC_LOGGING_CATEGORY(QGCMobileFileDialogControllerLog, "QGCMobileFileDialogControllerLog") - -QStringList QGCMobileFileDialogController::getFiles(const QString& fileExtension) -{ - QStringList files; - - QDir fileDir(_getSaveLocation()); - - QFileInfoList fileInfoList = fileDir.entryInfoList(QStringList(QString("*.%1").arg(fileExtension)), QDir::Files, QDir::Name); - - foreach (const QFileInfo& fileInfo, fileInfoList) { - files << fileInfo.baseName() + QStringLiteral(".") + fileExtension; - } - - return files; -} - -QString QGCMobileFileDialogController::fullPath(const QString& filename, const QString& fileExtension) -{ - qDebug() << "QGCMobileFileDialogController::fullPath" << filename << fileExtension; - QString saveLocation(_getSaveLocation()); - if (saveLocation.isEmpty()) { - return filename; - } - - QString fixedFilename(filename); - QString correctExtension = QString(".%1").arg(fileExtension); - if (!filename.endsWith(correctExtension)) { - fixedFilename += correctExtension; - } - - QString fullPath = saveLocation + QDir::separator() + fixedFilename; - qCDebug(QGCMobileFileDialogControllerLog) << "Full path" << fullPath; - return fullPath; -} - -bool QGCMobileFileDialogController::fileExists(const QString& filename, const QString& fileExtension) -{ - QFile file(fullPath(filename, fileExtension)); - qDebug() << "QGCMobileFileDialogController::fileExists" << file.fileName(); - return file.exists(); -} - -QString QGCMobileFileDialogController::_getSaveLocation(void) -{ - QStringList docDirs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); - if (docDirs.count() <= 0) { - qCWarning(QGCMobileFileDialogControllerLog) << "No save location"; - return QString(); - } - - QString saveDirectory = docDirs[0]; - if (!QDir(saveDirectory).exists()) { - QDir().mkdir(saveDirectory); - } - qCDebug(QGCMobileFileDialogControllerLog) << "Save directory" << saveDirectory; - - return saveDirectory; -} diff --git a/src/QGCMobileFileDialogController.h b/src/QGCMobileFileDialogController.h deleted file mode 100644 index 602d84e65..000000000 --- a/src/QGCMobileFileDialogController.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#ifndef QGCMobileFileDialogController_H -#define QGCMobileFileDialogController_H - -#include - -#include "QGCLoggingCategory.h" - -Q_DECLARE_LOGGING_CATEGORY(QGCMobileFileDialogControllerLog) - -class QGCMobileFileDialogController : public QObject -{ - Q_OBJECT - -public: - /// Return all file in Documents location which match the specified extension - Q_INVOKABLE QStringList getFiles(const QString& fileExtension); - - /// Return the full path for specified file in the Documents location - /// @param filename File name, not fully qualified, may not have extension - /// @param fileExtension Expected file extension, added if needed - Q_INVOKABLE QString fullPath(const QString& filename, const QString& fileExtension); - - /// Check for file existence - /// @param filename File name, not fully qualified, may not have extension - /// @param fileExtension Expected file extension, added if needed - /// @return true: File exists at Documents location - Q_INVOKABLE bool fileExists(const QString& filename, const QString& fileExtension); - -private: - QString _getSaveLocation(void); -}; - -#endif diff --git a/src/QGCFileDialog.cc b/src/QGCQFileDialog.cc similarity index 91% rename from src/QGCFileDialog.cc rename to src/QGCQFileDialog.cc index 59ff5db45..0a4932fcb 100644 --- a/src/QGCFileDialog.cc +++ b/src/QGCQFileDialog.cc @@ -8,7 +8,7 @@ ****************************************************************************/ -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCApplication.h" #include "MainWindow.h" @@ -20,7 +20,7 @@ #include #include -QString QGCFileDialog::getExistingDirectory( +QString QGCQFileDialog::getExistingDirectory( QWidget* parent, const QString& caption, const QString& dir, @@ -38,7 +38,7 @@ QString QGCFileDialog::getExistingDirectory( } } -QString QGCFileDialog::getOpenFileName( +QString QGCQFileDialog::getOpenFileName( QWidget* parent, const QString& caption, const QString& dir, @@ -57,7 +57,7 @@ QString QGCFileDialog::getOpenFileName( } } -QStringList QGCFileDialog::getOpenFileNames( +QStringList QGCQFileDialog::getOpenFileNames( QWidget* parent, const QString& caption, const QString& dir, @@ -76,7 +76,7 @@ QStringList QGCFileDialog::getOpenFileNames( } } -QString QGCFileDialog::getSaveFileName( +QString QGCQFileDialog::getSaveFileName( QWidget* parent, const QString& caption, const QString& dir, @@ -162,7 +162,7 @@ QString QGCFileDialog::getSaveFileName( } /// @brief Make sure filename is using one of the valid extensions defined in the filter -bool QGCFileDialog::_validateExtension(const QString& filter, const QString& extension) { +bool QGCQFileDialog::_validateExtension(const QString& filter, const QString& extension) { QRegularExpression re("(\\*\\.\\w+)"); QRegularExpressionMatchIterator i = re.globalMatch(filter); while (i.hasNext()) { @@ -178,7 +178,7 @@ bool QGCFileDialog::_validateExtension(const QString& filter, const QString& ext } /// @brief Returns first extension found in filter -QString QGCFileDialog::_getFirstExtensionInFilter(const QString& filter) { +QString QGCQFileDialog::_getFirstExtensionInFilter(const QString& filter) { QRegularExpression re("(\\*\\.\\w+)"); QRegularExpressionMatchIterator i = re.globalMatch(filter); while (i.hasNext()) { @@ -192,14 +192,14 @@ QString QGCFileDialog::_getFirstExtensionInFilter(const QString& filter) { } /// @brief Validates and updates the parameters for the file dialog calls -void QGCFileDialog::_validate(Options& options) +void QGCQFileDialog::_validate(Options& options) { Q_UNUSED(options) - // You can't use QGCFileDialog if QGCApplication is not created yet. + // You can't use QGCQFileDialog if QGCApplication is not created yet. Q_ASSERT(qgcApp()); - Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCFileDialog can only be called from main thread"); + Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCQFileDialog can only be called from main thread"); if (MainWindow::instance()) { } } diff --git a/src/QGCFileDialog.h b/src/QGCQFileDialog.h similarity index 96% rename from src/QGCFileDialog.h rename to src/QGCQFileDialog.h index 04d5a5747..652f3b0e1 100644 --- a/src/QGCFileDialog.h +++ b/src/QGCQFileDialog.h @@ -28,7 +28,7 @@ use to catch these dialogs for unit testing. @remark If you need to know what type of file was returned by these functions, you can use something like: @code{.cpp} - QString filename = QGCFileDialog::getSaveFileName(this, tr("Save File"), "~/", "Foo files (*.foo);;All Files (*.*)", "foo"); + QString filename = QGCQFileDialog::getSaveFileName(this, tr("Save File"), "~/", "Foo files (*.foo);;All Files (*.*)", "foo"); if (!filename.isEmpty()) { QFileInfo fi(filename); QString fileExtension(fi.suffix()); @@ -39,7 +39,7 @@ @endcode */ -class QGCFileDialog : public QFileDialog { +class QGCQFileDialog : public QFileDialog { public: @@ -119,7 +119,7 @@ public: Options options = 0); private slots: - /// @brief The exec slot is private because we only want QGCFileDialog users to use the static methods. Otherwise it will break + /// @brief The exec slot is private because we only want QGCQFileDialog users to use the static methods. Otherwise it will break /// unit testing. int exec(void) { return QFileDialog::exec(); } diff --git a/src/QmlControls/ParameterEditor.qml b/src/QmlControls/ParameterEditor.qml index a56f3151b..25c00004a 100644 --- a/src/QmlControls/ParameterEditor.qml +++ b/src/QmlControls/ParameterEditor.qml @@ -111,21 +111,29 @@ QGCView { MenuItem { text: qsTr("Load from file...") onTriggered: { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFilePicker, qsTr("Select Parameter File"), qgcView.showDialogDefaultWidth, StandardButton.Cancel) - } else { - controller.loadFromFilePicker() - } + var appSettings = QGroundControl.settingsManager.appSettings + + fileDialog.qgcView = qgcView + fileDialog.title = qsTr("Select Parameter File") + fileDialog.selectExisting = true + fileDialog.folder = appSettings.parameterSavePath + fileDialog.fileExtension = appSettings.parameterFileExtension + fileDialog.nameFilters = [ qsTr("Parameter Files (*.%1)").arg(appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ] + fileDialog.openForLoad() } } MenuItem { text: qsTr("Save to file...") onTriggered: { - if (ScreenTools.isMobile) { - qgcView.showDialog(mobileFileSaver, qsTr("Save Parameter File"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel) - } else { - controller.saveToFilePicker() - } + var appSettings = QGroundControl.settingsManager.appSettings + + fileDialog.qgcView = qgcView + fileDialog.title = qsTr("Save Parameters") + fileDialog.selectExisting = false + fileDialog.folder = appSettings.parameterSavePath + fileDialog.fileExtension = appSettings.parameterFileExtension + fileDialog.nameFilters = [ qsTr("Parameter Files (*.%1)").arg(appSettings.parameterFileExtension) , qsTr("All Files (*.*)") ] + fileDialog.openForSave() } } MenuSeparator { visible: _showRCToParam } @@ -272,30 +280,26 @@ QGCView { } } // QGCViewPanel - Component { - id: editorDialogComponent + QGCFileDialog { + id: fileDialog - ParameterEditorDialog { - fact: _editorDialogFact - showRCToParam: _showRCToParam + onAcceptedForSave: { + controller.saveToFile(file) + close() } - } - - Component { - id: mobileFilePicker - QGCMobileFileOpenDialog { - fileExtension: QGroundControl.parameterFileExtension - onFilenameReturned: controller.loadFromFile(filename) + onAcceptedForLoad: { + controller.loadFromFile(file) + close() } } Component { - id: mobileFileSaver + id: editorDialogComponent - QGCMobileFileSaveDialog { - fileExtension: QGroundControl.parameterFileExtension - onFilenameReturned: controller.saveToFile(filename) + ParameterEditorDialog { + fact: _editorDialogFact + showRCToParam: _showRCToParam } } diff --git a/src/QmlControls/ParameterEditorController.cc b/src/QmlControls/ParameterEditorController.cc index 6613ef4ed..66385dc9e 100644 --- a/src/QmlControls/ParameterEditorController.cc +++ b/src/QmlControls/ParameterEditorController.cc @@ -14,9 +14,11 @@ #include "ParameterEditorController.h" #include "QGCApplication.h" #include "ParameterManager.h" +#include "SettingsManager.h" +#include "AppSettings.h" #ifndef __mobile__ -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCMapRCToParamDialog.h" #include "MainWindow.h" #endif @@ -93,11 +95,6 @@ void ParameterEditorController::clearRCToParam(void) void ParameterEditorController::saveToFile(const QString& filename) { - if (!_autopilot) { - qWarning() << "Internal error _autopilot==NULL"; - return; - } - if (!filename.isEmpty()) { QFile file(filename); @@ -112,28 +109,10 @@ void ParameterEditorController::saveToFile(const QString& filename) } } -void ParameterEditorController::saveToFilePicker(void) -{ -#ifndef __mobile__ - QString fileName = QGCFileDialog::getSaveFileName(MainWindow::instance(), - "Save Parameters", - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), - "Parameter Files (*.params)", - "params", - true); - saveToFile(fileName); -#endif -} - void ParameterEditorController::loadFromFile(const QString& filename) { QString errors; - if (!_autopilot) { - qWarning() << "Internal error _autopilot==NULL"; - return; - } - if (!filename.isEmpty()) { QFile file(filename); @@ -152,17 +131,6 @@ void ParameterEditorController::loadFromFile(const QString& filename) } } -void ParameterEditorController::loadFromFilePicker(void) -{ -#ifndef __mobile__ - QString fileName = QGCFileDialog::getOpenFileName(MainWindow::instance(), - "Load Parameters", - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), - "Parameter Files (*.params);;All Files (*)"); - loadFromFile(fileName); -#endif -} - void ParameterEditorController::refresh(void) { _vehicle->parameterManager()->refreshAllParameters(); diff --git a/src/QmlControls/ParameterEditorController.h b/src/QmlControls/ParameterEditorController.h index 2c8b275fa..c37e0d89e 100644 --- a/src/QmlControls/ParameterEditorController.h +++ b/src/QmlControls/ParameterEditorController.h @@ -41,8 +41,6 @@ public: Q_INVOKABLE QStringList searchParametersForComponent(int componentId, const QString& searchText, bool searchInName=true, bool searchInDescriptions=true); Q_INVOKABLE void clearRCToParam(void); - Q_INVOKABLE void saveToFilePicker(void); - Q_INVOKABLE void loadFromFilePicker(void); Q_INVOKABLE void saveToFile(const QString& filename); Q_INVOKABLE void loadFromFile(const QString& filename); Q_INVOKABLE void refresh(void); diff --git a/src/QmlControls/QFileDialogController.cc b/src/QmlControls/QFileDialogController.cc new file mode 100644 index 000000000..df3fb88ad --- /dev/null +++ b/src/QmlControls/QFileDialogController.cc @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +#include "QFileDialogController.h" + +#include +#include +#include + +QGC_LOGGING_CATEGORY(QFileDialogControllerLog, "QFileDialogControllerLog") + +QStringList QFileDialogController::getFiles(const QString& directoryPath, const QString& fileExtension) +{ + qCDebug(QFileDialogControllerLog) << "getFiles" << directoryPath << fileExtension; + QStringList files; + + QDir fileDir(directoryPath); + + QFileInfoList fileInfoList = fileDir.entryInfoList(QStringList(QString("*.%1").arg(fileExtension)), QDir::Files, QDir::Name); + + foreach (const QFileInfo& fileInfo, fileInfoList) { + qCDebug(QFileDialogControllerLog) << "getFiles found" << fileInfo.baseName(); + files << fileInfo.baseName() + QStringLiteral(".") + fileExtension; + } + + return files; +} + +QString QFileDialogController::filenameWithExtension(const QString& filename, const QString& fileExtension) +{ + QString filenameWithExtension(filename); + + QString correctExtension = QString(".%1").arg(fileExtension); + if (!filenameWithExtension.endsWith(correctExtension)) { + filenameWithExtension += correctExtension; + } + + return filenameWithExtension; +} + +bool QFileDialogController::fileExists(const QString& filename) +{ + return QFile(filename).exists(); +} + +QString QFileDialogController::fullyQualifiedFilename(const QString& directoryPath, const QString& filename, const QString& fileExtension) +{ + return directoryPath + QStringLiteral("/") + filenameWithExtension(filename, fileExtension); +} diff --git a/src/QmlControls/QFileDialogController.h b/src/QmlControls/QFileDialogController.h new file mode 100644 index 000000000..59948dc7e --- /dev/null +++ b/src/QmlControls/QFileDialogController.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +#ifndef QFileDialogController_H +#define QFileDialogController_H + +#include +#include + +#include "QGCLoggingCategory.h" + +Q_DECLARE_LOGGING_CATEGORY(QFileDialogControllerLog) + +class QFileDialogController : public QObject +{ + Q_OBJECT + +public: + /// Return all file in the specified path which match the specified extension + Q_INVOKABLE QStringList getFiles(const QString& directoryPath, const QString& fileExtension); + + /// Returns the specified file name with the extension added it needed + Q_INVOKABLE QString filenameWithExtension(const QString& filename, const QString& fileExtension); + + /// Returns the fully qualified file name from the specified parts + Q_INVOKABLE QString fullyQualifiedFilename(const QString& directoryPath, const QString& filename, const QString& fileExtension); + + /// Check for file existence of specified fully qualified file name + Q_INVOKABLE bool fileExists(const QString& filename); + + Q_INVOKABLE QString urlToLocalFile(QUrl url) { return url.toLocalFile(); } +}; + +#endif diff --git a/src/QmlControls/QGCFileDialog.qml b/src/QmlControls/QGCFileDialog.qml new file mode 100644 index 000000000..17d719a5d --- /dev/null +++ b/src/QmlControls/QGCFileDialog.qml @@ -0,0 +1,159 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controllers 1.0 + +/// This control is meant to be a direct replacement for the standard Qml FileDialog control. +/// It differs for mobile builds which uses a completely custom file picker. +Item { + id: _root + visible: false + + property var qgcView + property string folder + property var nameFilters + property string fileExtension + property string title + property bool selectExisting + property bool selectFolder + + property bool _openForLoad + property real _margins: ScreenTools.defaultFontPixelHeight / 2 + + function openForLoad() { + _openForLoad = true + if (ScreenTools.isMobile && folder.length !== 0) { + qgcView.showDialog(mobileFileOpenDialog, title, qgcView.showDialogDefaultWidth, StandardButton.Cancel) + } else { + fullFileDialog.open() + } + } + + function openForSave() { + _openForLoad = false + if (ScreenTools.isMobile && folder.length !== 0) { + qgcView.showDialog(mobileFileSaveDialog, title, qgcView.showDialogDefaultWidth, StandardButton.Cancel | StandardButton.Ok) + } else { + fullFileDialog.open() + } + } + + function close() { + fullFileDialog.close() + } + + signal acceptedForLoad(string file) + signal acceptedForSave(string file) + signal rejected + + QFileDialogController { id: controller } + QGCPalette { id: qgcPal; colorGroupEnabled: true } + + FileDialog { + id: fullFileDialog + folder: "file://" + _root.folder + nameFilters: _root.nameFilters + title: _root.title + selectExisting: _root.selectExisting + selectMultiple: false + selectFolder: _root.selectFolder + + onAccepted: { + if (_openForLoad) { + _root.acceptedForLoad(controller.urlToLocalFile(fileUrl)) + } else { + _root.acceptedForSave(controller.urlToLocalFile(fileUrl)) + } + } + onRejected: _root.rejected() + } + + Component { + id: mobileFileOpenDialog + + QGCViewDialog { + Item { + anchors.margins: _margins + anchors.fill: parent + + QGCListView { + id: listView + anchors.fill: parent + spacing: _margins / 2 + orientation: ListView.Vertical + model: controller.getFiles(folder, fileExtension) + + delegate: QGCButton { + text: modelData + + onClicked: { + hideDialog() + _root.acceptedForLoad(controller.fullyQualifiedFilename(folder, modelData, fileExtension)) + } + } + } + + QGCLabel { + text: qsTr("No files") + visible: listView.model.length == 0 + } + } + } + } + + Component { + id: mobileFileSaveDialog + + QGCViewDialog { + function accept() { + if (filenameTextField.text == "") { + return + } + if (!replaceMessage.visible) { + if (controller.fileExists(controller.fullyQualifiedFilename(folder, filenameTextField.text, fileExtension))) { + replaceMessage.visible = true + return + } + } + _root.acceptedForSave(controller.fullyQualifiedFilename(folder, filenameTextField.text, fileExtension)) + hideDialog() + } + + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: ScreenTools.defaultFontPixelHeight + + QGCLabel { + text: qsTr("File name:") + } + + QGCTextField { + id: filenameTextField + onTextChanged: replaceMessage.visible = false + } + + QGCLabel { + anchors.left: parent.left + anchors.right: parent.right + wrapMode: Text.WordWrap + text: qsTr("File names must end with .%1 file extension. If missing it will be added.").arg(fileExtension) + } + + QGCLabel { + id: replaceMessage + anchors.left: parent.left + anchors.right: parent.right + wrapMode: Text.WordWrap + text: qsTr("The file %1 exists. Click Save again to replace it.").arg(filenameTextField.text) + visible: false + color: qgcPal.warningText + } + } + } + } +} diff --git a/src/QmlControls/QGCMobileFileOpenDialog.qml b/src/QmlControls/QGCMobileFileOpenDialog.qml deleted file mode 100644 index 02873ea71..000000000 --- a/src/QmlControls/QGCMobileFileOpenDialog.qml +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Dialogs 1.2 - -import QGroundControl 1.0 -import QGroundControl.ScreenTools 1.0 -import QGroundControl.Controls 1.0 -import QGroundControl.Controllers 1.0 -import QGroundControl.Palette 1.0 - -/// Simple file open dialog for mobile -QGCViewDialog { - property string fileExtension ///< File extension for file listing - - signal filenameReturned(string filename) - - readonly property real _margins: ScreenTools.defaultFontPixelHeight / 2 - - QGCMobileFileDialogController { id: controller } - QGCPalette { id: qgcPal; colorGroupEnabled: true } - - Item { - anchors.margins: _margins - anchors.fill: parent - - QGCListView { - anchors.fill: parent - spacing: _margins / 2 - orientation: ListView.Vertical - model: controller.getFiles(fileExtension) - - delegate: QGCButton { - text: modelData - - onClicked: { - hideDialog() - filenameReturned(controller.fullPath(modelData, fileExtension)) - } - } - } - - QGCLabel { - text: qsTr("No files") - visible: controller.getFiles(fileExtension).length == 0 - } - } -} diff --git a/src/QmlControls/QGCMobileFileSaveDialog.qml b/src/QmlControls/QGCMobileFileSaveDialog.qml deleted file mode 100644 index cf46485d0..000000000 --- a/src/QmlControls/QGCMobileFileSaveDialog.qml +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Dialogs 1.2 - -import QGroundControl 1.0 -import QGroundControl.ScreenTools 1.0 -import QGroundControl.Controls 1.0 -import QGroundControl.Controllers 1.0 -import QGroundControl.Palette 1.0 - -/// Simple file picker for mobile -QGCViewDialog { - property string fileExtension ///< File extension for file listing - - signal filenameReturned(string filename) - - readonly property real _margins: ScreenTools.defaultFontPixelHeight / 2 - - function accept() { - if (filenameTextField.text == "") { - return - } - if (!replaceMessage.visible) { - if (controller.fileExists(filenameTextField.text, fileExtension)) { - console.log("File exists") - replaceMessage.visible = true - return - } - } - filenameReturned(controller.fullPath(filenameTextField.text, fileExtension)) - hideDialog() - } - - QGCMobileFileDialogController { id: controller } - QGCPalette { id: qgcPal; colorGroupEnabled: true } - - Column { - anchors.left: parent.left - anchors.right: parent.right - spacing: ScreenTools.defaultFontPixelHeight - - QGCLabel { - text: qsTr("File name:") - } - - QGCTextField { - id: filenameTextField - onTextChanged: replaceMessage.visible = false - } - - QGCLabel { - anchors.left: parent.left - anchors.right: parent.right - wrapMode: Text.WordWrap - text: qsTr("File names must end with .%1 file extension. If missing it will be added.").arg(fileExtension) - } - - QGCLabel { - id: replaceMessage - anchors.left: parent.left - anchors.right: parent.right - wrapMode: Text.WordWrap - text: qsTr("The file %1 exists. Click Save again to replace it.").arg(filenameTextField.text) - visible: false - color: qgcPal.warningText - } - } -} - diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir index 3fbaad8e2..dbd7b9d67 100644 --- a/src/QmlControls/QGroundControl.Controls.qmldir +++ b/src/QmlControls/QGroundControl.Controls.qmldir @@ -33,13 +33,12 @@ QGCButton 1.0 QGCButton.qml QGCCheckBox 1.0 QGCCheckBox.qml QGCColoredImage 1.0 QGCColoredImage.qml QGCComboBox 1.0 QGCComboBox.qml +QGCFileDialog 1.0 QGCFileDialog.qml QGCFlickable 1.0 QGCFlickable.qml QGCGroupBox 1.0 QGCGroupBox.qml QGCLabel 1.0 QGCLabel.qml QGCListView 1.0 QGCListView.qml QGCMapLabel 1.0 QGCMapLabel.qml -QGCMobileFileOpenDialog 1.0 QGCMobileFileOpenDialog.qml -QGCMobileFileSaveDialog 1.0 QGCMobileFileSaveDialog.qml QGCMouseArea 1.0 QGCMouseArea.qml QGCMovableItem 1.0 QGCMovableItem.qml QGCPipable 1.0 QGCPipable.qml diff --git a/src/QmlControls/QGroundControlQmlGlobal.h b/src/QmlControls/QGroundControlQmlGlobal.h index 744a9cfd2..eb7394dc1 100644 --- a/src/QmlControls/QGroundControlQmlGlobal.h +++ b/src/QmlControls/QGroundControlQmlGlobal.h @@ -21,6 +21,7 @@ #include "FactMetaData.h" #include "SimulatedPosition.h" #include "QGCLoggingCategory.h" +#include "AppSettings.h" #ifdef QT_DEBUG #include "MockLink.h" @@ -118,8 +119,6 @@ public: Q_INVOKABLE bool linesIntersect(QPointF xLine1, QPointF yLine1, QPointF xLine2, QPointF yLine2); - Q_INVOKABLE QString urlToLocalFile(QUrl url) { return url.toLocalFile(); } - // Property accesors QString appName () { return qgcApp()->applicationName(); } @@ -151,9 +150,9 @@ public: void setFlightMapPosition (QGeoCoordinate& coordinate); void setFlightMapZoom (double zoom); - QString parameterFileExtension(void) const { return QGCApplication::parameterFileExtension; } - QString missionFileExtension(void) const { return QGCApplication::missionFileExtension; } - QString telemetryFileExtension(void) const { return QGCApplication::telemetryFileExtension; } + QString parameterFileExtension(void) const { return AppSettings::parameterFileExtension; } + QString missionFileExtension(void) const { return AppSettings::missionFileExtension; } + QString telemetryFileExtension(void) const { return AppSettings::telemetryFileExtension; } QString qgcVersion(void) const { return qgcApp()->applicationVersion(); } diff --git a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc index f4c009b1c..3ed439fd3 100644 --- a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc +++ b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc @@ -12,7 +12,7 @@ /// @author Gus Grubba #if !defined(__mobile__) -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "MainWindow.h" #endif @@ -407,7 +407,7 @@ QGCMapEngineManager::importSets(QString path) { //-- TODO: This has to be something fixed dir = QDir(QDir::homePath()).filePath(QString("export_%1.db").arg(QDateTime::currentDateTime().toTime_t())); #else - dir = QGCFileDialog::getOpenFileName( + dir = QGCQFileDialog::getOpenFileName( MainWindow::instance(), "Export Tile Set", QDir::homePath(), @@ -437,7 +437,7 @@ QGCMapEngineManager::exportSets(QString path) { #if defined(__mobile__) dir = QDir(QDir::homePath()).filePath(QString("export_%1.db").arg(QDateTime::currentDateTime().toTime_t())); #else - dir = QGCFileDialog::getSaveFileName( + dir = QGCQFileDialog::getSaveFileName( MainWindow::instance(), "Export Tile Set", QDir::homePath(), diff --git a/src/Settings/App.SettingsGroup.json b/src/Settings/App.SettingsGroup.json index 675af1fad..1c979df63 100644 --- a/src/Settings/App.SettingsGroup.json +++ b/src/Settings/App.SettingsGroup.json @@ -55,13 +55,6 @@ "units": "meters", "decimalPlaces": 2 }, -{ - "name": "MissionAutoLoadDir", - "shortDescription": "Mission auto load directory", - "longDescription": "The directory from which missions will be automatically loaded onto a vehicle when it connects. The mission file must be named AutoLoad#.mission where the # is replaced with the vehicle id.", - "type": "string", - "defaultValue": "" -}, { "name": "PromptFLightDataSave", "shortDescription": "Save telemetry Log after each flight", @@ -90,6 +83,13 @@ "type": "bool", "defaultValue": false }, +{ + "name": "AutoLoadMissions", + "shortDescription": "AutoLoad mission on vehicle connect", + "longDescription": "Automatically load a mission file named AutoLoad#.mission when a vehicle with id # connects.", + "type": "bool", + "defaultValue": false +}, { "name": "BaseDeviceFontPointSize", "shortDescription": "Application font size", @@ -116,9 +116,9 @@ "defaultValue": false }, { - "name": "TelemetrySavePath", - "shortDescription": "Telemetry log save directory", - "longDescription": "The directory to which telemetry logs are automatically saved to.", + "name": "SavePath", + "shortDescription": "Application save directory", + "longDescription": "Directory to which all data files are saved/loaded from", "type": "string", "defaultValue": "" } diff --git a/src/Settings/AppSettings.cc b/src/Settings/AppSettings.cc index 5a370d333..c230106dd 100644 --- a/src/Settings/AppSettings.cc +++ b/src/Settings/AppSettings.cc @@ -13,6 +13,7 @@ #include #include +#include const char* AppSettings::appSettingsGroupName = "App"; const char* AppSettings::offlineEditingFirmwareTypeSettingsName = "OfflineEditingFirmwareType"; @@ -21,7 +22,6 @@ const char* AppSettings::offlineEditingCruiseSpeedSettingsName = "Offline const char* AppSettings::offlineEditingHoverSpeedSettingsName = "OfflineEditingHoverSpeed"; const char* AppSettings::batteryPercentRemainingAnnounceSettingsName = "batteryPercentRemainingAnnounce"; const char* AppSettings::defaultMissionItemAltitudeSettingsName = "DefaultMissionItemAltitude"; -const char* AppSettings::missionAutoLoadDirSettingsName = "MissionAutoLoadDir"; const char* AppSettings::telemetrySaveName = "PromptFLightDataSave"; const char* AppSettings::telemetrySaveNotArmedName = "PromptFLightDataSaveNotArmed"; const char* AppSettings::audioMutedName = "AudioMuted"; @@ -29,7 +29,18 @@ const char* AppSettings::virtualJoystickName = "Virtual const char* AppSettings::appFontPointSizeName = "BaseDeviceFontPointSize"; const char* AppSettings::indoorPaletteName = "StyleIsDark"; const char* AppSettings::showLargeCompassName = "ShowLargeCompass"; -const char* AppSettings::telemetrySavePathName = "TelemetrySavePath"; +const char* AppSettings::savePathName = "SavePath"; +const char* AppSettings::autoLoadMissionsName = "AutoLoadMissions"; + +const char* AppSettings::parameterFileExtension = "params"; +const char* AppSettings::missionFileExtension = "mission"; +const char* AppSettings::fenceFileExtension = "fence"; +const char* AppSettings::rallyPointFileExtension = "rally"; +const char* AppSettings::telemetryFileExtension = "tlog"; + +const char* AppSettings::parameterDirectory = "Parameters"; +const char* AppSettings::telemetryDirectory = "Telemetry"; +const char* AppSettings::missionDirectory = "Missions"; AppSettings::AppSettings(QObject* parent) : SettingsGroup(appSettingsGroupName, QString() /* root settings group */, parent) @@ -39,7 +50,6 @@ AppSettings::AppSettings(QObject* parent) , _offlineEditingHoverSpeedFact(NULL) , _batteryPercentRemainingAnnounceFact(NULL) , _defaultMissionItemAltitudeFact(NULL) - , _missionAutoLoadDirFact(NULL) , _telemetrySaveFact(NULL) , _telemetrySaveNotArmedFact(NULL) , _audioMutedFact(NULL) @@ -47,11 +57,44 @@ AppSettings::AppSettings(QObject* parent) , _appFontPointSizeFact(NULL) , _indoorPaletteFact(NULL) , _showLargeCompassFact(NULL) - , _telemetrySavePathFact(NULL) + , _savePathFact(NULL) + , _autoLoadMissionsFact(NULL) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - qmlRegisterUncreatableType("QGroundControl.SettingsManager", 1, 0, "AppSettings", "Reference only"); + qmlRegisterUncreatableType("QGroundControl.SettingsManager", 1, 0, "AppSettings", "Reference only"); QGCPalette::setGlobalTheme(indoorPalette()->rawValue().toBool() ? QGCPalette::Dark : QGCPalette::Light); + + // Instantiate savePath so we can check for override and setup default path if needed + + Fact* savePathFact = savePath(); + QString appName = qgcApp()->applicationName(); + if (savePathFact->rawValue().toString().isEmpty() && _nameToMetaDataMap[savePathName]->rawDefaultValue().toString().isEmpty()) { +#ifdef __mobile__ + QDir rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); + savePathFact->setVisible(false); +#else + QDir rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); +#endif + savePathFact->setRawValue(rootDir.filePath(appName)); + } + + connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::savePathsChanged); + connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::_checkSavePathDirectories); + + _checkSavePathDirectories(); +} + +void AppSettings::_checkSavePathDirectories(void) +{ + QDir savePathDir(savePath()->rawValue().toString()); + if (!savePathDir.exists()) { + QDir().mkpath(savePathDir.absolutePath()); + } + if (savePathDir.exists()) { + savePathDir.mkdir(parameterDirectory); + savePathDir.mkdir(telemetryDirectory); + savePathDir.mkdir(missionDirectory); + } } Fact* AppSettings::offlineEditingFirmwareType(void) @@ -106,15 +149,6 @@ Fact* AppSettings::defaultMissionItemAltitude(void) return _defaultMissionItemAltitudeFact; } -Fact* AppSettings::missionAutoLoadDir(void) -{ - if (!_missionAutoLoadDirFact) { - _missionAutoLoadDirFact = _createSettingsFact(missionAutoLoadDirSettingsName); - } - - return _missionAutoLoadDirFact; -} - Fact* AppSettings::telemetrySave(void) { if (!_telemetrySaveFact) { @@ -185,12 +219,60 @@ Fact* AppSettings::showLargeCompass(void) return _showLargeCompassFact; } -Fact* AppSettings::telemetrySavePath(void) +Fact* AppSettings::savePath(void) +{ + if (!_savePathFact) { + _savePathFact = _createSettingsFact(savePathName); + } + + return _savePathFact; +} + +QString AppSettings::missionSavePath(void) +{ + QString fullPath; + + QString path = savePath()->rawValue().toString(); + if (!path.isEmpty() && QDir(path).exists()) { + QDir dir(path); + return dir.filePath(missionDirectory); + } + + return fullPath; +} + +QString AppSettings::parameterSavePath(void) +{ + QString fullPath; + + QString path = savePath()->rawValue().toString(); + if (!path.isEmpty() && QDir(path).exists()) { + QDir dir(path); + return dir.filePath(parameterDirectory); + } + + return fullPath; +} + +QString AppSettings::telemetrySavePath(void) +{ + QString fullPath; + + QString path = savePath()->rawValue().toString(); + if (!path.isEmpty() && QDir(path).exists()) { + QDir dir(path); + return dir.filePath(telemetryDirectory); + } + + return fullPath; +} + +Fact* AppSettings::autoLoadMissions(void) { - if (!_telemetrySavePathFact) { - _telemetrySavePathFact = _createSettingsFact(telemetrySavePathName); + if (!_autoLoadMissionsFact) { + _autoLoadMissionsFact = _createSettingsFact(autoLoadMissionsName); } - return _telemetrySavePathFact; + return _autoLoadMissionsFact; } diff --git a/src/Settings/AppSettings.h b/src/Settings/AppSettings.h index 91f1d2031..feaa7dbd3 100644 --- a/src/Settings/AppSettings.h +++ b/src/Settings/AppSettings.h @@ -25,7 +25,6 @@ public: Q_PROPERTY(Fact* offlineEditingHoverSpeed READ offlineEditingHoverSpeed CONSTANT) Q_PROPERTY(Fact* batteryPercentRemainingAnnounce READ batteryPercentRemainingAnnounce CONSTANT) Q_PROPERTY(Fact* defaultMissionItemAltitude READ defaultMissionItemAltitude CONSTANT) - Q_PROPERTY(Fact* missionAutoLoadDir READ missionAutoLoadDir CONSTANT) Q_PROPERTY(Fact* telemetrySave READ telemetrySave CONSTANT) Q_PROPERTY(Fact* telemetrySaveNotArmed READ telemetrySaveNotArmed CONSTANT) Q_PROPERTY(Fact* audioMuted READ audioMuted CONSTANT) @@ -33,7 +32,16 @@ public: Q_PROPERTY(Fact* appFontPointSize READ appFontPointSize CONSTANT) Q_PROPERTY(Fact* indoorPalette READ indoorPalette CONSTANT) Q_PROPERTY(Fact* showLargeCompass READ showLargeCompass CONSTANT) - Q_PROPERTY(Fact* telemetrySavePath READ telemetrySavePath CONSTANT) + Q_PROPERTY(Fact* savePath READ savePath CONSTANT) + Q_PROPERTY(Fact* autoLoadMissions READ autoLoadMissions CONSTANT) + + Q_PROPERTY(QString missionSavePath READ missionSavePath NOTIFY savePathsChanged) + Q_PROPERTY(QString parameterSavePath READ parameterSavePath NOTIFY savePathsChanged) + Q_PROPERTY(QString telemetrySavePath READ telemetrySavePath NOTIFY savePathsChanged) + + Q_PROPERTY(QString missionFileExtension MEMBER missionFileExtension CONSTANT) + Q_PROPERTY(QString parameterFileExtension MEMBER parameterFileExtension CONSTANT) + Q_PROPERTY(QString telemetryFileExtension MEMBER telemetryFileExtension CONSTANT) Fact* offlineEditingFirmwareType (void); Fact* offlineEditingVehicleType (void); @@ -41,7 +49,6 @@ public: Fact* offlineEditingHoverSpeed (void); Fact* batteryPercentRemainingAnnounce (void); Fact* defaultMissionItemAltitude (void); - Fact* missionAutoLoadDir (void); Fact* telemetrySave (void); Fact* telemetrySaveNotArmed (void); Fact* audioMuted (void); @@ -49,7 +56,12 @@ public: Fact* appFontPointSize (void); Fact* indoorPalette (void); Fact* showLargeCompass (void); - Fact* telemetrySavePath (void); + Fact* savePath (void); + Fact* autoLoadMissions (void); + + QString missionSavePath (void); + QString parameterSavePath (void); + QString telemetrySavePath (void); static const char* appSettingsGroupName; @@ -59,7 +71,6 @@ public: static const char* offlineEditingHoverSpeedSettingsName; static const char* batteryPercentRemainingAnnounceSettingsName; static const char* defaultMissionItemAltitudeSettingsName; - static const char* missionAutoLoadDirSettingsName; static const char* telemetrySaveName; static const char* telemetrySaveNotArmedName; static const char* audioMutedName; @@ -67,10 +78,27 @@ public: static const char* appFontPointSizeName; static const char* indoorPaletteName; static const char* showLargeCompassName; - static const char* telemetrySavePathName; + static const char* savePathName; + static const char* autoLoadMissionsName; + + // Application wide file extensions + static const char* parameterFileExtension; + static const char* missionFileExtension; + static const char* fenceFileExtension; + static const char* rallyPointFileExtension; + static const char* telemetryFileExtension; + + // Child directories of savePath for specific file types + static const char* parameterDirectory; + static const char* telemetryDirectory; + static const char* missionDirectory; + +signals: + void savePathsChanged(void); private slots: void _indoorPaletteChanged(void); + void _checkSavePathDirectories(void); private: SettingsFact* _offlineEditingFirmwareTypeFact; @@ -79,7 +107,6 @@ private: SettingsFact* _offlineEditingHoverSpeedFact; SettingsFact* _batteryPercentRemainingAnnounceFact; SettingsFact* _defaultMissionItemAltitudeFact; - SettingsFact* _missionAutoLoadDirFact; SettingsFact* _telemetrySaveFact; SettingsFact* _telemetrySaveNotArmedFact; SettingsFact* _audioMutedFact; @@ -87,7 +114,8 @@ private: SettingsFact* _appFontPointSizeFact; SettingsFact* _indoorPaletteFact; SettingsFact* _showLargeCompassFact; - SettingsFact* _telemetrySavePathFact; + SettingsFact* _savePathFact; + SettingsFact* _autoLoadMissionsFact; }; #endif diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc index 7c7dcc636..00b310adb 100644 --- a/src/Vehicle/Vehicle.cc +++ b/src/Vehicle/Vehicle.cc @@ -1665,17 +1665,19 @@ void Vehicle::_startMissionRequest(void) if (!_missionManagerInitialRequestSent && _parameterManager->parametersReady() && _vehicleCapabilitiesKnown) { qCDebug(VehicleLog) << "_startMissionRequest"; _missionManagerInitialRequestSent = true; - QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionAutoLoadDir()->rawValue().toString(); - if (missionAutoLoadDirPath.isEmpty()) { - _missionManager->requestMissionItems(); - } else { - QmlObjectListModel* visualItems = NULL; - QDir missionAutoLoadDir(missionAutoLoadDirPath); - QString autoloadFilename = missionAutoLoadDir.absoluteFilePath(tr("AutoLoad%1.mission").arg(_id)); - if (MissionController::loadItemsFromFile(this, autoloadFilename, &visualItems)) { - MissionController::sendItemsToVehicle(this, visualItems); + if (_settingsManager->appSettings()->autoLoadMissions()->rawValue().toBool()) { + QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionSavePath(); + if (!missionAutoLoadDirPath.isEmpty()) { + QmlObjectListModel* visualItems = NULL; + QDir missionAutoLoadDir(missionAutoLoadDirPath); + QString autoloadFilename = missionAutoLoadDir.absoluteFilePath(tr("AutoLoad%1.%2").arg(_id).arg(AppSettings::missionFileExtension)); + if (MissionController::loadItemsFromFile(this, autoloadFilename, &visualItems)) { + MissionController::sendItemsToVehicle(this, visualItems); + return; + } } } + _missionManager->requestMissionItems(); } else { if (!_parameterManager->parametersReady()) { qCDebug(VehicleLog) << "Delaying _startMissionRequest due to parameters not ready"; diff --git a/src/VehicleSetup/FirmwareUpgradeController.cc b/src/VehicleSetup/FirmwareUpgradeController.cc index 0378805d8..003833265 100644 --- a/src/VehicleSetup/FirmwareUpgradeController.cc +++ b/src/VehicleSetup/FirmwareUpgradeController.cc @@ -14,7 +14,7 @@ #include "FirmwareUpgradeController.h" #include "Bootloader.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCApplication.h" #include "QGCFileDownload.h" #include "QGCOptions.h" @@ -442,7 +442,7 @@ void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareId) } if (firmwareId.firmwareType == CustomFirmware) { - _firmwareFilename = QGCFileDialog::getOpenFileName(NULL, // Parent to main window + _firmwareFilename = QGCQFileDialog::getOpenFileName(NULL, // Parent to main window "Select Firmware File", // Dialog Caption QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory "Firmware Files (*.px4 *.bin *.ihx)"); // File filter diff --git a/src/ViewWidgets/CustomCommandWidgetController.cc b/src/ViewWidgets/CustomCommandWidgetController.cc index b8791a5dc..1465bceb6 100644 --- a/src/ViewWidgets/CustomCommandWidgetController.cc +++ b/src/ViewWidgets/CustomCommandWidgetController.cc @@ -11,7 +11,7 @@ #include "CustomCommandWidgetController.h" #include "MultiVehicleManager.h" #include "QGCMAVLink.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "UAS.h" #include "QGCApplication.h" @@ -53,7 +53,7 @@ void CustomCommandWidgetController::_activeVehicleChanged(Vehicle* activeVehicle void CustomCommandWidgetController::selectQmlFile(void) { QSettings settings; - QString qmlFile = QGCFileDialog::getOpenFileName(NULL, "Select custom Qml file", QString(), "Qml files (*.qml)"); + QString qmlFile = QGCQFileDialog::getOpenFileName(NULL, "Select custom Qml file", QString(), "Qml files (*.qml)"); if (qmlFile.isEmpty()) { _customQmlFile.clear(); settings.remove(_settingsKey); diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 6d8600def..ea141ca79 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -30,7 +30,7 @@ #include "QGCFlightGearLink.h" #include "QGC.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCMessageBox.h" #include "QGCApplication.h" #include "Vehicle.h" @@ -744,7 +744,7 @@ bool QGCFlightGearLink::connectSimulation() } // Let the user pick the right directory - QString dirPath = QGCFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName); + QString dirPath = QGCQFileDialog::getExistingDirectory(MainWindow::instance(), tr("Please select directory of FlightGear application : ") + fgAppName); if (dirPath.isEmpty()) { return false; } diff --git a/src/qgcunittest/FileDialogTest.cc b/src/qgcunittest/FileDialogTest.cc index 0c9b12e54..8af5c1f9d 100644 --- a/src/qgcunittest/FileDialogTest.cc +++ b/src/qgcunittest/FileDialogTest.cc @@ -9,12 +9,12 @@ /// @file -/// @brief Unit test for QGCFileDialog catching mechanism. +/// @brief Unit test for QGCQFileDialog catching mechanism. /// /// @author Don Gagne #include "FileDialogTest.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" FileDialogTest::FileDialogTest(void) { @@ -28,19 +28,19 @@ void FileDialogTest::_fileDialogExpected_test(void) for (int i=0; i diff --git a/src/qgcunittest/UnitTest.h b/src/qgcunittest/UnitTest.h index 2467c5edc..fc06f287d 100644 --- a/src/qgcunittest/UnitTest.h +++ b/src/qgcunittest/UnitTest.h @@ -28,7 +28,7 @@ #define UT_REGISTER_TEST(className) static UnitTestWrapper className(#className); class QGCMessageBox; -class QGCFileDialog; +class QGCQFileDialog; class LinkManager; class MockLink; class MainWindow; @@ -58,7 +58,7 @@ public: getSaveFileName }; - /// @brief Sets up for an expected QGCFileDialog + /// @brief Sets up for an expected QGCQFileDialog /// @param type Type of expected file dialog /// @param response Files to return from call. Multiple files only supported by getOpenFileNames void setExpectedFileDialog(enum FileDialogType type, QStringList response); @@ -67,7 +67,7 @@ public: expectFailNoFailure = 1 << 0, ///< not expecting any failures expectFailNoDialog = 1 << 1, ///< expecting a failure due to no dialog displayed expectFailBadResponseButton = 1 << 2, ///< expecting a failure due to bad button response (QGCMessageBox only) - expectFailWrongFileDialog = 1 << 3 ///< expecting one dialog type, got the wrong type (QGCFileDialog ony) + expectFailWrongFileDialog = 1 << 3 ///< expecting one dialog type, got the wrong type (QGCQFileDialog ony) }; /// @brief Check whether a message box was displayed and correctly responded to @@ -134,7 +134,7 @@ private: // This allows the private call to _messageBox friend class QGCMessageBox; - // When the app is running in unit test mode the QGCFileDialog methods are re-routed here. + // When the app is running in unit test mode the QGCQFileDialog methods are re-routed here. static QString _getExistingDirectory( QWidget* parent, @@ -167,7 +167,7 @@ private: static QString _fileDialogResponseSingle(enum FileDialogType type); // This allows the private calls to the file dialog methods - friend class QGCFileDialog; + friend class QGCQFileDialog; void _unitTestCalled(void); static QList& _testList(void); @@ -178,7 +178,7 @@ private: static QMessageBox::StandardButton _messageBoxResponseButton; ///< Response to next message box static int _missedMessageBoxCount; ///< Count of message box not checked with call to messageBoxWasDisplayed - // Catch QGCFileDialog calls + // Catch QGCQFileDialog calls static bool _fileDialogRespondedTo; ///< File dialog was responded to static bool _fileDialogResponseSet; ///< true: _fileDialogResponse was set by a call to UnitTest::setExpectedFileDialog static QStringList _fileDialogResponse; ///< Response to next file dialog diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc index e7da45413..cdfd274d8 100644 --- a/src/ui/QGCMAVLinkLogPlayer.cc +++ b/src/ui/QGCMAVLinkLogPlayer.cc @@ -10,7 +10,7 @@ #include "ui_QGCMAVLinkLogPlayer.h" #include "QGCApplication.h" #include "LinkManager.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCMessageBox.h" QGCMAVLinkLogPlayer::QGCMAVLinkLogPlayer(QWidget *parent) : @@ -69,7 +69,7 @@ void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void) return; } - QString logFilename = QGCFileDialog::getOpenFileName( + QString logFilename = QGCQFileDialog::getOpenFileName( this, tr("Load MAVLink Log File"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), diff --git a/src/ui/QGCUASFileView.cc b/src/ui/QGCUASFileView.cc index bbd8b5fec..e5dad5a70 100644 --- a/src/ui/QGCUASFileView.cc +++ b/src/ui/QGCUASFileView.cc @@ -10,7 +10,7 @@ #include "QGCUASFileView.h" #include "FileManager.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "UAS.h" #include @@ -54,10 +54,10 @@ void QGCUASFileView::_downloadFile(void) _ui.statusText->clear(); - QString downloadToHere = QGCFileDialog::getExistingDirectory(this, + QString downloadToHere = QGCQFileDialog::getExistingDirectory(this, "Download Directory", QDir::homePath(), - QGCFileDialog::ShowDirsOnly | QGCFileDialog::DontResolveSymlinks); + QGCQFileDialog::ShowDirsOnly | QGCQFileDialog::DontResolveSymlinks); // And now download to this location @@ -111,7 +111,7 @@ void QGCUASFileView::_uploadFile(void) item = item->parent(); } while (item); - QString uploadFromHere = QGCFileDialog::getOpenFileName(this, "Upload File", QDir::homePath()); + QString uploadFromHere = QGCQFileDialog::getOpenFileName(this, "Upload File", QDir::homePath()); _ui.statusText->setText(QString("Uploading: %1").arg(uploadFromHere)); diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc index f0d1a3a3b..5f63085a3 100644 --- a/src/ui/linechart/LinechartWidget.cc +++ b/src/ui/linechart/LinechartWidget.cc @@ -37,7 +37,7 @@ #include "LogCompressor.h" #include "QGC.h" #include "MG.h" -#include "QGCFileDialog.h" +#include "QGCQFileDialog.h" #include "QGCMessageBox.h" #include "QGCApplication.h" #include "SettingsManager.h" @@ -433,7 +433,7 @@ void LinechartWidget::startLogging() // Let user select the log file name // QDate date(QDate::currentDate()); // QString("./pixhawk-log-" + date.toString("yyyy-MM-dd") + "-" + QString::number(logindex) + ".log") - QString fileName = QGCFileDialog::getSaveFileName(this, + QString fileName = QGCQFileDialog::getSaveFileName(this, tr("Save Log File"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr("Log Files (*.log)"), diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml index 0d6e9ac31..6bedafc08 100644 --- a/src/ui/preferences/GeneralSettings.qml +++ b/src/ui/preferences/GeneralSettings.qml @@ -26,18 +26,17 @@ import QGroundControl.Controllers 1.0 import QGroundControl.SettingsManager 1.0 QGCView { - id: qgcView + id: _qgcView viewPanel: panel color: qgcPal.window anchors.fill: parent anchors.margins: ScreenTools.defaultFontPixelWidth property Fact _percentRemainingAnnounce: QGroundControl.settingsManager.appSettings.batteryPercentRemainingAnnounce - property Fact _autoLoadDir: QGroundControl.settingsManager.appSettings.missionAutoLoadDir + property Fact _savePath: QGroundControl.settingsManager.appSettings.savePath property Fact _appFontPointSize: QGroundControl.settingsManager.appSettings.appFontPointSize property real _labelWidth: ScreenTools.defaultFontPixelWidth * 15 property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 30 - property Fact _telemPath: QGroundControl.settingsManager.appSettings.telemetrySavePath property Fact _videoPath: QGroundControl.settingsManager.videoSettings.videoSavePath property Fact _mapProvider: QGroundControl.settingsManager.flightMapSettings.mapProvider property Fact _mapType: QGroundControl.settingsManager.flightMapSettings.mapType @@ -56,14 +55,14 @@ QGCView { contentWidth: settingsColumn.width Column { id: settingsColumn - width: qgcView.width + width: _qgcView.width spacing: ScreenTools.defaultFontPixelHeight * 0.5 anchors.margins: ScreenTools.defaultFontPixelWidth //----------------------------------------------------------------- //-- Units Item { - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 height: unitLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -76,7 +75,7 @@ QGCView { } Rectangle { height: unitsCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 color: qgcPal.windowShade anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -115,7 +114,7 @@ QGCView { //----------------------------------------------------------------- //-- Miscellanous Item { - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 height: miscLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -128,7 +127,7 @@ QGCView { } Rectangle { height: miscCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 color: qgcPal.windowShade anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -232,38 +231,6 @@ QGCView { property Fact _telemetrySaveNotArmed: QGroundControl.settingsManager.appSettings.telemetrySaveNotArmed } - //----------------------------------------------------------------- - //-- Telemetry save path - Row { - spacing: ScreenTools.defaultFontPixelWidth - visible: QGroundControl.settingsManager.appSettings.telemetrySavePath.visible - - QGCLabel { - anchors.baseline: telemBrowse.baseline - text: qsTr("Telemetry save path:") - enabled: promptSaveLog.checked - } - QGCLabel { - anchors.baseline: telemBrowse.baseline - text: _telemPath.value == "" ? qsTr("") : _telemPath.value - enabled: promptSaveLog.checked - } - QGCButton { - id: telemBrowse - text: "Browse" - enabled: promptSaveLog.checked - onClicked: telemDialog.visible = true - - FileDialog { - id: telemDialog - title: "Choose a location to save telemetry files." - folder: "file://" + _telemPath.value - selectFolder: true - onAccepted: _telemPath.value = QGroundControl.urlToLocalFile(telemDialog.fileUrl) - } - } - } - //----------------------------------------------------------------- //-- Clear settings QGCCheckBox { @@ -337,43 +304,45 @@ QGCView { fact: QGroundControl.settingsManager.appSettings.defaultMissionItemAltitude } } + //----------------------------------------------------------------- //-- Mission AutoLoad + FactCheckBox { + text: qsTr("AutoLoad missions") + fact: _autoLoad + visible: _autoLoad.visible + + property Fact _autoLoad: QGroundControl.settingsManager.appSettings.autoLoadMissions + } + + //----------------------------------------------------------------- + //-- Save path Row { spacing: ScreenTools.defaultFontPixelWidth - visible: _autoLoadDir.visible - - QGCCheckBox { - id: autoLoadCheckbox - anchors.verticalCenter: parent.verticalCenter - text: qsTr("AutoLoad mission directory:") - checked: _autoLoadDir.valueString + visible: _savePath.visible - onClicked: { - if (checked) { - _autoLoadDir.rawValue = QGroundControl.urlToLocalFile(autoloadDirPicker.shortcuts.home) - } else { - _autoLoadDir.rawValue = "" - } - } + QGCLabel { + anchors.baseline: savePathBrowse.baseline + text: qsTr("File save path:") } - FactTextField { - id: autoLoadDirField - width: _editFieldWidth - enabled: autoLoadCheckbox.checked - anchors.verticalCenter: parent.verticalCenter - fact: _autoLoadDir + QGCLabel { + anchors.baseline: savePathBrowse.baseline + text: _savePath.rawValue === "" ? qsTr("") : _savePath.value } QGCButton { - text: qsTr("Browse") - onClicked: autoloadDirPicker.visible = true - - FileDialog { - id: autoloadDirPicker - title: qsTr("Choose the location of mission file.") - folder: "file://" + _autoLoadDir.value + id: savePathBrowse + text: "Browse" + onClicked: savePathBrowseDialog.openForLoad() + + QGCFileDialog { + id: savePathBrowseDialog + qgcView: _qgcView + title: qsTr("Choose the location to save files:") + folder: _savePath.rawValue + selectExisting: true selectFolder: true - onAccepted: _autoLoadDir.rawValue = QGroundControl.urlToLocalFile(autoloadDirPicker.fileUrl) + + onAcceptedForLoad: _savePath.rawValue = file } } } @@ -430,7 +399,7 @@ QGCView { //----------------------------------------------------------------- //-- Autoconnect settings Item { - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 height: autoConnectLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -443,7 +412,7 @@ QGCView { } Rectangle { height: autoConnectCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 color: qgcPal.windowShade anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -482,7 +451,7 @@ QGCView { //----------------------------------------------------------------- //-- Video Source Item { - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 height: videoLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter @@ -495,7 +464,7 @@ QGCView { } Rectangle { height: videoCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: qgcView.width * 0.8 + width: _qgcView.width * 0.8 color: qgcPal.windowShade anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter -- 2.22.0