diff --git a/src/uas/QGCUASFileManager.cc b/src/uas/QGCUASFileManager.cc index 8eaee04fa81..41b726d993f 100644 --- a/src/uas/QGCUASFileManager.cc +++ b/src/uas/QGCUASFileManager.cc @@ -99,11 +99,6 @@ quint32 QGCUASFileManager::crc32(Request* request, unsigned state) return state; } -void QGCUASFileManager::nothingMessage() -{ - // FIXME: Connect ui correctly -} - /// @brief Respond to the Ack associated with the Open command with the next Read command. void QGCUASFileManager::_openAckResponse(Request* openAck) { @@ -220,17 +215,11 @@ void QGCUASFileManager::_listAckResponse(Request* listAck) _emitErrorMessage(tr("Missing NULL termination in list entry")); return; } - - // Returned names are prepended with D for directory, F for file, U for unknown - QString s(ptr + 1); - if (*ptr == 'D') { - s.append('/'); - } - + // 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(s); + _emitStatusMessage(ptr); } // account for the name + NUL @@ -243,6 +232,7 @@ void QGCUASFileManager::_listAckResponse(Request* listAck) // Directory is empty, we're done Q_ASSERT(listAck->hdr.opcode == kRspAck); _currentOperation = kCOIdle; + emit listComplete(); } else { // Possibly more entries to come, need to keep trying till we get EOF _currentOperation = kCOList; @@ -307,6 +297,7 @@ void QGCUASFileManager::receiveMessage(LinkInterface* link, mavlink_message_t me if (previousOperation == kCOList && errorCode == kErrEOF) { // This is not an error, just the end of the read loop + emit listComplete(); return; } else if (previousOperation == kCORead && errorCode == kErrEOF) { // This is not an error, just the end of the read loop diff --git a/src/uas/QGCUASFileManager.h b/src/uas/QGCUASFileManager.h index 77cf33f503c..5a3bc8432df 100644 --- a/src/uas/QGCUASFileManager.h +++ b/src/uas/QGCUASFileManager.h @@ -43,11 +43,11 @@ class QGCUASFileManager : public QObject signals: void statusMessage(const QString& msg); void resetStatusMessages(); - void errorMessage(const QString& ms); + void errorMessage(const QString& msg); + void listComplete(void); public slots: void receiveMessage(LinkInterface* link, mavlink_message_t message); - void nothingMessage(); void listDirectory(const QString& dirPath); void downloadPath(const QString& from, const QDir& downloadDir); diff --git a/src/ui/QGCUASFileView.cc b/src/ui/QGCUASFileView.cc index 55412e18f81..a9ac957363f 100644 --- a/src/ui/QGCUASFileView.cc +++ b/src/ui/QGCUASFileView.cc @@ -1,42 +1,199 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + #include "QGCUASFileView.h" #include "uas/QGCUASFileManager.h" -#include "ui_QGCUASFileView.h" #include #include +#include QGCUASFileView::QGCUASFileView(QWidget *parent, QGCUASFileManager *manager) : QWidget(parent), - _manager(manager), - ui(new Ui::QGCUASFileView) + _manager(manager) { - ui->setupUi(this); + _ui.setupUi(this); - connect(ui->testButton, SIGNAL(clicked()), _manager, SLOT(nothingMessage())); - connect(ui->listFilesButton, SIGNAL(clicked()), this, SLOT(listFiles())); - connect(ui->downloadButton, SIGNAL(clicked()), this, SLOT(downloadFiles())); + bool success = connect(_ui.listFilesButton, SIGNAL(clicked()), this, SLOT(_refreshTree())); + Q_ASSERT(success); + success = connect(_ui.downloadButton, SIGNAL(clicked()), this, SLOT(_downloadFiles())); + Q_ASSERT(success); + success = connect(_ui.treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(_currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + Q_ASSERT(success); + Q_UNUSED(success); +} - connect(_manager, SIGNAL(statusMessage(QString)), ui->messageArea, SLOT(appendPlainText(QString))); - connect(_manager, SIGNAL(errorMessage(QString)), ui->messageArea, SLOT(appendPlainText(QString))); - connect(_manager, SIGNAL(resetStatusMessages()), ui->messageArea, SLOT(clear())); +void QGCUASFileView::_downloadFiles(void) +{ + QString dir = 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) { + do { + path.prepend("/" + item->text(0)); + 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)); + } } -QGCUASFileView::~QGCUASFileView() +void QGCUASFileView::_refreshTree(void) { - delete ui; + QTreeWidgetItem* item; + + for (int i=_ui.treeWidget->invisibleRootItem()->childCount(); i>=0; i--) { + item = _ui.treeWidget->takeTopLevelItem(i); + delete item; + } + + _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); + + qDebug() << "List: /"; + _manager->listDirectory("/"); } -void QGCUASFileView::listFiles() +void QGCUASFileView::_treeStatusMessage(const QString& msg) { - _manager->listDirectory(ui->pathLineEdit->text()); + int type; + if (msg.startsWith("F")) { + type = _typeFile; + } else if (msg.startsWith("D")) { + type = _typeDir; + if (msg == "D." || msg == "D..") { + return; + } + } else { + Q_ASSERT(false); + } + + QTreeWidgetItem* item; + if (_walkItemStack.count() == 0) { + item = new QTreeWidgetItem(_ui.treeWidget, type); + } else { + item = new QTreeWidgetItem(_walkItemStack.last(), type); + } + Q_CHECK_PTR(item); + + item->setText(0, msg.right(msg.size() - 1)); } -void QGCUASFileView::downloadFiles() +void QGCUASFileView::_treeErrorMessage(const QString& msg) { - QString dir = QFileDialog::getExistingDirectory(this, tr("Download Directory"), - QDir::homePath(), - QFileDialog::ShowDirsOnly - | QFileDialog::DontResolveSymlinks); - // And now download to this location - _manager->downloadPath(ui->pathLineEdit->text(), QDir(dir)); + QTreeWidgetItem* item; + if (_walkItemStack.count() == 0) { + item = new QTreeWidgetItem(_ui.treeWidget, _typeError); + } else { + item = new QTreeWidgetItem(_walkItemStack.last(), _typeError); + } + Q_CHECK_PTR(item); + + item->setText(0, tr("Error: ") + msg); +} + +void QGCUASFileView::_listComplete(void) +{ + // Walk the current items, traversing down into directories + +Again: + int walkIndex = _walkIndexStack.last(); + QTreeWidgetItem* parentItem = _walkItemStack.last(); + QTreeWidgetItem* childItem = parentItem->child(walkIndex); + + // Loop until we hit a directory + while (childItem && childItem->type() != _typeDir) { + // Move to next index at current level + _walkIndexStack.last() = ++walkIndex; + childItem = parentItem->child(walkIndex); + } + + if (childItem) { + // Process this item + QString text = childItem->text(0); + + // Move to the next item for processing at this level + _walkIndexStack.last() = ++walkIndex; + + // Push this new directory on the stack + _walkItemStack.append(childItem); + _walkIndexStack.append(0); + + // Ask for the directory list + QString dir; + for (int i=1; i<_walkItemStack.count(); i++) { + QTreeWidgetItem* item = _walkItemStack[i]; + dir.append("/" + item->text(0)); + } + qDebug() << "List:" << dir; + _manager->listDirectory(dir); + } else { + // We have run out of items at the this level, pop the stack and keep going at that level + _walkIndexStack.removeLast(); + _walkItemStack.removeLast(); + 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))); + } + } +} + +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); + _ui.downloadButton->setEnabled(current->type() == _typeFile); } diff --git a/src/ui/QGCUASFileView.h b/src/ui/QGCUASFileView.h index 0bb3700416d..0b33e5b3b35 100644 --- a/src/ui/QGCUASFileView.h +++ b/src/ui/QGCUASFileView.h @@ -1,12 +1,34 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + #ifndef QGCUASFILEVIEW_H #define QGCUASFILEVIEW_H #include -#include "uas/QGCUASFileManager.h" +#include -namespace Ui { -class QGCUASFileView; -} +#include "uas/QGCUASFileManager.h" +#include "ui_QGCUASFileView.h" class QGCUASFileView : public QWidget { @@ -14,17 +36,27 @@ class QGCUASFileView : public QWidget public: explicit QGCUASFileView(QWidget *parent, QGCUASFileManager *manager); - ~QGCUASFileView(); - -public slots: - void listFiles(); - void downloadFiles(); protected: QGCUASFileManager* _manager; + +private slots: + void _refreshTree(void); + void _downloadFiles(void); + void _treeStatusMessage(const QString& msg); + void _treeErrorMessage(const QString& msg); + void _listComplete(void); + void _downloadStatusMessage(const QString& msg); + void _currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); private: - Ui::QGCUASFileView *ui; + static const int _typeFile = QTreeWidgetItem::UserType + 1; + static const int _typeDir = QTreeWidgetItem::UserType + 2; + static const int _typeError = QTreeWidgetItem::UserType + 3; + + QList _walkIndexStack; + QList _walkItemStack; + Ui::QGCUASFileView _ui; }; #endif // QGCUASFILEVIEW_H diff --git a/src/ui/QGCUASFileView.ui b/src/ui/QGCUASFileView.ui index 1cbc196fecf..1bb3552c465 100644 --- a/src/ui/QGCUASFileView.ui +++ b/src/ui/QGCUASFileView.ui @@ -14,7 +14,7 @@ Form - + List Files @@ -22,10 +22,10 @@ - - - + + true + 1 @@ -33,30 +33,16 @@ - - - - Null Message - - - - + - - Download File + + false - - - - - Path: + Download File - - -