Commit 5e36ee5f authored by Don Gagne's avatar Don Gagne

Cleanup FileManager

- Download working again
- Fixed lots of bad error handling
parent 2e3088b8
......@@ -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;
......
......@@ -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)
......
......@@ -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
......
......@@ -22,7 +22,7 @@
======================================================================*/
#include "QGCUASFileView.h"
#include "uas/FileManager.h"
#include "FileManager.h"
#include "QGCFileDialog.h"
#include <QFileDialog>
......@@ -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);
}
}
......@@ -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<QTreeWidgetItem*> _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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment