QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
QGCFileDialogController.cc
Go to the documentation of this file.
3#include "SettingsManager.h"
4#include "AppSettings.h"
5
6#include <QtCore/QDir>
7
8#ifdef Q_OS_ANDROID
9#include <QtCore/QPointer>
10#include "AndroidInterface.h"
11#endif
12
13QGC_LOGGING_CATEGORY(QGCFileDialogControllerLog, "QMLControls.QGCFileDialogController")
14
16 : QObject(parent)
17{
18 qCDebug(QGCFileDialogControllerLog) << this;
19}
20
22{
23 qCDebug(QGCFileDialogControllerLog) << this;
24}
25
26QStringList QGCFileDialogController::getFiles(const QString &directoryPath, const QStringList &nameFilters)
27{
28 qCDebug(QGCFileDialogControllerLog) << "getFiles" << directoryPath << nameFilters;
29
30 QDir fileDir(directoryPath);
31 const QFileInfoList fileInfoList = fileDir.entryInfoList(nameFilters, QDir::Files, QDir::Name);
32
33 QStringList files;
34 for (const QFileInfo &fileInfo: fileInfoList) {
35 qCDebug(QGCFileDialogControllerLog) << "getFiles found" << fileInfo.fileName();
36 files << fileInfo.fileName();
37 }
38
39 return files;
40}
41
42bool QGCFileDialogController::fileExists(const QString &filename)
43{
44 return QFile(filename).exists();
45}
46
47QString QGCFileDialogController::fullyQualifiedFilename(const QString& directoryPath, const QString& filename, const QStringList& nameFilters)
48{
49 QString firstFileExtention;
50
51 // Check that the filename has one of the specified file extensions
52
53 bool extensionFound = true;
54 if (nameFilters.count()) {
55 extensionFound = false;
56 for (const QString& nameFilter: nameFilters) {
57 if (nameFilter.startsWith("*.")) {
58 const QString fileExtension = nameFilter.right(nameFilter.length() - 2);
59 if (fileExtension != "*") {
60 if (firstFileExtention.isEmpty()) {
61 firstFileExtention = fileExtension;
62 }
63 if (filename.endsWith(fileExtension)) {
64 extensionFound = true;
65 break;
66 }
67 }
68 } else if (nameFilter != "*") {
69 qCWarning(QGCFileDialogControllerLog) << "unsupported name filter format" << nameFilter;
70 }
71 }
72 }
73
74 // Add the extension if it is missing
75 QString filenameWithExtension = filename;
76 if (!extensionFound) {
77 filenameWithExtension = QStringLiteral("%1.%2").arg(filename).arg(firstFileExtention);
78 }
79
80 return (directoryPath + QStringLiteral("/") + filenameWithExtension);
81}
82
83void QGCFileDialogController::deleteFile(const QString &filename)
84{
85 QFile::remove(filename);
86}
87
89{
90#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
91 const QString defaultSavePath = SettingsManager::instance()->appSettings()->savePath()->rawValueString();
92 if (fullFolderPath.startsWith(defaultSavePath)) {
93 const int lastDirSepIndex = fullFolderPath.lastIndexOf(QStringLiteral("/"));
94 return (QCoreApplication::applicationName() + QStringLiteral("/") + fullFolderPath.right(fullFolderPath.length() - lastDirSepIndex));
95 }
96#else
97 qCWarning(QGCFileDialogControllerLog) << Q_FUNC_INFO << "should only be used in mobile builds";
98#endif
99 return fullFolderPath;
100}
101
103{
104 // For some strange reason on Qt6 running on Linux files returned by FileDialog are not returned as local file urls.
105 // Seems to be new behavior with Qt6.
106 QString result;
107 if (url.isLocalFile()) {
108 result = url.toLocalFile();
109 } else {
110 result = url.toString();
111 }
112
113#ifndef Q_OS_WIN
114 // Qt6 Linux FileDialog can return file URLs missing the third slash
115 // (file://path instead of file:///path). Qt parses that as host=first-segment,
116 // path=rest, and toLocalFile() yields "//host/rest" (UNC-style). On non-Windows
117 // platforms drop the spurious leading slash so it becomes a normal absolute path.
118 if (result.startsWith(QStringLiteral("//"))) {
119 result = result.mid(1);
120 }
121#endif
122
123 return result;
124}
125
127{
128#ifdef Q_OS_ANDROID
129 const QString missionPath = SettingsManager::instance()->appSettings()->missionSavePath();
130 if (missionPath.isEmpty()) {
131 qCWarning(QGCFileDialogControllerLog) << "Missions save path is empty";
132 emit importFailed(tr("Missions directory is not configured"));
133 return;
134 }
135
136 QDir dir(missionPath);
137 if (!dir.exists()) {
138 qCWarning(QGCFileDialogControllerLog) << "Missions save path does not exist";
139 emit importFailed(tr("Missions save path does not exist"));
140 return;
141 }
142
143 QPointer<QGCFileDialogController> self = this;
144 AndroidInterface::openFileImportDialog(missionPath, [self](const QString& filePath) {
145 if (self) {
146 QMetaObject::invokeMethod(
147 self,
148 [filePath, self]() { self->_handleImportResult(filePath); },
149 Qt::QueuedConnection);
150 }
151 });
152#else
153 qCWarning(QGCFileDialogControllerLog) << Q_FUNC_INFO << "only supported on Android";
154#endif
155}
156
157#ifdef Q_OS_ANDROID
158
159void QGCFileDialogController::_handleImportResult(const QString& filePath)
160{
161 if (filePath.isEmpty()) {
162 qCWarning(QGCFileDialogControllerLog) << "Import failed: empty file path received from Java";
163 emit importFailed(tr("Failed to import file"));
164 return;
165 }
166
167 qCDebug(QGCFileDialogControllerLog) << "File imported successfully to:" << filePath;
168 emit fileImported(filePath);
169}
170
171#endif // Q_OS_ANDROID
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QString missionSavePath()
void fileImported(const QString &filePath)
static Q_INVOKABLE bool fileExists(const QString &filename)
Check for file existence of specified fully qualified file name.
static Q_INVOKABLE QString fullFolderPathToShortMobilePath(const QString &fullFolderPath)
static Q_INVOKABLE QString urlToLocalFile(QUrl url)
static Q_INVOKABLE void deleteFile(const QString &filename)
Deletes the file specified by the fully qualified file name.
static Q_INVOKABLE QStringList getFiles(const QString &directoryPath, const QStringList &nameFilters)
Return all file in the specified path which match the specified extension.
Q_INVOKABLE void importFromNativePicker()
static Q_INVOKABLE QString fullyQualifiedFilename(const QString &directoryPath, const QString &filename, const QStringList &nameFilters=QStringList())
void importFailed(const QString &errorMessage)
static SettingsManager * instance()
AppSettings * appSettings() const
void openFileImportDialog(const QString &destPath, std::function< void(const QString &)> callback)