12#include <QtCore/QFileInfo>
22 , _ftpManager(_vehicle->ftpManager())
37 if (_operation != Operation::None) {
38 _setErrorString(tr(
"Another FTP operation is in progress"));
42 const QString previousPath = _currentPath;
44 _resetDirectoryState();
47 _setErrorString(QString());
50 _setOperation(Operation::List);
54 const uint8_t compId = _componentIdForRequest(componentId);
56 qCWarning(FTPControllerLog) <<
"Failed to start list operation for" << uri;
57 _setErrorString(tr(
"Failed to list %1").arg(uri));
58 _currentPath = previousPath;
70 if (_operation != Operation::None) {
71 const QString
error = tr(
"Another FTP operation is in progress");
72 _setErrorString(
error);
78 const QString
error = tr(
"Could not create directory %1").arg(localDir);
79 _setErrorString(
error);
84 const QString absoluteLocalDir = QDir(localDir).absolutePath();
86 _lastDownloadFile.clear();
88 _setErrorString(QString());
91 _setOperation(Operation::Download);
95 const uint8_t compId = _componentIdForRequest(componentId);
96 if (!_ftpManager->
download(compId, uri, absoluteLocalDir, fileName)) {
97 qCWarning(FTPControllerLog) <<
"Failed to start download" << uri << absoluteLocalDir;
98 const QString
error = tr(
"Failed to download %1").arg(uri);
99 _setErrorString(
error);
111 if (_operation != Operation::None) {
112 const QString
error = tr(
"Another FTP operation is in progress");
113 _setErrorString(
error);
118 QFileInfo sourceInfo(localFile);
119 if (!sourceInfo.exists() || !sourceInfo.isFile()) {
120 const QString
error = tr(
"File %1 does not exist").arg(localFile);
121 _setErrorString(
error);
126 _lastUploadTarget.clear();
128 _setErrorString(QString());
131 _setOperation(Operation::Upload);
135 const uint8_t compId = _componentIdForRequest(componentId);
136 if (!_ftpManager->
upload(compId, uri, sourceInfo.absoluteFilePath())) {
137 qCWarning(FTPControllerLog) <<
"Failed to start upload" << sourceInfo.absoluteFilePath() << uri;
138 const QString
error = tr(
"Failed to upload %1").arg(sourceInfo.fileName());
139 _setErrorString(
error);
151 if (_operation != Operation::None) {
152 const QString
error = tr(
"Another FTP operation is in progress");
153 _setErrorString(
error);
158 _setErrorString(QString());
160 _setOperation(Operation::Delete);
162 const uint8_t compId = _componentIdForRequest(componentId);
164 qCWarning(FTPControllerLog) <<
"Failed to start delete" << uri;
165 const QString
error = tr(
"Failed to delete %1").arg(uri);
166 _setErrorString(
error);
178 switch (_operation) {
179 case Operation::Download:
182 case Operation::Upload:
185 case Operation::List:
188 case Operation::Delete:
191 case Operation::None:
196void FTPController::_handleDownloadComplete(
const QString &filePath,
const QString &
error)
198 if (_operation != Operation::Download) {
204 if (
error.isEmpty()) {
205 if (!filePath.isEmpty()) {
206 _lastDownloadFile = filePath;
210 _setErrorString(QString());
212 _setErrorString(
error);
213 _lastDownloadFile.clear();
214 _lastDownloadIsArchive =
false;
221void FTPController::_handleUploadComplete(
const QString &remotePath,
const QString &
error)
223 if (_operation != Operation::Upload) {
229 if (
error.isEmpty()) {
230 _lastUploadTarget = remotePath;
232 _setErrorString(QString());
234 _setErrorString(
error);
235 _lastUploadTarget.clear();
242void FTPController::_handleDirectoryComplete(
const QStringList &entries,
const QString &
error)
244 if (_operation != Operation::List) {
250 if (
error.isEmpty()) {
251 if (_directoryEntries != entries) {
252 _directoryEntries = entries;
255 _setErrorString(QString());
257 _setErrorString(
error);
258 _resetDirectoryState();
264void FTPController::_handleDeleteComplete(
const QString &remotePath,
const QString &
error)
268 if (_operation != Operation::Delete) {
274 if (
error.isEmpty()) {
275 _setErrorString(QString());
277 _setErrorString(
error);
283void FTPController::_handleCommandProgress(
float value)
285 if (_operation == Operation::Download || _operation == Operation::Upload) {
286 if (std::fabs(_progress - value) > std::numeric_limits<float>::epsilon()) {
293void FTPController::_setBusy(
bool busy)
303void FTPController::_setOperation(Operation operation)
305 if (_operation == operation) {
309 _operation = operation;
313void FTPController::_clearOperation()
315 _setOperation(Operation::None);
316 if (std::fabs(_progress) > std::numeric_limits<float>::epsilon()) {
322void FTPController::_setErrorString(
const QString &
error)
324 if (_errorString ==
error) {
328 _errorString =
error;
332void FTPController::_resetDirectoryState()
334 if (!_directoryEntries.isEmpty()) {
335 _directoryEntries.clear();
340uint8_t FTPController::_componentIdForRequest(
int componentId)
const
342 if (componentId <= 0 || componentId > std::numeric_limits<uint8_t>::max()) {
343 return MAV_COMP_ID_AUTOPILOT1;
346 return static_cast<uint8_t
>(componentId);
351 if (archivePath.isEmpty()) {
352 _setErrorString(tr(
"No archive path specified"));
356 if (!QFile::exists(archivePath)) {
357 _setErrorString(tr(
"Archive file not found: %1").arg(archivePath));
362 _setErrorString(tr(
"Not a supported archive format: %1").arg(archivePath));
367 _setErrorString(QString());
374 _setErrorString(tr(
"Extraction already in progress"));
378 if (archivePath.isEmpty()) {
379 _setErrorString(tr(
"No archive path specified"));
383 if (!QFile::exists(archivePath)) {
384 _setErrorString(tr(
"Archive file not found: %1").arg(archivePath));
388 QString targetDir = outputDir;
389 if (targetDir.isEmpty()) {
390 targetDir = QFileInfo(archivePath).absolutePath();
394 _setErrorString(tr(
"Could not create output directory: %1").arg(targetDir));
398 _extractionOutputDir = targetDir;
400 if (_extractionJob ==
nullptr) {
403 this, &FTPController::_handleExtractionProgress);
405 this, &FTPController::_handleExtractionFinished);
409 _extractionProgress = 0.0F;
419 if (_extractionJob !=
nullptr && _extracting) {
424void FTPController::_handleExtractionProgress(qreal progress)
426 const auto newProgress =
static_cast<float>(
progress);
427 if (std::fabs(_extractionProgress - newProgress) > std::numeric_limits<float>::epsilon()) {
428 _extractionProgress = newProgress;
433void FTPController::_handleExtractionFinished(
bool success)
439 _setErrorString(QString());
442 const QString
error = _extractionJob !=
nullptr ? _extractionJob->
errorString() : tr(
"Extraction failed");
443 _setErrorString(
error);
447 _extractionProgress = 0.0F;
QObject wrapper for async compression operations using QtConcurrent/QPromise.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QML-facing controller for MAVLink FTP operations.
void uploadComplete(const QString &remotePath, const QString &error)
void directoryEntriesChanged()
void downloadComplete(const QString &filePath, const QString &error)
void extractionComplete(const QString &outputDir, const QString &error)
Q_INVOKABLE void cancelActiveOperation()
Q_INVOKABLE bool downloadFile(const QString &uri, const QString &localDir, const QString &fileName=QString(), int componentId=MAV_COMP_ID_AUTOPILOT1)
void currentPathChanged()
void errorStringChanged()
Q_INVOKABLE bool extractArchive(const QString &archivePath, const QString &outputDir=QString())
Q_INVOKABLE bool uploadFile(const QString &localFile, const QString &uri, int componentId=MAV_COMP_ID_AUTOPILOT1)
Q_INVOKABLE void cancelExtraction()
Cancel an in-progress extraction.
void deleteComplete(const QString &remotePath, const QString &error)
void extractionProgressChanged()
Q_INVOKABLE bool browseArchive(const QString &archivePath)
void activeOperationChanged()
void lastDownloadFileChanged()
void lastUploadTargetChanged()
Q_INVOKABLE bool deleteFile(const QString &uri, int componentId=MAV_COMP_ID_AUTOPILOT1)
Q_INVOKABLE bool listDirectory(const QString &uri, int componentId=MAV_COMP_ID_AUTOPILOT1)
bool listDirectory(uint8_t fromCompId, const QString &fromURI)
bool deleteFile(uint8_t fromCompId, const QString &fromURI)
bool upload(uint8_t toCompId, const QString &toURI, const QString &fromFile)
void uploadComplete(const QString &file, const QString &errorMsg)
void commandProgress(float value)
void downloadComplete(const QString &file, const QString &errorMsg)
void cancelListDirectory()
void deleteComplete(const QString &file, const QString &errorMsg)
bool download(uint8_t fromCompId, const QString &fromURI, const QString &toDir, const QString &fileName="", bool checksize=true)
void listDirectoryComplete(const QStringList &dirList, const QString &errorMsg)
List model for archive contents, suitable for QML ListView binding.
void setArchivePath(const QString &path)
QObject wrapper for compression operations with progress signals.
QString errorString() const
void progressChanged(qreal progress)
Emitted when progress changes (0.0 to 1.0)
void cancel()
Cancel current operation.
void finished(bool success)
void extractArchive(const QString &archivePath, const QString &outputDirectoryPath, qint64 maxBytes=0)
bool isArchiveFile(const QString &filePath)
Check if file path indicates an archive file (.zip, .tar, .tar.gz, etc.)
bool ensureDirectoryExists(const QString &path)