annotate data/fileio/RemoteFile.cpp @ 278:9a13687c078b

* Add SingleColourLayer to manage colours for layers that have a single predominant colour (i.e. most of them).
author Chris Cannam
date Thu, 12 Jul 2007 16:14:59 +0000
parents ce6f65ab3327
children 7802b0e2b0ff
rev   line source
Chris@208 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@208 2
Chris@208 3 /*
Chris@208 4 Sonic Visualiser
Chris@208 5 An audio file viewer and annotation editor.
Chris@208 6 Centre for Digital Music, Queen Mary, University of London.
Chris@208 7 This file copyright 2007 QMUL.
Chris@208 8
Chris@208 9 This program is free software; you can redistribute it and/or
Chris@208 10 modify it under the terms of the GNU General Public License as
Chris@208 11 published by the Free Software Foundation; either version 2 of the
Chris@208 12 License, or (at your option) any later version. See the file
Chris@208 13 COPYING included with this distribution for more information.
Chris@208 14 */
Chris@208 15
Chris@208 16 #include "RemoteFile.h"
Chris@208 17 #include "base/TempDirectory.h"
Chris@208 18 #include "base/Exceptions.h"
Chris@208 19
Chris@208 20 #include <QHttp>
Chris@208 21 #include <QFtp>
Chris@208 22 #include <QFileInfo>
Chris@208 23 #include <QDir>
Chris@208 24 #include <QApplication>
Chris@208 25 #include <QProgressDialog>
Chris@210 26 #include <QHttpResponseHeader>
Chris@208 27
Chris@208 28 #include <iostream>
Chris@208 29
Chris@208 30 int
Chris@208 31 RemoteFile::m_count = 0;
Chris@208 32
Chris@208 33 QMutex
Chris@208 34 RemoteFile::m_fileCreationMutex;
Chris@208 35
Chris@208 36 RemoteFile::RemoteFile(QUrl url) :
Chris@208 37 m_ftp(0),
Chris@208 38 m_http(0),
Chris@208 39 m_localFile(0),
Chris@208 40 m_ok(false),
Chris@210 41 m_lastStatus(0),
Chris@208 42 m_done(false),
Chris@210 43 m_progressDialog(0),
Chris@210 44 m_progressShowTimer(this)
Chris@208 45 {
Chris@208 46 if (!canHandleScheme(url)) {
Chris@208 47 std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl;
Chris@208 48 return;
Chris@208 49 }
Chris@208 50
Chris@208 51 m_localFilename = createLocalFile(url);
Chris@208 52 if (m_localFilename == "") return;
Chris@208 53 m_localFile = new QFile(m_localFilename);
Chris@208 54 m_localFile->open(QFile::WriteOnly);
Chris@208 55
Chris@208 56 QString scheme = url.scheme().toLower();
Chris@208 57
Chris@208 58 if (scheme == "http") {
Chris@208 59
Chris@211 60 m_ok = true;
Chris@208 61 m_http = new QHttp(url.host(), url.port(80));
Chris@208 62 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
Chris@208 63 connect(m_http, SIGNAL(dataReadProgress(int, int)),
Chris@208 64 this, SLOT(dataReadProgress(int, int)));
Chris@210 65 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
Chris@214 66 this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &)));
Chris@278 67 QString path = url.path();
Chris@278 68 std::cerr << "RemoteFile: path is \"" << path.toStdString() << "\"" << std::endl;
Chris@278 69 m_http->get(path, m_localFile);
Chris@208 70
Chris@208 71 } else if (scheme == "ftp") {
Chris@208 72
Chris@211 73 m_ok = true;
Chris@208 74 m_ftp = new QFtp;
Chris@208 75 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
Chris@214 76 connect(m_ftp, SIGNAL(commandFinished(int, bool)),
Chris@214 77 this, SLOT(ftpCommandFinished(int, bool)));
Chris@208 78 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
Chris@208 79 this, SLOT(dataTransferProgress(qint64, qint64)));
Chris@208 80 m_ftp->connectToHost(url.host(), url.port(21));
Chris@208 81
Chris@208 82 QString username = url.userName();
Chris@208 83 if (username == "") {
Chris@208 84 username = "anonymous";
Chris@208 85 }
Chris@208 86
Chris@208 87 QString password = url.password();
Chris@208 88 if (password == "") {
Chris@208 89 password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST"));
Chris@208 90 }
Chris@208 91
Chris@214 92 m_ftp->login(username, password);
Chris@214 93
Chris@214 94 QString dirpath = url.path().section('/', 0, -2);
Chris@214 95 QString filename = url.path().section('/', -1);
Chris@214 96
Chris@214 97 if (dirpath == "") dirpath = "/";
Chris@214 98 m_ftp->cd(dirpath);
Chris@214 99 m_ftp->get(filename, m_localFile);
Chris@208 100 }
Chris@208 101
Chris@208 102 if (m_ok) {
Chris@208 103 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100);
Chris@210 104 m_progressDialog->hide();
Chris@210 105 connect(&m_progressShowTimer, SIGNAL(timeout()),
Chris@210 106 this, SLOT(showProgressDialog()));
Chris@210 107 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled()));
Chris@210 108 m_progressShowTimer.setSingleShot(true);
Chris@210 109 m_progressShowTimer.start(2000);
Chris@208 110 }
Chris@208 111 }
Chris@208 112
Chris@208 113 RemoteFile::~RemoteFile()
Chris@208 114 {
Chris@211 115 cleanup();
Chris@211 116 }
Chris@211 117
Chris@211 118 void
Chris@211 119 RemoteFile::cleanup()
Chris@211 120 {
Chris@211 121 // std::cerr << "RemoteFile::cleanup" << std::endl;
Chris@211 122 m_done = true;
Chris@214 123 if (m_http) {
Chris@214 124 delete m_http;
Chris@214 125 m_http = 0;
Chris@214 126 }
Chris@214 127 if (m_ftp) {
Chris@214 128 m_ftp->abort();
Chris@214 129 m_ftp->deleteLater();
Chris@214 130 m_ftp = 0;
Chris@214 131 }
Chris@211 132 delete m_progressDialog;
Chris@211 133 m_progressDialog = 0;
Chris@208 134 delete m_localFile;
Chris@211 135 m_localFile = 0;
Chris@208 136 }
Chris@208 137
Chris@208 138 bool
Chris@208 139 RemoteFile::canHandleScheme(QUrl url)
Chris@208 140 {
Chris@208 141 QString scheme = url.scheme().toLower();
Chris@208 142 return (scheme == "http" || scheme == "ftp");
Chris@208 143 }
Chris@208 144
Chris@210 145 bool
Chris@210 146 RemoteFile::isAvailable()
Chris@210 147 {
Chris@211 148 while (m_ok && (!m_done && m_lastStatus == 0)) {
Chris@210 149 QApplication::processEvents();
Chris@210 150 }
Chris@211 151 bool available = true;
Chris@211 152 if (!m_ok) available = false;
Chris@211 153 else available = (m_lastStatus / 100 == 2);
Chris@211 154 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no")
Chris@211 155 << std::endl;
Chris@211 156 return available;
Chris@210 157 }
Chris@210 158
Chris@208 159 void
Chris@208 160 RemoteFile::wait()
Chris@208 161 {
Chris@211 162 while (m_ok && !m_done) {
Chris@208 163 QApplication::processEvents();
Chris@208 164 }
Chris@208 165 }
Chris@208 166
Chris@208 167 bool
Chris@208 168 RemoteFile::isOK() const
Chris@208 169 {
Chris@208 170 return m_ok;
Chris@208 171 }
Chris@208 172
Chris@208 173 bool
Chris@208 174 RemoteFile::isDone() const
Chris@208 175 {
Chris@208 176 return m_done;
Chris@208 177 }
Chris@208 178
Chris@208 179 QString
Chris@208 180 RemoteFile::getLocalFilename() const
Chris@208 181 {
Chris@208 182 return m_localFilename;
Chris@208 183 }
Chris@208 184
Chris@208 185 QString
Chris@208 186 RemoteFile::getErrorString() const
Chris@208 187 {
Chris@208 188 return m_errorString;
Chris@208 189 }
Chris@208 190
Chris@208 191 void
Chris@208 192 RemoteFile::dataReadProgress(int done, int total)
Chris@208 193 {
Chris@208 194 dataTransferProgress(done, total);
Chris@208 195 }
Chris@208 196
Chris@208 197 void
Chris@214 198 RemoteFile::httpResponseHeaderReceived(const QHttpResponseHeader &resp)
Chris@210 199 {
Chris@210 200 m_lastStatus = resp.statusCode();
Chris@210 201 if (m_lastStatus / 100 >= 4) {
Chris@210 202 m_errorString = QString("%1 %2")
Chris@210 203 .arg(resp.statusCode()).arg(resp.reasonPhrase());
Chris@211 204 std::cerr << "RemoteFile::responseHeaderReceived: "
Chris@211 205 << m_errorString.toStdString() << std::endl;
Chris@211 206 } else {
Chris@211 207 std::cerr << "RemoteFile::responseHeaderReceived: "
Chris@211 208 << m_lastStatus << std::endl;
Chris@211 209 }
Chris@210 210 }
Chris@210 211
Chris@210 212 void
Chris@214 213 RemoteFile::ftpCommandFinished(int id, bool error)
Chris@214 214 {
Chris@214 215 std::cerr << "RemoteFile::ftpCommandFinished(" << id << ", " << error << ")" << std::endl;
Chris@214 216
Chris@214 217 if (!m_ftp) return;
Chris@214 218
Chris@214 219 QFtp::Command command = m_ftp->currentCommand();
Chris@214 220
Chris@214 221 if (!error) {
Chris@214 222 std::cerr << "RemoteFile::ftpCommandFinished: success for command "
Chris@214 223 << command << std::endl;
Chris@214 224 return;
Chris@214 225 }
Chris@214 226
Chris@214 227 if (command == QFtp::ConnectToHost) {
Chris@214 228 m_errorString = tr("Failed to connect to FTP server");
Chris@214 229 } else if (command == QFtp::Login) {
Chris@214 230 m_errorString = tr("Login failed");
Chris@214 231 } else if (command == QFtp::Cd) {
Chris@214 232 m_errorString = tr("Failed to change to correct directory");
Chris@214 233 } else if (command == QFtp::Get) {
Chris@214 234 m_errorString = tr("FTP download aborted");
Chris@214 235 }
Chris@214 236
Chris@214 237 m_lastStatus = 400; // for done()
Chris@214 238 }
Chris@214 239
Chris@214 240 void
Chris@208 241 RemoteFile::dataTransferProgress(qint64 done, qint64 total)
Chris@208 242 {
Chris@211 243 if (!m_progressDialog) return;
Chris@211 244
Chris@208 245 int percent = int((double(done) / double(total)) * 100.0 - 0.1);
Chris@208 246 emit progress(percent);
Chris@208 247
Chris@211 248 if (percent > 0) {
Chris@211 249 m_progressDialog->setValue(percent);
Chris@211 250 m_progressDialog->show();
Chris@211 251 }
Chris@210 252 }
Chris@210 253
Chris@210 254 void
Chris@210 255 RemoteFile::cancelled()
Chris@210 256 {
Chris@211 257 deleteLocalFile();
Chris@210 258 m_done = true;
Chris@210 259 m_ok = false;
Chris@210 260 m_errorString = tr("Download cancelled");
Chris@208 261 }
Chris@208 262
Chris@208 263 void
Chris@208 264 RemoteFile::done(bool error)
Chris@208 265 {
Chris@214 266 std::cerr << "RemoteFile::done(" << error << ")" << std::endl;
Chris@211 267
Chris@211 268 if (m_done) return;
Chris@211 269
Chris@208 270 emit progress(100);
Chris@210 271
Chris@208 272 if (error) {
Chris@208 273 if (m_http) {
Chris@208 274 m_errorString = m_http->errorString();
Chris@208 275 } else if (m_ftp) {
Chris@208 276 m_errorString = m_ftp->errorString();
Chris@208 277 }
Chris@208 278 }
Chris@208 279
Chris@210 280 if (m_lastStatus / 100 >= 4) {
Chris@211 281 error = true;
Chris@210 282 }
Chris@210 283
Chris@211 284 cleanup();
Chris@208 285
Chris@211 286 if (!error) {
Chris@208 287 QFileInfo fi(m_localFilename);
Chris@208 288 if (!fi.exists()) {
Chris@208 289 m_errorString = tr("Failed to create local file %1").arg(m_localFilename);
Chris@211 290 error = true;
Chris@208 291 } else if (fi.size() == 0) {
Chris@208 292 m_errorString = tr("File contains no data!");
Chris@211 293 error = true;
Chris@208 294 }
Chris@208 295 }
Chris@211 296
Chris@211 297 if (error) {
Chris@211 298 deleteLocalFile();
Chris@211 299 }
Chris@211 300
Chris@211 301 m_ok = !error;
Chris@211 302 m_done = true;
Chris@211 303 }
Chris@211 304
Chris@211 305 void
Chris@211 306 RemoteFile::deleteLocalFile()
Chris@211 307 {
Chris@211 308 // std::cerr << "RemoteFile::deleteLocalFile" << std::endl;
Chris@211 309
Chris@211 310 cleanup();
Chris@211 311
Chris@211 312 if (m_localFilename == "") return;
Chris@211 313
Chris@211 314 m_fileCreationMutex.lock();
Chris@211 315
Chris@211 316 if (!QFile(m_localFilename).remove()) {
Chris@211 317 std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl;
Chris@211 318 } else {
Chris@211 319 m_localFilename = "";
Chris@211 320 }
Chris@211 321
Chris@211 322 m_fileCreationMutex.unlock();
Chris@211 323
Chris@208 324 m_done = true;
Chris@208 325 }
Chris@208 326
Chris@210 327 void
Chris@210 328 RemoteFile::showProgressDialog()
Chris@210 329 {
Chris@210 330 if (m_progressDialog) m_progressDialog->show();
Chris@210 331 }
Chris@210 332
Chris@208 333 QString
Chris@208 334 RemoteFile::createLocalFile(QUrl url)
Chris@208 335 {
Chris@208 336 QDir dir;
Chris@208 337 try {
Chris@208 338 dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
Chris@208 339 } catch (DirectoryCreationFailed f) {
Chris@208 340 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;
Chris@208 341 return "";
Chris@208 342 }
Chris@208 343
Chris@208 344 QString filepart = url.path().section('/', -1, -1,
Chris@208 345 QString::SectionSkipEmpty);
Chris@208 346
Chris@208 347 QString extension = filepart.section('.', -1);
Chris@208 348 QString base = filepart;
Chris@208 349 if (extension != "") {
Chris@208 350 base = base.left(base.length() - extension.length() - 1);
Chris@208 351 }
Chris@208 352 if (base == "") base = "remote";
Chris@208 353
Chris@208 354 QString filename;
Chris@208 355
Chris@208 356 if (extension == "") {
Chris@208 357 filename = base;
Chris@208 358 } else {
Chris@208 359 filename = QString("%1.%2").arg(base).arg(extension);
Chris@208 360 }
Chris@208 361
Chris@208 362 QString filepath(dir.filePath(filename));
Chris@208 363
Chris@208 364 std::cerr << "RemoteFile::createLocalFile: URL is \"" << url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl;
Chris@208 365
Chris@208 366 m_fileCreationMutex.lock();
Chris@208 367 ++m_count;
Chris@208 368
Chris@208 369 if (QFileInfo(filepath).exists() ||
Chris@208 370 !QFile(filepath).open(QFile::WriteOnly)) {
Chris@208 371
Chris@208 372 std::cerr << "RemoteFile::createLocalFile: Failed to create local file \""
Chris@208 373 << filepath.toStdString() << "\" for URL \""
Chris@208 374 << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl;
Chris@208 375
Chris@208 376
Chris@208 377 if (extension == "") {
Chris@208 378 filename = QString("%1_%2").arg(base).arg(m_count);
Chris@208 379 } else {
Chris@208 380 filename = QString("%1_%2.%3").arg(base).arg(m_count).arg(extension);
Chris@208 381 }
Chris@208 382 filepath = dir.filePath(filename);
Chris@208 383
Chris@208 384 if (QFileInfo(filepath).exists() ||
Chris@208 385 !QFile(filepath).open(QFile::WriteOnly)) {
Chris@208 386
Chris@208 387 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \""
Chris@208 388 << filepath.toStdString() << "\" for URL \""
Chris@208 389 << url.toString().toStdString() << "\" (or file already exists)" << std::endl;
Chris@208 390
Chris@208 391 m_fileCreationMutex.unlock();
Chris@208 392 return "";
Chris@208 393 }
Chris@208 394 }
Chris@208 395
Chris@208 396 m_fileCreationMutex.unlock();
Chris@208 397
Chris@208 398 std::cerr << "RemoteFile::createLocalFile: url "
Chris@208 399 << url.toString().toStdString() << " -> local filename "
Chris@208 400 << filepath.toStdString() << std::endl;
Chris@208 401
Chris@208 402 return filepath;
Chris@208 403 }