Newer
Older
/*=====================================================================
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"
QGCUASFileView::QGCUASFileView(QWidget *parent, QGCUASFileManager *manager) :
QWidget(parent),
_manager(manager),
_listInProgress(false),
_downloadInProgress(false),
_uploadInProgress(false)
// 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
// Connect UI signals
success = connect(_ui.listFilesButton, SIGNAL(clicked()), this, SLOT(_refreshTree()));
success = connect(_ui.downloadButton, SIGNAL(clicked()), this, SLOT(_downloadFile()));
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);
}
/// @brief Downloads the file currently selected in the tree view
void QGCUASFileView::_downloadFile(void)
Q_ASSERT(!_downloadInProgress);
_ui.statusText->clear();
QString downloadToHere = QGCFileDialog::getExistingDirectory(this, tr("Download Directory"),
QGCFileDialog::ShowDirsOnly
| QGCFileDialog::DontResolveSymlinks);
// And now download to this location
QString path;
QTreeWidgetItem* item = _ui.treeWidget->currentItem();
if (item && item->type() == _typeFile) {
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;
}
item = item->parent();
} while (item);
qDebug() << "Download: " << path;
_ui.downloadButton->setEnabled(false);
_downloadInProgress = true;
_connectDownloadSignals();
_manager->downloadPath(path, QDir(downloadToHere));
}
}
/// @brief uploads a file into the currently selected directory the tree view
void QGCUASFileView::_uploadFile(void)
{
Q_ASSERT(!_uploadInProgress);
_ui.statusText->clear();
// get and check directory from list view
QTreeWidgetItem* item = _ui.treeWidget->currentItem();
if (item && item->type() != _typeDir) {
return;
}
// Find complete path for upload directory
QString path;
do {
QString name = item->text(0).split("\t")[0]; // Strip off file sizes
path.prepend("/" + name);
item = item->parent();
} while (item);
QString uploadFromHere = QGCFileDialog::getOpenFileName(this, tr("Upload File"),
QDir::homePath());
qDebug() << "Upload: " << uploadFromHere << "to path" << path;
_manager->uploadPath(path, uploadFromHere);
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/// @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.
_walkIndexStack.clear();
_walkItemStack.clear();
_walkIndexStack.append(0);
_walkItemStack.append(_ui.treeWidget->invisibleRootItem());
// Don't queue up more than once
_ui.listFilesButton->setEnabled(false);
_listInProgress = true;
_connectListSignals();
/// @brief Adds the specified directory entry to the tree view.
void QGCUASFileView::_listEntryReceived(const QString& entry)
} else if (entry.startsWith("D")) {
if (entry == "D." || entry == "D..") {
return; // Silence maybe-unitialized on type
item = new QTreeWidgetItem(_walkItemStack.last(), type);
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)
if (_listInProgress) {
_ui.listFilesButton->setEnabled(true);
_listInProgress = false;
_disconnectListSignals();
_ui.statusText->setText(tr("Error: ") + msg);
}
}
void QGCUASFileView::_listComplete(void)
{
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// 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));
}
} 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 {
_ui.listFilesButton->setEnabled(true);
_listInProgress = false;
_disconnectListSignals();
}
}
}
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);
void QGCUASFileView::_requestDirectoryList(const QString& dir)
qDebug() << "List:" << dir;
_manager->listDirectory(dir);
/// @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)
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 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)
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&)));