diff --git a/src/qgcunittest/FileManagerTest.h b/src/qgcunittest/FileManagerTest.h index b747a92da018b5ecc22b7c30f5f512f06bd3fa7d..f5a602591c89373f3cc63c544a8a4ccdc951bcac 100644 --- a/src/qgcunittest/FileManagerTest.h +++ b/src/qgcunittest/FileManagerTest.h @@ -53,13 +53,11 @@ private slots: void cleanup(void); // Test cases -#if 0 void _ackTest(void); void _noAckTest(void); void _resetTest(void); void _listTest(void); void _readDownloadTest(void); -#endif void _streamDownloadTest(void); // Connected to FileManager listEntry signal @@ -70,19 +68,15 @@ private: enum { listEntrySignalIndex = 0, - listCompleteSignalIndex, - downloadFileLengthSignalIndex, - downloadFileCompleteSignalIndex, - errorMessageSignalIndex, + commandCompleteSignalIndex, + commandErrorSignalIndex, maxSignalIndex }; enum { - listEntrySignalMask = 1 << listEntrySignalIndex, - listCompleteSignalMask = 1 << listCompleteSignalIndex, - downloadFileLengthSignalMask = 1 << downloadFileLengthSignalIndex, - downloadFileCompleteSignalMask = 1 << downloadFileCompleteSignalIndex, - errorMessageSignalMask = 1 << errorMessageSignalIndex, + listEntrySignalMask = 1 << listEntrySignalIndex, + commandCompleteSignalMask = 1 << commandCompleteSignalIndex, + commandErrorSignalMask = 1 << errorMessageSignalIndex, }; static const uint8_t _systemIdQGC = 255; diff --git a/src/uas/FileManager.cc b/src/uas/FileManager.cc index 9410cfc5c12f82918f0dc01f550d75c52674af5c..4c8484385e1f7c8144066271d9bcdfc454cd4045 100644 --- a/src/uas/FileManager.cc +++ b/src/uas/FileManager.cc @@ -48,20 +48,22 @@ FileManager::FileManager(QObject* parent, UASInterface* uas, uint8_t unitTestSys Q_ASSERT(sizeof(RequestHeader) == 12); } -/// @brief Respond to the Ack associated with the Open command with the next Read command. +/// Respond to the Ack associated with the Open command with the next read command. void FileManager::_openAckResponse(Request* openAck) { - Q_ASSERT(_currentOperation == kCOOpenRead || _currentOperation == kCOOpenStream); + qCDebug(FileManagerLog) << QString("_openAckResponse: _currentOperation(%1) _readFileLength(%2)").arg(_currentOperation).arg(openAck->openFileLength); + + Q_ASSERT(_currentOperation == kCOOpenRead || _currentOperation == kCOOpenBurst); _currentOperation = _currentOperation == kCOOpenRead ? kCORead : kCOBurst; _activeSession = openAck->hdr.session; // File length comes back in data Q_ASSERT(openAck->hdr.size == sizeof(uint32_t)); - emit downloadFileLength(openAck->openFileLength); + _downloadFileSize = openAck->openFileLength; // Start the sequence of read commands - _downloadOffset = 0; // Start reading at beginning of file + _downloadOffset = 0; // Start reading at beginning of file _readFileAccumulator.clear(); // Start with an empty file Request request; @@ -74,10 +76,14 @@ void FileManager::_openAckResponse(Request* openAck) _sendRequest(&request); } -/// @brief Closes out a read session by writing the file and doing cleanup. +/// Closes out a download session by writing the file and doing cleanup. /// @param success true: successful download completion, false: error during download void FileManager::_closeDownloadSession(bool success) { + qCDebug(FileManagerLog) << QString("_closeDownloadSession: success(%1)").arg(success); + + _currentOperation = kCOIdle; + if (success) { QString downloadFilePath = _readFileDownloadDir.absoluteFilePath(_readFileDownloadFilename); @@ -95,11 +101,31 @@ void FileManager::_closeDownloadSession(bool success) } file.close(); - emit downloadFileComplete(); + emit commandComplete(); } + + // If !success error is emitted elsewhere // Close the open session - _sendTerminateCommand(); + _sendResetCommand(); +} + +/// Closes out an upload session doing cleanup. +/// @param success true: successful upload completion, false: error during download +void FileManager::_closeUploadSession(bool success) +{ + qCDebug(FileManagerLog) << QString("_closeUploadSession: success(%1)").arg(success); + + _currentOperation = kCOIdle; + _writeFileAccumulator.clear(); + _writeFileSize = 0; + + if (success) { + emit commandComplete(); + } + + // Close the open session + _sendResetCommand(); } /// Respond to the Ack associated with the Read or Stream commands. @@ -107,15 +133,13 @@ void FileManager::_closeDownloadSession(bool success) void FileManager::_downloadAckResponse(Request* readAck, bool readFile) { if (readAck->hdr.session != _activeSession) { - _currentOperation = kCOIdle; - _readFileAccumulator.clear(); + _closeDownloadSession(false /* failure */); _emitErrorMessage(tr("Download: Incorrect session returned")); return; } if (readAck->hdr.offset != _downloadOffset) { - _currentOperation = kCOIdle; - _readFileAccumulator.clear(); + _closeDownloadSession(false /* failure */); _emitErrorMessage(tr("Download: Offset returned (%1) differs from offset requested/expected (%2)").arg(readAck->hdr.offset).arg(_downloadOffset)); return; } @@ -124,7 +148,10 @@ void FileManager::_downloadAckResponse(Request* readAck, bool readFile) _downloadOffset += readAck->hdr.size; _readFileAccumulator.append((const char*)readAck->data, readAck->hdr.size); - emit downloadFileProgress(_readFileAccumulator.length()); + + if (_downloadFileSize != 0) { + emit commandProgress(100 * ((float)_readFileAccumulator.length() / (float)_downloadFileSize)); + } if (readAck->hdr.size == sizeof(readAck->data)) { if (readFile || readAck->hdr.burstComplete) { @@ -143,7 +170,6 @@ void FileManager::_downloadAckResponse(Request* readAck, bool readFile) } } else if (readFile) { // We only receieved a partial buffer back. These means we are at EOF - _currentOperation = kCOIdle; _closeDownloadSession(true /* success */); } } @@ -198,7 +224,7 @@ void FileManager::_listAckResponse(Request* listAck) // Directory is empty, we're done Q_ASSERT(listAck->hdr.opcode == kRspAck); _currentOperation = kCOIdle; - emit listComplete(); + emit commandComplete(); } else { // Possibly more entries to come, need to keep trying till we get EOF _currentOperation = kCOList; @@ -210,14 +236,16 @@ void FileManager::_listAckResponse(Request* listAck) /// @brief Respond to the Ack associated with the create command. void FileManager::_createAckResponse(Request* createAck) { + qCDebug(FileManagerLog) << "_createAckResponse"; + _currentOperation = kCOWrite; _activeSession = createAck->hdr.session; - // Start the sequence of read commands + // Start the sequence of write commands from the beginning of the file - _writeOffset = 0; // Start writing at beginning of file + _writeOffset = 0; _writeSize = 0; - + _writeFileDatablock(); } @@ -225,37 +253,30 @@ void FileManager::_createAckResponse(Request* createAck) void FileManager::_writeAckResponse(Request* writeAck) { if(_writeOffset + _writeSize >= _writeFileSize){ - _writeFileAccumulator.clear(); - _writeFileSize = 0; - _currentOperation = kCOIdle; - emit uploadFileComplete(); + _closeUploadSession(true /* success */); } if (writeAck->hdr.session != _activeSession) { - _currentOperation = kCOIdle; - _writeFileAccumulator.clear(); + _closeUploadSession(false /* failure */); _emitErrorMessage(tr("Write: Incorrect session returned")); return; } if (writeAck->hdr.offset != _writeOffset) { - _currentOperation = kCOIdle; - _writeFileAccumulator.clear(); + _closeUploadSession(false /* failure */); _emitErrorMessage(tr("Write: Offset returned (%1) differs from offset requested (%2)").arg(writeAck->hdr.offset).arg(_writeOffset)); return; } if (writeAck->hdr.size != sizeof(uint32_t)) { - _currentOperation = kCOIdle; - _writeFileAccumulator.clear(); + _closeUploadSession(false /* failure */); _emitErrorMessage(tr("Write: Returned invalid size of write size data")); return; } - if( writeAck->writeFileLength !=_writeSize){ - _currentOperation = kCOIdle; - _writeFileAccumulator.clear(); + if( writeAck->writeFileLength !=_writeSize) { + _closeUploadSession(false /* failure */); _emitErrorMessage(tr("Write: Size returned (%1) differs from size requested (%2)").arg(writeAck->writeFileLength).arg(_writeSize)); return; } @@ -266,12 +287,8 @@ void FileManager::_writeAckResponse(Request* writeAck) /// @brief Send next write file data block. void FileManager::_writeFileDatablock(void) { - /// @brief Maximum data size in RequestHeader::data -// static const uint8_t kMaxDataLength = MAVLINK_MSG_FILE_TRANSFER_PROTOCOL_FIELD_PAYLOAD_LEN - sizeof(RequestHeader); -// static const uint8_t kMaxDataLength = Request.data; - - if(_writeOffset + _writeSize >= _writeFileSize){ - _sendTerminateCommand(); + if (_writeOffset + _writeSize >= _writeFileSize){ + _closeUploadSession(true /* success */); return; } @@ -373,15 +390,13 @@ void FileManager::receiveMessage(LinkInterface* link, mavlink_message_t message) if (request->hdr.req_opcode == kCmdListDirectory && errorCode == kErrEOF) { // This is not an error, just the end of the list loop - emit listComplete(); + emit commandComplete(); return; } else if ((request->hdr.req_opcode == kCmdReadFile || request->hdr.req_opcode == kCmdBurstReadFile) && errorCode == kErrEOF) { // This is not an error, just the end of the download loop _closeDownloadSession(true /* success */); return; } else if (request->hdr.req_opcode == kCmdCreateFile) { - // End a failed create file operation - _sendTerminateCommand(); _emitErrorMessage(tr("Nak received creating file, error: %1").arg(errorString(request->data[0]))); return; } else { @@ -389,6 +404,9 @@ void FileManager::receiveMessage(LinkInterface* link, mavlink_message_t message) if (request->hdr.req_opcode == kCmdReadFile || request->hdr.req_opcode == kCmdBurstReadFile) { // Nak error during download loop, download failed _closeDownloadSession(false /* failure */); + } else if (request->hdr.req_opcode == kCmdWriteFile) { + // Nak error during upload loop, upload failed + _closeUploadSession(false /* failure */); } _emitErrorMessage(tr("Nak received, error: %1").arg(errorString(request->data[0]))); } @@ -468,7 +486,7 @@ void FileManager::_downloadWorker(const QString& from, const QDir& downloadDir, i++; // move past slash _readFileDownloadFilename = from.right(from.size() - i); - _currentOperation = readFile ? kCOOpenRead : kCOOpenStream; + _currentOperation = readFile ? kCOOpenRead : kCOOpenBurst; Request request; request.hdr.session = 0; @@ -493,8 +511,9 @@ void FileManager::uploadPath(const QString& toPath, const QFileInfo& uploadFile) return; } - if(!uploadFile.isReadable()){ + if (!uploadFile.isReadable()){ _emitErrorMessage(tr("File (%1) is not readable for upload").arg(uploadFile.path())); + return; } QFile file(uploadFile.absoluteFilePath()); @@ -607,35 +626,38 @@ void FileManager::_ackTimeout(void) case kCORead: case kCOBurst: _closeDownloadSession(false /* failure */); - _currentOperation = kCOAck; - _emitErrorMessage(tr("Timeout waiting for ack: Sending Terminate command")); + _emitErrorMessage(tr("Timeout waiting for ack: Download failed")); + break; + + case kCOOpenRead: + case kCOOpenBurst: + _currentOperation = kCOIdle; + _emitErrorMessage(tr("Timeout waiting for ack: Download failed")); + _sendResetCommand(); break; case kCOCreate: - _currentOperation = kCOAck; - _writeFileAccumulator.clear(); - _emitErrorMessage(tr("Timeout waiting for ack: Sending Terminate command")); - _sendTerminateCommand(); + _currentOperation = kCOIdle; + _emitErrorMessage(tr("Timeout waiting for ack: Upload failed")); + _sendResetCommand(); break; case kCOWrite: - _currentOperation = kCOAck; - _writeFileAccumulator.clear(); - _emitErrorMessage(tr("Timeout waiting for ack: Sending Terminate command")); + _closeUploadSession(false /* failure */); + _emitErrorMessage(tr("Timeout waiting for ack: Upload failed")); break; default: _currentOperation = kCOIdle; - _emitErrorMessage(QString("Timeout waiting for ack: operation (%1)").arg(_currentOperation)); + _emitErrorMessage(QString("Timeout waiting for ack: Command failed (%1)").arg(_currentOperation)); break; } } -void FileManager::_sendTerminateCommand(void) +void FileManager::_sendResetCommand(void) { Request request; - request.hdr.session = _activeSession; - request.hdr.opcode = kCmdTerminateSession; + request.hdr.opcode = kCmdResetSessions; request.hdr.size = 0; _sendRequest(&request); } @@ -643,7 +665,7 @@ void FileManager::_sendTerminateCommand(void) void FileManager::_emitErrorMessage(const QString& msg) { qCDebug(FileManagerLog) << "Error:" << msg; - emit errorMessage(msg); + emit commandError(msg); } void FileManager::_emitListEntry(const QString& entry) diff --git a/src/uas/FileManager.h b/src/uas/FileManager.h index 7ab02842b53244d317a2e41c135fddc378732be1..62518ca89d7f5e00f40b89a9808b02678c160333 100644 --- a/src/uas/FileManager.h +++ b/src/uas/FileManager.h @@ -35,6 +35,7 @@ Q_DECLARE_LOGGING_CATEGORY(FileManagerLog) class FileManager : public QObject { Q_OBJECT + public: FileManager(QObject* parent, UASInterface* uas, uint8_t unitTestSystemIdQGC = 0); @@ -65,38 +66,23 @@ public: void uploadPath(const QString& toPath, const QFileInfo& uploadFile); signals: - /// @brief Signalled whenever an error occurs during the listDirectory or downloadPath methods. - void errorMessage(const QString& msg); - // Signals associated with the listDirectory method - /// @brief Signalled to indicate a new directory entry was received. + /// Signalled to indicate a new directory entry was received. void listEntry(const QString& entry); - /// @brief Signalled after listDirectory completes. If an error occurs during directory listing this signal will not be emitted. - void listComplete(void); + // Signals associated with all commands - // Signals associated with the downloadPath method + /// Signalled after a command has completed + void commandComplete(void); - /// @brief Signalled after downloadPath is called to indicate length of file being downloaded - void downloadFileLength(unsigned int length); + /// Signalled when an error occurs during a command. In this case a commandComplete signal will + /// not be sent. + void commandError(const QString& msg); - /// @brief Signalled during file download to indicate download progress - /// @param bytesReceived Number of bytes currently received from file - void downloadFileProgress(unsigned int bytesReceived); - - /// @brief Signaled to indicate completion of file download. If an error occurs during download this signal will not be emitted. - void downloadFileComplete(void); - - /// @brief Signalled after createFile acknowledge is returned to indicate length of file being downloaded - void uploadFileLength(unsigned int length); - - /// @brief Signalled during file upload to indicate progress - /// @param bytesReceived Number of bytes currently transmitted to file - void uploadFileProgress(unsigned int bytesReceived); - - /// @brief Signaled to indicate completion of file upload. If an error occurs during download this signal will not be emitted. - void uploadFileComplete(void); + /// Signalled during a lengthy command to show progress + /// @param value Amount of progress: 0.0 = none, 1.0 = complete + void commandProgress(int value); public slots: void receiveMessage(LinkInterface* link, mavlink_message_t message); @@ -184,7 +170,7 @@ private: kCOAck, // waiting for an Ack kCOList, // waiting for List response kCOOpenRead, // waiting for Open response followed by Read download - kCOOpenStream, // waiting for Open response, followed by Stream download + kCOOpenBurst, // waiting for Open response, followed by Burst download kCORead, // waiting for Read response kCOBurst, // waiting for Burst response kCOWrite, // waiting for Write response @@ -205,8 +191,9 @@ private: void _writeAckResponse(Request* writeAck); void _writeFileDatablock(void); void _sendListCommand(void); - void _sendTerminateCommand(void); + void _sendResetCommand(void); void _closeDownloadSession(bool success); + void _closeUploadSession(bool success); void _downloadWorker(const QString& from, const QDir& downloadDir, bool readFile); static QString errorString(uint8_t errorCode); @@ -222,15 +209,19 @@ private: QString _listPath; ///< path for the current List operation uint8_t _activeSession; ///< currently active session, 0 for none + uint32_t _readOffset; ///< current read offset + uint32_t _writeOffset; ///< current write offset uint32_t _writeSize; ///< current write data size - uint32_t _writeFileSize; ///< current write file size + uint32_t _writeFileSize; ///< Size of file being uploaded + QByteArray _writeFileAccumulator; ///< Holds file being uploaded + uint32_t _downloadOffset; ///< current download offset QByteArray _readFileAccumulator; ///< Holds file being downloaded - QByteArray _writeFileAccumulator; ///< Holds file being uploaded QDir _readFileDownloadDir; ///< Directory to download file to QString _readFileDownloadFilename; ///< Filename (no path) for download file + uint32_t _downloadFileSize; ///< Size of file being downloaded uint8_t _systemIdQGC; ///< System ID for QGC uint8_t _systemIdServer; ///< System ID for server diff --git a/src/ui/QGCUASFileView.cc b/src/ui/QGCUASFileView.cc index 5b80339790b07f6850590345abfbb9023e23b42a..9f2aeeb38a2a48e68f836cc0422b9b82d5c1081d 100644 --- a/src/ui/QGCUASFileView.cc +++ b/src/ui/QGCUASFileView.cc @@ -22,7 +22,7 @@ ======================================================================*/ #include "QGCUASFileView.h" -#include "uas/FileManager.h" +#include "FileManager.h" #include "QGCFileDialog.h" #include @@ -32,62 +32,64 @@ QGCUASFileView::QGCUASFileView(QWidget *parent, FileManager *manager) : QWidget(parent), _manager(manager), - _listInProgress(false), - _downloadInProgress(false), - _uploadInProgress(false) + _currentCommand(commandNone) { _ui.setupUi(this); - // Progress bar is only visible while a download is in progress - _ui.progressBar->setVisible(false); - - bool success; - Q_UNUSED(success); // Silence retail unused variable error + _ui.progressBar->reset(); // Connect UI signals - success = connect(_ui.listFilesButton, SIGNAL(clicked()), this, SLOT(_refreshTree())); - Q_ASSERT(success); - success = connect(_ui.downloadButton, SIGNAL(clicked()), this, SLOT(_downloadFile())); - Q_ASSERT(success); - success = connect(_ui.uploadButton, SIGNAL(clicked()), this, SLOT(_uploadFile())); - Q_ASSERT(success); - success = connect(_ui.treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(_currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); - Q_ASSERT(success); + connect(_ui.listFilesButton, &QPushButton::clicked, this, &QGCUASFileView::_refreshTree); + connect(_ui.downloadButton, &QPushButton::clicked, this, &QGCUASFileView::_downloadFile); + connect(_ui.uploadButton, &QPushButton::clicked, this, &QGCUASFileView::_uploadFile); + connect(_ui.treeWidget, &QTreeWidget::currentItemChanged, this, &QGCUASFileView::_currentItemChanged); + + // Connect signals from FileManager + connect(_manager, &FileManager::commandProgress, this, &QGCUASFileView::_commandProgress); + connect(_manager, &FileManager::commandComplete, this, &QGCUASFileView::_commandComplete); + connect(_manager, &FileManager::commandError, this, &QGCUASFileView::_commandError); + connect(_manager, &FileManager::listEntry, this, &QGCUASFileView::_listEntryReceived); } /// @brief Downloads the file currently selected in the tree view void QGCUASFileView::_downloadFile(void) { - Q_ASSERT(!_downloadInProgress); + if (_currentCommand != commandNone) { + qWarning() << QString("Download attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); + return; + } _ui.statusText->clear(); - QString downloadToHere = QGCFileDialog::getExistingDirectory(this, tr("Download Directory"), - QDir::homePath(), - QGCFileDialog::ShowDirsOnly - | QGCFileDialog::DontResolveSymlinks); + QString downloadToHere = QGCFileDialog::getExistingDirectory(this, + "Download Directory", + QDir::homePath(), + QGCFileDialog::ShowDirsOnly | QGCFileDialog::DontResolveSymlinks); // And now download to this location + QString path; + QString downloadFilename; + QTreeWidgetItem* item = _ui.treeWidget->currentItem(); if (item && item->type() == _typeFile) { - _downloadFilename.clear(); do { QString name = item->text(0).split("\t")[0]; // Strip off file sizes // If this is the file name and not a directory keep track of the download file name - if (_downloadFilename.isEmpty()) { - _downloadFilename = name; + if (downloadFilename.isEmpty()) { + downloadFilename = name; } path.prepend("/" + name); item = item->parent(); } while (item); - _ui.downloadButton->setEnabled(false); - _downloadInProgress = true; - _connectDownloadSignals(); + _setAllButtonsEnabled(false); + _currentCommand = commandDownload; + _ui.statusText->setText(QString("Downloading: %1").arg(downloadFilename)); + _manager->streamPath(path, QDir(downloadToHere)); } } @@ -95,7 +97,10 @@ void QGCUASFileView::_downloadFile(void) /// @brief uploads a file into the currently selected directory the tree view void QGCUASFileView::_uploadFile(void) { - Q_ASSERT(!_uploadInProgress); + if (_currentCommand != commandNone) { + qWarning() << QString("Upload attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); + return; + } _ui.statusText->clear(); @@ -113,83 +118,41 @@ void QGCUASFileView::_uploadFile(void) item = item->parent(); } while (item); - QString uploadFromHere = QGCFileDialog::getOpenFileName(this, tr("Upload File"), - QDir::homePath()); + QString uploadFromHere = QGCFileDialog::getOpenFileName(this, "Upload File", QDir::homePath()); + _ui.statusText->setText(QString("Uploading: %1").arg(uploadFromHere)); + qDebug() << "Upload: " << uploadFromHere << "to path" << path; + + _setAllButtonsEnabled(false); + _currentCommand = commandUpload; _manager->uploadPath(path, uploadFromHere); } - -/// @brief Called when length of file being downloaded is known. -void QGCUASFileView::_downloadLength(unsigned int length) -{ - Q_ASSERT(_downloadInProgress); - - // Setup the progress bar - QProgressBar* bar = _ui.progressBar; - bar->setMinimum(0); - bar->setMaximum(length); - bar->setValue(0); - bar->setVisible(true); - - _ui.downloadButton->setEnabled(true); - _downloadStartTime.start(); - - _ui.statusText->setText(tr("Downloading: %1").arg(_downloadFilename)); -} - /// @brief Called to update the progress of the download. -/// @param bytesReceived Current count of bytes received for current download -void QGCUASFileView::_downloadProgress(unsigned int bytesReceived) -{ - static uint lastSecsReported = 0; - - Q_ASSERT(_downloadInProgress); - - _ui.progressBar->setValue(bytesReceived); - - // Calculate and display download rate. Only update once per second. - uint kbReceived = bytesReceived / 1024; - uint secs = _downloadStartTime.elapsed() / 1000; - if (secs != 0) { - uint kbPerSec = kbReceived / secs; - if (kbPerSec != 0 && secs != lastSecsReported) { - lastSecsReported = secs; - _ui.statusText->setText(tr("Downloading: %1 %2 KB/sec").arg(_downloadFilename).arg(kbPerSec)); - } - } -} - -/// @brief Called when the download associated with the FileManager::downloadPath command completes. -void QGCUASFileView::_downloadComplete(void) +/// @param value Progress bar value +void QGCUASFileView::_commandProgress(int value) { - Q_ASSERT(_downloadInProgress); - _ui.downloadButton->setEnabled(true); - _ui.progressBar->setVisible(false); - _downloadInProgress = false; - _disconnectDownloadSignals(); - _ui.statusText->setText(tr("Download complete: %1").arg(_downloadFilename)); + _ui.progressBar->setValue(value); } /// @brief Called when an error occurs during a download. /// @param msg Error message -void QGCUASFileView::_downloadErrorMessage(const QString& msg) +void QGCUASFileView::_commandError(const QString& msg) { - if (_downloadInProgress) { - _ui.downloadButton->setEnabled(true); - _ui.progressBar->setVisible(false); - _downloadInProgress = false; - _disconnectDownloadSignals(); - _ui.statusText->setText(tr("Error: ") + msg); - } + _setAllButtonsEnabled(true); + _currentCommand = commandNone; + _ui.statusText->setText(QString("Error: %1").arg(msg)); } /// @brief Refreshes the directory list tree. void QGCUASFileView::_refreshTree(void) { - Q_ASSERT(!_listInProgress); + if (_currentCommand != commandNone) { + qWarning() << QString("List attempted while another command was in progress: _currentCommand(%1)").arg(_currentCommand); + return; + } _ui.treeWidget->clear(); _ui.statusText->clear(); @@ -199,10 +162,8 @@ void QGCUASFileView::_refreshTree(void) _walkIndexStack.append(0); _walkItemStack.append(_ui.treeWidget->invisibleRootItem()); - // Don't queue up more than once - _ui.listFilesButton->setEnabled(false); - _listInProgress = true; - _connectListSignals(); + _setAllButtonsEnabled(false); + _currentCommand = commandList; _requestDirectoryList("/"); } @@ -210,7 +171,10 @@ void QGCUASFileView::_refreshTree(void) /// @brief Adds the specified directory entry to the tree view. void QGCUASFileView::_listEntryReceived(const QString& entry) { - Q_ASSERT(_listInProgress); + if (_currentCommand != commandList) { + qWarning() << QString("List entry received while no list command in progress: _currentCommand(%1)").arg(_currentCommand); + return; + } int type; if (entry.startsWith("F")) { @@ -232,22 +196,29 @@ void QGCUASFileView::_listEntryReceived(const QString& entry) item->setText(0, entry.right(entry.size() - 1)); } -/// @brief Called when an error occurs during a directory listing. -/// @param msg Error message -void QGCUASFileView::_listErrorMessage(const QString& msg) +/// @brief Called when a command completes successfully +void QGCUASFileView::_commandComplete(void) { - if (_listInProgress) { - _ui.listFilesButton->setEnabled(true); - _listInProgress = false; - _disconnectListSignals(); - _ui.statusText->setText(tr("Error: ") + msg); + QString statusText; + + if (_currentCommand == commandDownload) { + _currentCommand = commandNone; + _setAllButtonsEnabled(true); + statusText = "Download complete"; + } else if (_currentCommand == commandDownload) { + _currentCommand = commandNone; + _setAllButtonsEnabled(true); + statusText = "Upload complete"; + } else if (_currentCommand == commandList) { + _listComplete(); } + + _ui.statusText->setText(statusText); + _ui.progressBar->reset(); } void QGCUASFileView::_listComplete(void) { - Q_ASSERT(_listInProgress); - // Walk the current items, traversing down into directories Again: @@ -287,9 +258,8 @@ Again: if (_walkIndexStack.count() != 0) { goto Again; } else { - _ui.listFilesButton->setEnabled(true); - _listInProgress = false; - _disconnectListSignals(); + _setAllButtonsEnabled(true); + _currentCommand = commandNone; } } } @@ -297,7 +267,7 @@ Again: void QGCUASFileView::_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) { Q_UNUSED(previous); - // FIXME: Should not enable when downloading + _ui.downloadButton->setEnabled(current ? (current->type() == _typeFile) : false); _ui.uploadButton->setEnabled(current ? (current->type() == _typeDir) : false); } @@ -307,51 +277,14 @@ void QGCUASFileView::_requestDirectoryList(const QString& dir) _manager->listDirectory(dir); } -/// @brief Connects to the signals associated with the FileManager::downloadPath method. We only leave these signals connected -/// while a download because there may be multiple UAS, which in turn means multiple QGCUASFileView instances. We only want the signals -/// connected to the active FileView which is doing the current download. -void QGCUASFileView::_connectDownloadSignals(void) +void QGCUASFileView::_setAllButtonsEnabled(bool enabled) { - bool success; - Q_UNUSED(success); // Silence retail unused variable error - - success = connect(_manager, SIGNAL(downloadFileLength(unsigned int)), this, SLOT(_downloadLength(unsigned int))); - Q_ASSERT(success); - success = connect(_manager, SIGNAL(downloadFileProgress(unsigned int)), this, SLOT(_downloadProgress(unsigned int))); - Q_ASSERT(success); - success = connect(_manager, SIGNAL(downloadFileComplete(void)), this, SLOT(_downloadComplete(void))); - Q_ASSERT(success); - success = connect(_manager, SIGNAL(errorMessage(const QString&)), this, SLOT(_downloadErrorMessage(const QString&))); - Q_ASSERT(success); -} - -void QGCUASFileView::_disconnectDownloadSignals(void) -{ - disconnect(_manager, SIGNAL(downloadFileLength(unsigned int)), this, SLOT(_downloadLength(unsigned int))); - disconnect(_manager, SIGNAL(downloadFileProgress(unsigned int)), this, SLOT(_downloadProgress(unsigned int))); - disconnect(_manager, SIGNAL(downloadFileComplete(void)), this, SLOT(_downloadComplete(void))); - disconnect(_manager, SIGNAL(errorMessage(const QString&)), this, SLOT(_downloadErrorMessage(const QString&))); -} - -/// @brief Connects to the signals associated with the FileManager::listDirectory method. We only leave these signals connected -/// while a download because there may be multiple UAS, which in turn means multiple QGCUASFileView instances. We only want the signals -/// connected to the active FileView which is doing the current download. -void QGCUASFileView::_connectListSignals(void) -{ - bool success; - Q_UNUSED(success); // Silence retail unused variable error + _ui.treeWidget->setEnabled(enabled); + _ui.downloadButton->setEnabled(enabled); + _ui.listFilesButton->setEnabled(enabled); + _ui.uploadButton->setEnabled(enabled); - success = connect(_manager, SIGNAL(listEntry(const QString&)), this, SLOT(_listEntryReceived(const QString&))); - Q_ASSERT(success); - success = connect(_manager, SIGNAL(listComplete(void)), this, SLOT(_listComplete(void))); - Q_ASSERT(success); - success = connect(_manager, SIGNAL(errorMessage(const QString&)), this, SLOT(_listErrorMessage(const QString&))); - Q_ASSERT(success); -} - -void QGCUASFileView::_disconnectListSignals(void) -{ - disconnect(_manager, SIGNAL(listEntry(const QString&)), this, SLOT(_listEntryReceived(const QString&))); - disconnect(_manager, SIGNAL(listComplete(void)), this, SLOT(_listComplete(void))); - disconnect(_manager, SIGNAL(errorMessage(const QString&)), this, SLOT(_listErrorMessage(const QString&))); + if (enabled) { + _currentItemChanged(_ui.treeWidget->currentItem(), NULL); + } } diff --git a/src/ui/QGCUASFileView.h b/src/ui/QGCUASFileView.h index b7a1a9d53fa649c82722e9cacf220a0f94df73cd..f0a58c3e531dfc9359892e40bcbee29a71a9036d 100644 --- a/src/ui/QGCUASFileView.h +++ b/src/ui/QGCUASFileView.h @@ -41,26 +41,22 @@ protected: FileManager* _manager; private slots: - void _refreshTree(void); void _listEntryReceived(const QString& entry); - void _listErrorMessage(const QString& msg); - void _listComplete(void); + void _refreshTree(void); void _downloadFile(void); void _uploadFile(void); - void _downloadLength(unsigned int length); - void _downloadProgress(unsigned int length); - void _downloadErrorMessage(const QString& msg); - void _downloadComplete(void); + + void _commandProgress(int value); + void _commandError(const QString& msg); + void _commandComplete(void); void _currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); private: - void _connectDownloadSignals(void); - void _disconnectDownloadSignals(void); - void _connectListSignals(void); - void _disconnectListSignals(void); + void _listComplete(void); void _requestDirectoryList(const QString& dir); + void _setAllButtonsEnabled(bool enabled); static const int _typeFile = QTreeWidgetItem::UserType + 1; static const int _typeDir = QTreeWidgetItem::UserType + 2; @@ -70,12 +66,14 @@ private: QList _walkItemStack; Ui::QGCUASFileView _ui; - QString _downloadFilename; ///< File currently being downloaded, not including path - QTime _downloadStartTime; ///< Time at which download started + enum CommandState { + commandNone, ///< No command active + commandList, ///< List command active + commandDownload, ///< Download command active + commandUpload ///< Upload command active + }; - bool _listInProgress; ///< Indicates that a listDirectory command is in progress - bool _downloadInProgress; ///< Indicates that a downloadPath command is in progress - bool _uploadInProgress; ///< Indicates that a upload command is in progress + CommandState _currentCommand; ///< Current active command }; #endif // QGCUASFILEVIEW_H