Skip to content
Snippets Groups Projects
QGCUASFileView.cc 7.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Don Gagne's avatar
    Don Gagne committed
    /*=====================================================================
     
     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"
    
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    #include <QFileDialog>
    #include <QDir>
    
    Don Gagne's avatar
    Don Gagne committed
    #include <QMessageBox>
    
    QGCUASFileView::QGCUASFileView(QWidget *parent, QGCUASFileManager *manager) :
        QWidget(parent),
    
    Don Gagne's avatar
    Don Gagne committed
        _manager(manager)
    
    Don Gagne's avatar
    Don Gagne committed
        _ui.setupUi(this);
    
    Don Gagne's avatar
    Don Gagne committed
        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);
    
    Don Gagne's avatar
    Don Gagne committed
        success = connect(&_listCompleteTimer, SIGNAL(timeout()), this, SLOT(_listCompleteTimeout()));
        Q_ASSERT(success);
        Q_UNUSED(success);    // Silence retail unused variable error
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    Don Gagne's avatar
    Don Gagne committed
    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 {
    
                QString name = item->text(0).split("\t")[0];    // Strip off file sizes
                path.prepend("/" + name);
    
    Don Gagne's avatar
    Don Gagne committed
                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));
        }
    
    Don Gagne's avatar
    Don Gagne committed
    void QGCUASFileView::_refreshTree(void)
    
        _ui.treeWidget->clear();
    
    Don Gagne's avatar
    Don Gagne committed
    
        _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);
    
    Don Gagne's avatar
    Don Gagne committed
    
    
    Don Gagne's avatar
    Don Gagne committed
        _requestDirectoryList("/");
    
    Don Gagne's avatar
    Don Gagne committed
    void QGCUASFileView::_treeStatusMessage(const QString& msg)
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    {
    
    Don Gagne's avatar
    Don Gagne committed
        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);
    
    Don Gagne's avatar
    Don Gagne committed
            return; // Silence maybe-unitialized on type below
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
        QTreeWidgetItem* item;
    
        item = new QTreeWidgetItem(_walkItemStack.last(), type);
    
    Don Gagne's avatar
    Don Gagne committed
        Q_CHECK_PTR(item);
        
        item->setText(0, msg.right(msg.size() - 1));
    
    Don Gagne's avatar
    Don Gagne committed
    void QGCUASFileView::_treeErrorMessage(const QString& msg)
    
    Don Gagne's avatar
    Don Gagne committed
        QTreeWidgetItem* item;
    
        item = new QTreeWidgetItem(_walkItemStack.last(), _typeError);
    
    Don Gagne's avatar
    Don Gagne committed
        Q_CHECK_PTR(item);
        
        item->setText(0, tr("Error: ") + msg);
    
        
        // Fake listComplete signal after an error
        _listComplete();
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    void QGCUASFileView::_listComplete(void)
    {
    
    Don Gagne's avatar
    Don Gagne committed
        _clearListCompleteTimeout();
        
    
    Don Gagne's avatar
    Don Gagne committed
        // 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));
            }
    
    Don Gagne's avatar
    Don Gagne committed
            _requestDirectoryList(dir);
    
    Don Gagne's avatar
    Don Gagne committed
        } 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)));
    
                _ui.listFilesButton->setEnabled(true);
    
    Don Gagne's avatar
    Don Gagne committed
            }
        }
    }
    
    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 ? (current->type() == _typeFile) : false);
    
    Don Gagne's avatar
    Don Gagne committed
    
    void QGCUASFileView::_setupListCompleteTimeout(void)
    {
        Q_ASSERT(!_listCompleteTimer.isActive());
        
        _listCompleteTimer.setSingleShot(true);
        _listCompleteTimer.start(_listCompleteTimerTimeoutMsecs);
    }
    
    void QGCUASFileView::_clearListCompleteTimeout(void)
    {
        Q_ASSERT(_listCompleteTimer.isActive());
        
        _listCompleteTimer.stop();
    }
    
    void QGCUASFileView::_listCompleteTimeout(void)
    {
        _treeErrorMessage(tr("Timeout waiting for listComplete signal"));
    }
    
    void QGCUASFileView::_requestDirectoryList(const QString& dir)
    {
        qDebug() << "List:" << dir;
        _setupListCompleteTimeout();
        _manager->listDirectory(dir);
    }