Skip to content

Commit

Permalink
Changed FTP to tree view
Browse files Browse the repository at this point in the history
Also added selection from tree view for downloading
  • Loading branch information
DonLakeFlyer committed Jul 6, 2014
1 parent 2b88c6e commit 84cd97c
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 68 deletions.
17 changes: 4 additions & 13 deletions src/uas/QGCUASFileManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/uas/QGCUASFileManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
199 changes: 178 additions & 21 deletions src/ui/QGCUASFileView.cc
Original file line number Diff line number Diff line change
@@ -1,42 +1,199 @@
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/

#include "QGCUASFileView.h"
#include "uas/QGCUASFileManager.h"
#include "ui_QGCUASFileView.h"

#include <QFileDialog>
#include <QDir>
#include <QMessageBox>

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);
}
52 changes: 42 additions & 10 deletions src/ui/QGCUASFileView.h
Original file line number Diff line number Diff line change
@@ -1,30 +1,62 @@
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/

#ifndef QGCUASFILEVIEW_H
#define QGCUASFILEVIEW_H

#include <QWidget>
#include "uas/QGCUASFileManager.h"
#include <QTreeWidgetItem>

namespace Ui {
class QGCUASFileView;
}
#include "uas/QGCUASFileManager.h"
#include "ui_QGCUASFileView.h"

class QGCUASFileView : public QWidget
{
Q_OBJECT

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<int> _walkIndexStack;
QList<QTreeWidgetItem*> _walkItemStack;
Ui::QGCUASFileView _ui;
};

#endif // QGCUASFILEVIEW_H
Loading

0 comments on commit 84cd97c

Please sign in to comment.