Commit 989cdcd0 authored by Lorenz Meier's avatar Lorenz Meier

Merge pull request #818 from DonLakeFlyer/FTPProgressBar

FTP progress bar and download speed
parents 0cda5053 5868dbc1
......@@ -59,15 +59,17 @@ void QGCUASFileManagerUnitTest::init(void)
Q_ASSERT(connected);
Q_UNUSED(connected); // Silent release build compiler warning
connected = connect(_fileManager, SIGNAL(statusMessage(const QString&)), this, SLOT(statusMessage(const QString&)));
connected = connect(_fileManager, SIGNAL(listEntry(const QString&)), this, SLOT(listEntry(const QString&)));
Q_ASSERT(connected);
_rgSignals[statusMessageSignalIndex] = SIGNAL(statusMessage(const QString&));
_rgSignals[errorMessageSignalIndex] = SIGNAL(errorMessage(const QString&));
_rgSignals[resetStatusMessagesSignalIndex] = SIGNAL(resetStatusMessages(void));
_rgSignals[listEntrySignalIndex] = SIGNAL(listEntry(const QString&));
_rgSignals[listCompleteSignalIndex] = SIGNAL(listComplete(void));
_rgSignals[openFileLengthSignalIndex] = SIGNAL(openFileLength(unsigned int));
_rgSignals[downloadFileLengthSignalIndex] = SIGNAL(downloadFileLength(unsigned int));
_rgSignals[downloadFileCompleteSignalIndex] = SIGNAL(downloadFileComplete(void));
_rgSignals[errorMessageSignalIndex] = SIGNAL(errorMessage(const QString&));
_multiSpy = new MultiSignalSpy();
Q_CHECK_PTR(_multiSpy);
QCOMPARE(_multiSpy->init(_fileManager, _rgSignals, _cSignals), true);
......@@ -86,11 +88,11 @@ void QGCUASFileManagerUnitTest::cleanup(void)
_multiSpy = NULL;
}
/// @brief Connected to QGCUASFileManager statusMessage signal in order to catch list command output
void QGCUASFileManagerUnitTest::statusMessage(const QString& msg)
/// @brief Connected to QGCUASFileManager listEntry signal in order to catch list entries
void QGCUASFileManagerUnitTest::listEntry(const QString& entry)
{
// Keep a list of all names received so we can test it for correctness
_fileListReceived += msg;
_fileListReceived += entry;
}
......@@ -151,14 +153,13 @@ void QGCUASFileManagerUnitTest::_listTest(void)
Q_ASSERT(_multiSpy->checkNoSignals() == true);
// QGCUASFileManager::listDirectory signalling as follows:
// Emits the resetStatusMessages signal
// Emits a statusMessage signal for each list entry
// Emits a listEntry signal for each list entry
// Emits an errorMessage signal if:
// It gets a Nak back
// Sequence number is incorrrect on any response
// CRC is incorrect on any responses
// List entry is formatted incorrectly
// It is possible to get a number of good statusMessage signals, followed by an errorMessage signal
// It is possible to get a number of good listEntry signals, followed by an errorMessage signal
// Emits listComplete after it receives the final list entry
// If an errorMessage signal is signalled no listComplete is signalled
......@@ -166,7 +167,7 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// We should get a single resetStatusMessages signal
// We should get a single errorMessage signal
_fileManager->listDirectory("/bogus");
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask | resetStatusMessagesSignalMask), true);
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true);
_multiSpy->clearAllSignals();
// Setup the mock file server with a valid directory list
......@@ -187,15 +188,15 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// For simulated server errors on subsequent Acks, the first Ack will go through. This means we should have gotten some
// partial results. In the case of the directory list test set, all entries fit into the first ack, so we should have
// gotten back all of them.
QCOMPARE(_multiSpy->getSpyByIndex(statusMessageSignalIndex)->count(), fileList.count());
_multiSpy->clearSignalByIndex(statusMessageSignalIndex);
QCOMPARE(_multiSpy->getSpyByIndex(listEntrySignalIndex)->count(), fileList.count());
_multiSpy->clearSignalByIndex(listEntrySignalIndex);
// And then it should have errored out because the next list Request would have failed.
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask | resetStatusMessagesSignalMask), true);
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true);
} else {
// For the simulated errors which failed the intial response we should not have gotten any results back at all.
// Just an error.
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask | resetStatusMessagesSignalMask), true);
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true);
}
// Set everything back to initial state
......@@ -206,9 +207,9 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// Send a list command at the root of the directory tree which should succeed
_fileManager->listDirectory("/");
QCOMPARE(_multiSpy->checkSignalByMask(resetStatusMessagesSignalMask | listCompleteSignalMask), true);
QCOMPARE(_multiSpy->checkSignalByMask(listCompleteSignalMask), true);
QCOMPARE(_multiSpy->checkNoSignalByMask(errorMessageSignalMask), true);
QCOMPARE(_multiSpy->getSpyByIndex(statusMessageSignalIndex)->count(), fileList.count());
QCOMPARE(_multiSpy->getSpyByIndex(listEntrySignalIndex)->count(), fileList.count());
QVERIFY(_fileListReceived == fileList);
}
......@@ -238,26 +239,26 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
Q_ASSERT(_multiSpy->checkNoSignals() == true);
// QGCUASFileManager::downloadPath works as follows:
// Emits the resetStatusMessages signal
// Sends an Open Command to the server
// Expects an Ack Response back from the server with the correct sequence numner
// Emits an errorMessage signal if it gets a Nak back
// Emits an openFileLength signal with the file length if it gets back a good Ack
// Emits an downloadFileLength signal with the file length if it gets back a good Ack
// Sends subsequent Read commands to the server until it gets the full file contents back
// Emits a downloadFileProgress for each read command ack it gets back
// Sends Terminate command to server when download is complete to close Open command
// Mock file server will signal terminateCommandReceived when it gets a Terminate command
// Sends statusMessage signal to indicate the download is complete
// Sends downloadFileComplete signal to indicate the download is complete
// Emits an errorMessage signal if sequence number is incorrrect on any response
// Emits an errorMessage signal if CRC is incorrect on any responses
// Expected signals if the Open command fails for any reason
quint16 signalMaskOpenFailure = resetStatusMessagesSignalMask | errorMessageSignalMask;
quint16 signalMaskOpenFailure = errorMessageSignalMask;
// Expected signals if the Read command fails for any reason
quint16 signalMaskReadFailure = resetStatusMessagesSignalMask | openFileLengthSignalMask | errorMessageSignalMask;
quint16 signalMaskReadFailure = downloadFileLengthSignalMask | errorMessageSignalMask;
// Expected signals if the downloadPath command succeeds
quint16 signalMaskDownloadSuccess = resetStatusMessagesSignalMask | openFileLengthSignalMask | statusMessageSignalMask;
quint16 signalMaskDownloadSuccess = downloadFileLengthSignalMask | downloadFileCompleteSignalMask;
// Send a bogus path
// We should get a single resetStatusMessages signal
......@@ -296,7 +297,8 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
// For simulated server errors on subsequent Acks, the first Ack will go through. We must handle things differently depending
// on whether the downloaded file requires multiple packets to complete the download.
if (testCase->fMultiPacketResponse) {
// The downloaded file requires multiple Acks to complete. Hence second Read should have failed.
// The downloaded file requires multiple Acks to complete. Hence first Read should have succeeded and sent one downloadFileComplete.
// Second Read should have failed.
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskReadFailure), true);
// Open command succeeded, so we should get a Terminate for the open
......@@ -333,7 +335,7 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskDownloadSuccess), true);
// Make sure the file length coming back through the openFileLength signal is correct
QVERIFY(_multiSpy->getSpyByIndex(openFileLengthSignalIndex)->takeFirst().at(0).toInt() == testCase->length);
QVERIFY(_multiSpy->getSpyByIndex(downloadFileLengthSignalIndex)->takeFirst().at(0).toInt() == testCase->length);
_multiSpy->clearAllSignals();
......
......@@ -58,29 +58,28 @@ private slots:
void _listTest(void);
void _downloadTest(void);
// Connected to QGCUASFileManager statusMessage signal
void statusMessage(const QString&);
// Connected to QGCUASFileManager listEntry signal
void listEntry(const QString& entry);
private:
void _validateFileContents(const QString& filePath, uint8_t length);
enum {
statusMessageSignalIndex = 0,
errorMessageSignalIndex,
resetStatusMessagesSignalIndex,
listEntrySignalIndex = 0,
listCompleteSignalIndex,
openFileLengthSignalIndex,
downloadFileLengthSignalIndex,
downloadFileCompleteSignalIndex,
errorMessageSignalIndex,
maxSignalIndex
};
enum {
statusMessageSignalMask = 1 << statusMessageSignalIndex,
errorMessageSignalMask = 1 << errorMessageSignalIndex,
resetStatusMessagesSignalMask = 1 << resetStatusMessagesSignalIndex,
listEntrySignalMask = 1 << listEntrySignalIndex,
listCompleteSignalMask = 1 << listCompleteSignalIndex,
openFileLengthSignalMask = 1 << openFileLengthSignalIndex,
downloadFileLengthSignalMask = 1 << downloadFileLengthSignalIndex,
downloadFileCompleteSignalMask = 1 << downloadFileCompleteSignalIndex,
errorMessageSignalMask = 1 << errorMessageSignalIndex,
};
MockUAS _mockUAS;
MockMavlinkFileServer _mockFileServer;
......
......@@ -107,7 +107,9 @@ void QGCUASFileManager::_openAckResponse(Request* openAck)
// File length comes back in data
Q_ASSERT(openAck->hdr.size == sizeof(uint32_t));
emit openFileLength(openAck->openFileLength);
emit downloadFileLength(openAck->openFileLength);
// Start the sequence of read commands
_readOffset = 0; // Start reading at beginning of file
_readFileAccumulator.clear(); // Start with an empty file
......@@ -142,7 +144,7 @@ void QGCUASFileManager::_closeReadSession(bool success)
}
file.close();
_emitStatusMessage(tr("Download complete '%1'").arg(downloadFilePath));
emit downloadFileComplete();
}
// Close the open session
......@@ -167,6 +169,7 @@ void QGCUASFileManager::_readAckResponse(Request* readAck)
}
_readFileAccumulator.append((const char*)readAck->data, readAck->hdr.size);
emit downloadFileProgress(_readFileAccumulator.length());
if (readAck->hdr.size == sizeof(readAck->data)) {
// Possibly still more data to read, send next read request
......@@ -221,7 +224,9 @@ void QGCUASFileManager::_listAckResponse(Request* listAck)
// Returned names are prepended with D for directory, F for file, U for unknown
if (*ptr == 'F' || *ptr == 'D') {
// put it in the view
_emitStatusMessage(ptr);
_emitListEntry(ptr);
} else {
qDebug() << "unknown entry" << ptr;
}
// account for the name + NUL
......@@ -357,9 +362,6 @@ void QGCUASFileManager::listDirectory(const QString& dirPath)
return;
}
// clear the text widget
emit resetStatusMessages();
// initialise the lister
_listPath = dirPath;
_listOffset = 0;
......@@ -411,8 +413,6 @@ void QGCUASFileManager::downloadPath(const QString& from, const QDir& downloadDi
i++; // move past slash
_readFileDownloadFilename = from.right(from.size() - i);
emit resetStatusMessages();
_currentOperation = kCOOpen;
Request request;
......@@ -532,10 +532,10 @@ void QGCUASFileManager::_emitErrorMessage(const QString& msg)
emit errorMessage(msg);
}
void QGCUASFileManager::_emitStatusMessage(const QString& msg)
void QGCUASFileManager::_emitListEntry(const QString& entry)
{
qDebug() << "QGCUASFileManager: Status" << msg;
emit statusMessage(msg);
qDebug() << "QGCUASFileManager: list entry" << entry;
emit listEntry(entry);
}
/// @brief Sends the specified Request out to the UAS.
......
......@@ -45,11 +45,28 @@ public:
static const int ackTimerTimeoutMsecs = 1000;
signals:
void statusMessage(const QString& msg);
void resetStatusMessages();
/// @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.
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);
void openFileLength(unsigned int length);
// Signals associated with the downloadPath method
/// @brief Signalled after downloadPath is called to indicate length of file being downloaded
void downloadFileLength(unsigned int length);
/// @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);
public slots:
void receiveMessage(LinkInterface* link, mavlink_message_t message);
......@@ -140,7 +157,7 @@ protected:
void _setupAckTimeout(void);
void _clearAckTimeout(void);
void _emitErrorMessage(const QString& msg);
void _emitStatusMessage(const QString& msg);
void _emitListEntry(const QString& entry);
void _sendRequest(Request* request);
void _fillRequestWithString(Request* request, const QString& str);
void _openAckResponse(Request* openAck);
......
......@@ -30,108 +30,191 @@
QGCUASFileView::QGCUASFileView(QWidget *parent, QGCUASFileManager *manager) :
QWidget(parent),
_manager(manager)
_manager(manager),
_listInProgress(false),
_downloadInProgress(false)
{
_ui.setupUi(this);
// Progress bar is only visible while a download is in progress
_ui.progressBar->setVisible(false);
bool success = connect(_ui.listFilesButton, SIGNAL(clicked()), this, SLOT(_refreshTree()));
bool success;
Q_UNUSED(success); // Silence retail unused variable error
// Connect UI signals
success = connect(_ui.listFilesButton, SIGNAL(clicked()), this, SLOT(_refreshTree()));
Q_ASSERT(success);
success = connect(_ui.downloadButton, SIGNAL(clicked()), this, SLOT(_downloadFiles()));
success = connect(_ui.downloadButton, SIGNAL(clicked()), this, SLOT(_downloadFile()));
Q_ASSERT(success);
success = connect(_ui.treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(_currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
Q_ASSERT(success);
success = connect(&_listCompleteTimer, SIGNAL(timeout()), this, SLOT(_listCompleteTimeout()));
Q_ASSERT(success);
Q_UNUSED(success); // Silence retail unused variable error
}
void QGCUASFileView::_downloadFiles(void)
/// @brief Downloads the file currently selected in the tree view
void QGCUASFileView::_downloadFile(void)
{
QString dir = QFileDialog::getExistingDirectory(this, tr("Download Directory"),
QDir::homePath(),
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
Q_ASSERT(!_downloadInProgress);
_ui.statusText->clear();
QString downloadToHere = QFileDialog::getExistingDirectory(this, tr("Download Directory"),
QDir::homePath(),
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
// And now download to this location
QString path;
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;
}
path.prepend("/" + name);
item = item->parent();
} while (item);
qDebug() << "Download: " << path;
bool success = connect(_manager, SIGNAL(statusMessage(QString)), this, SLOT(_downloadStatusMessage(QString)));
Q_ASSERT(success);
success = connect(_manager, SIGNAL(errorMessage(QString)), this, SLOT(_downloadStatusMessage(QString)));
Q_ASSERT(success);
Q_UNUSED(success);
_manager->downloadPath(path, QDir(dir));
_ui.downloadButton->setEnabled(false);
_downloadInProgress = true;
_connectDownloadSignals();
_manager->downloadPath(path, QDir(downloadToHere));
}
}
/// @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 QGCUASFileManager::downloadPath command completes.
void QGCUASFileView::_downloadComplete(void)
{
Q_ASSERT(_downloadInProgress);
_ui.downloadButton->setEnabled(true);
_ui.progressBar->setVisible(false);
_downloadInProgress = false;
_disconnectDownloadSignals();
_ui.statusText->setText(tr("Download complete: %1").arg(_downloadFilename));
}
/// @brief Called when an error occurs during a download.
/// @param msg Error message
void QGCUASFileView::_downloadErrorMessage(const QString& msg)
{
if (_downloadInProgress) {
_ui.downloadButton->setEnabled(true);
_ui.progressBar->setVisible(false);
_downloadInProgress = false;
_disconnectDownloadSignals();
_ui.statusText->setText(tr("Error: ") + msg);
}
}
/// @brief Refreshes the directory list tree.
void QGCUASFileView::_refreshTree(void)
{
Q_ASSERT(!_listInProgress);
_ui.treeWidget->clear();
_ui.statusText->clear();
_walkIndexStack.clear();
_walkItemStack.clear();
_walkIndexStack.append(0);
_walkItemStack.append(_ui.treeWidget->invisibleRootItem());
bool success = connect(_manager, SIGNAL(statusMessage(QString)), this, SLOT(_treeStatusMessage(QString)));
Q_ASSERT(success);
success = connect(_manager, SIGNAL(errorMessage(QString)), this, SLOT(_treeErrorMessage(QString)));
Q_ASSERT(success);
success = connect(_manager, SIGNAL(listComplete(void)), this, SLOT(_listComplete(void)));
Q_ASSERT(success);
Q_UNUSED(success);
// Don't queue up more than once
_ui.listFilesButton->setEnabled(false);
_listInProgress = true;
_connectListSignals();
_requestDirectoryList("/");
}
void QGCUASFileView::_treeStatusMessage(const QString& msg)
/// @brief Adds the specified directory entry to the tree view.
void QGCUASFileView::_listEntryReceived(const QString& entry)
{
Q_ASSERT(_listInProgress);
int type;
if (msg.startsWith("F")) {
if (entry.startsWith("F")) {
type = _typeFile;
} else if (msg.startsWith("D")) {
} else if (entry.startsWith("D")) {
type = _typeDir;
if (msg == "D." || msg == "D..") {
if (entry == "D." || entry == "D..") {
return;
}
} else {
Q_ASSERT(false);
return; // Silence maybe-unitialized on type below
return; // Silence maybe-unitialized on type
}
QTreeWidgetItem* item;
item = new QTreeWidgetItem(_walkItemStack.last(), type);
Q_CHECK_PTR(item);
item->setText(0, msg.right(msg.size() - 1));
item->setText(0, entry.right(entry.size() - 1));
}
void QGCUASFileView::_treeErrorMessage(const QString& msg)
/// @brief Called when an error occurs during a directory listing.
/// @param msg Error message
void QGCUASFileView::_listErrorMessage(const QString& msg)
{
QTreeWidgetItem* item;
item = new QTreeWidgetItem(_walkItemStack.last(), _typeError);
Q_CHECK_PTR(item);
item->setText(0, tr("Error: ") + msg);
// Fake listComplete signal after an error
_listComplete();
if (_listInProgress) {
_ui.listFilesButton->setEnabled(true);
_listInProgress = false;
_disconnectListSignals();
_ui.statusText->setText(tr("Error: ") + msg);
}
}
void QGCUASFileView::_listComplete(void)
{
_clearListCompleteTimeout();
Q_ASSERT(_listInProgress);
// Walk the current items, traversing down into directories
Again:
......@@ -171,54 +254,71 @@ Again:
if (_walkIndexStack.count() != 0) {
goto Again;
} else {
disconnect(_manager, SIGNAL(statusMessage(QString)), this, SLOT(_treeStatusMessage(QString)));
disconnect(_manager, SIGNAL(errorMessage(QString)), this, SLOT(_treeErrorMessage(QString)));
disconnect(_manager, SIGNAL(listComplete(void)), this, SLOT(_listComplete(void)));
_ui.listFilesButton->setEnabled(true);
_listInProgress = false;
_disconnectListSignals();
}
}
}
void QGCUASFileView::_downloadStatusMessage(const QString& msg)
{
disconnect(_manager, SIGNAL(statusMessage(QString)), this, SLOT(_downloadStatusMessage(QString)));
disconnect(_manager, SIGNAL(errorMessage(QString)), this, SLOT(_downloadStatusMessage(QString)));
QMessageBox msgBox;
msgBox.setWindowModality(Qt::ApplicationModal);
msgBox.setText(msg);
msgBox.exec();
}
void QGCUASFileView::_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
Q_UNUSED(previous);
// FIXME: Should not enable when downloading
_ui.downloadButton->setEnabled(current ? (current->type() == _typeFile) : false);
}
void QGCUASFileView::_setupListCompleteTimeout(void)
void QGCUASFileView::_requestDirectoryList(const QString& dir)
{
Q_ASSERT(!_listCompleteTimer.isActive());
_listCompleteTimer.setSingleShot(true);
_listCompleteTimer.start(_listCompleteTimerTimeoutMsecs);
qDebug() << "List:" << dir;
_manager->listDirectory(dir);
}
void QGCUASFileView::_clearListCompleteTimeout(void)
/// @brief Connects to the signals associated with the QGCUASFileManager::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)
{
Q_ASSERT(_listCompleteTimer.isActive());
_listCompleteTimer.stop();
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::_listCompleteTimeout(void)
void QGCUASFileView::_disconnectDownloadSignals(void)
{
_treeErrorMessage(tr("Timeout waiting for listComplete signal"));
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&)));
}
void QGCUASFileView::_requestDirectoryList(const QString& dir)
/// @brief Connects to the signals associated with the QGCUASFileManager::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)
{
qDebug() << "List:" << dir;
_setupListCompleteTimeout();
_manager->listDirectory(dir);
bool success;
Q_UNUSED(success); // Silence retail unused variable error
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&)));
}
......@@ -42,29 +42,38 @@ protected:
private slots:
void _refreshTree(void);
void _downloadFiles(void);
void _treeStatusMessage(const QString& msg);
void _treeErrorMessage(const QString& msg);
void _listEntryReceived(const QString& entry);
void _listErrorMessage(const QString& msg);
void _listComplete(void);
void _downloadStatusMessage(const QString& msg);
void _downloadFile(void);
void _downloadLength(unsigned int length);
void _downloadProgress(unsigned int length);
void _downloadErrorMessage(const QString& msg);
void _downloadComplete(void);
void _currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
void _listCompleteTimeout(void);
private:
void _setupListCompleteTimeout(void);
void _clearListCompleteTimeout(void);
void _connectDownloadSignals(void);
void _disconnectDownloadSignals(void);
void _connectListSignals(void);
void _disconnectListSignals(void);
void _requestDirectoryList(const QString& dir);
static const int _typeFile = QTreeWidgetItem::UserType + 1;
static const int _typeDir = QTreeWidgetItem::UserType + 2;
static const int _typeError = QTreeWidgetItem::UserType + 3;
QTimer _listCompleteTimer; ///> Used to signal a timeout waiting for a listComplete signal
static const int _listCompleteTimerTimeoutMsecs = 5000; ///> Timeout in msecs for listComplete timer
QList<int> _walkIndexStack;
QList<QTreeWidgetItem*> _walkItemStack;
Ui::QGCUASFileView _ui;
QString _downloadFilename; ///< File currently being downloaded, not including path
QTime _downloadStartTime; ///< Time at which download started
bool _listInProgress; ///< Indicates that a listDirectory command is in progress
bool _downloadInProgress; ///< Indicates that a downloadPath command is in progress
};
#endif // QGCUASFILEVIEW_H
......@@ -14,13 +14,23 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="listFilesButton">
<property name="text">
<string>List Files</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTreeWidget" name="treeWidget">
<property name="headerHidden">
......@@ -33,7 +43,7 @@
</column>
</widget>
</item>
<item row="1" column="2">
<item row="3" column="2">
<widget class="QPushButton" name="downloadButton">
<property name="enabled">
<bool>false</bool>
......@@ -43,6 +53,19 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="statusText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
......
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