comparison data/fileio/FileSource.cpp @ 384:6f6ab834449d spectrogram-cache-rejig

* Merge from trunk
author Chris Cannam
date Wed, 27 Feb 2008 11:59:42 +0000
parents a6fab10ff9e6
children
comparison
equal deleted inserted replaced
337:a6fab10ff9e6 384:6f6ab834449d
12 License, or (at your option) any later version. See the file 12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information. 13 COPYING included with this distribution for more information.
14 */ 14 */
15 15
16 #include "FileSource.h" 16 #include "FileSource.h"
17 #include "ProgressPrinter.h"
18
17 #include "base/TempDirectory.h" 19 #include "base/TempDirectory.h"
18 #include "base/Exceptions.h" 20 #include "base/Exceptions.h"
19 21
20 #include <QHttp> 22 #include <QHttp>
21 #include <QFtp> 23 #include <QFtp>
25 #include <QProgressDialog> 27 #include <QProgressDialog>
26 #include <QHttpResponseHeader> 28 #include <QHttpResponseHeader>
27 29
28 #include <iostream> 30 #include <iostream>
29 31
30 //#define DEBUG_FILE_SOURCE 1 32 #define DEBUG_FILE_SOURCE 1
31 33
32 int 34 int
33 FileSource::m_count = 0; 35 FileSource::m_count = 0;
34 36
35 QMutex 37 QMutex
42 FileSource::m_remoteLocalMap; 44 FileSource::m_remoteLocalMap;
43 45
44 QMutex 46 QMutex
45 FileSource::m_mapMutex; 47 FileSource::m_mapMutex;
46 48
47 FileSource::FileSource(QString fileOrUrl, bool showProgress) : 49 FileSource::FileSource(QString fileOrUrl, ShowProgressType progressType) :
48 m_url(fileOrUrl), 50 m_url(fileOrUrl),
49 m_ftp(0), 51 m_ftp(0),
50 m_http(0), 52 m_http(0),
51 m_localFile(0), 53 m_localFile(0),
52 m_ok(false), 54 m_ok(false),
53 m_lastStatus(0), 55 m_lastStatus(0),
54 m_remote(isRemote(fileOrUrl)), 56 m_remote(isRemote(fileOrUrl)),
55 m_done(false), 57 m_done(false),
56 m_leaveLocalFile(false), 58 m_leaveLocalFile(false),
59 m_progressType(progressType),
60 m_progressPrinter(0),
57 m_progressDialog(0), 61 m_progressDialog(0),
58 m_progressShowTimer(this), 62 m_progressShowTimer(this),
59 m_refCounted(false) 63 m_refCounted(false)
60 { 64 {
61 #ifdef DEBUG_FILE_SOURCE 65 #ifdef DEBUG_FILE_SOURCE
66 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; 70 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
67 m_errorString = tr("Unsupported scheme in URL"); 71 m_errorString = tr("Unsupported scheme in URL");
68 return; 72 return;
69 } 73 }
70 74
71 init(showProgress); 75 init();
72 76
73 if (isRemote() && 77 if (isRemote() &&
74 (fileOrUrl.contains('%') || 78 (fileOrUrl.contains('%') ||
75 fileOrUrl.contains("--"))) { // for IDNA 79 fileOrUrl.contains("--"))) { // for IDNA
76 80
97 m_url.setEncodedUrl(fileOrUrl.toAscii()); 101 m_url.setEncodedUrl(fileOrUrl.toAscii());
98 102
99 m_ok = false; 103 m_ok = false;
100 m_done = false; 104 m_done = false;
101 m_lastStatus = 0; 105 m_lastStatus = 0;
102 init(showProgress); 106 init();
103 } 107 }
104 } 108 }
105 109
106 if (!isRemote()) { 110 if (!isRemote()) {
107 emit statusAvailable(); 111 emit statusAvailable();
108 emit ready(); 112 emit ready();
109 } 113 }
110 } 114 }
111 115
112 FileSource::FileSource(QUrl url, bool showProgress) : 116 FileSource::FileSource(QUrl url, ShowProgressType progressType) :
113 m_url(url), 117 m_url(url),
114 m_ftp(0), 118 m_ftp(0),
115 m_http(0), 119 m_http(0),
116 m_localFile(0), 120 m_localFile(0),
117 m_ok(false), 121 m_ok(false),
118 m_lastStatus(0), 122 m_lastStatus(0),
119 m_remote(isRemote(url.toString())), 123 m_remote(isRemote(url.toString())),
120 m_done(false), 124 m_done(false),
121 m_leaveLocalFile(false), 125 m_leaveLocalFile(false),
126 m_progressType(progressType),
127 m_progressPrinter(0),
122 m_progressDialog(0), 128 m_progressDialog(0),
123 m_progressShowTimer(this), 129 m_progressShowTimer(this),
124 m_refCounted(false) 130 m_refCounted(false)
125 { 131 {
126 #ifdef DEBUG_FILE_SOURCE 132 #ifdef DEBUG_FILE_SOURCE
131 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; 137 std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
132 m_errorString = tr("Unsupported scheme in URL"); 138 m_errorString = tr("Unsupported scheme in URL");
133 return; 139 return;
134 } 140 }
135 141
136 init(showProgress); 142 init();
137 } 143 }
138 144
139 FileSource::FileSource(const FileSource &rf) : 145 FileSource::FileSource(const FileSource &rf) :
140 QObject(), 146 QObject(),
141 m_url(rf.m_url), 147 m_url(rf.m_url),
145 m_ok(rf.m_ok), 151 m_ok(rf.m_ok),
146 m_lastStatus(rf.m_lastStatus), 152 m_lastStatus(rf.m_lastStatus),
147 m_remote(rf.m_remote), 153 m_remote(rf.m_remote),
148 m_done(false), 154 m_done(false),
149 m_leaveLocalFile(false), 155 m_leaveLocalFile(false),
156 m_progressType(rf.m_progressType),
157 m_progressPrinter(0),
150 m_progressDialog(0), 158 m_progressDialog(0),
151 m_progressShowTimer(0), 159 m_progressShowTimer(0),
152 m_refCounted(false) 160 m_refCounted(false)
153 { 161 {
154 #ifdef DEBUG_FILE_SOURCE 162 #ifdef DEBUG_FILE_SOURCE
195 203
196 if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); 204 if (isRemote() && !m_leaveLocalFile) deleteCacheFile();
197 } 205 }
198 206
199 void 207 void
200 FileSource::init(bool showProgress) 208 FileSource::init()
201 { 209 {
202 if (!isRemote()) { 210 if (!isRemote()) {
211 #ifdef DEBUG_FILE_SOURCE
212 std::cerr << "FileSource::init: Not a remote URL" << std::endl;
213 #endif
214 bool literal = false;
203 m_localFilename = m_url.toLocalFile(); 215 m_localFilename = m_url.toLocalFile();
216 if (m_localFilename == "") {
217 // QUrl may have mishandled the scheme (e.g. in a DOS path)
218 m_localFilename = m_url.toString();
219 literal = true;
220 }
221 #ifdef DEBUG_FILE_SOURCE
222 std::cerr << "FileSource::init: URL translates to local filename \""
223 << m_localFilename.toStdString() << "\"" << std::endl;
224 #endif
225 m_ok = true;
226 m_lastStatus = 200;
227
228 if (!QFileInfo(m_localFilename).exists()) {
229 if (literal) {
230 m_lastStatus = 404;
231 } else {
232 // Again, QUrl may have been mistreating us --
233 // e.g. dropping a part that looks like query data
234 m_localFilename = m_url.toString();
235 literal = true;
236 if (!QFileInfo(m_localFilename).exists()) {
237 m_lastStatus = 404;
238 }
239 }
240 }
241
242 m_done = true;
243 return;
244 }
245
246 if (createCacheFile()) {
247 #ifdef DEBUG_FILE_SOURCE
248 std::cerr << "FileSource::init: Already have this one" << std::endl;
249 #endif
204 m_ok = true; 250 m_ok = true;
205 if (!QFileInfo(m_localFilename).exists()) { 251 if (!QFileInfo(m_localFilename).exists()) {
206 m_lastStatus = 404; 252 m_lastStatus = 404;
207 } else { 253 } else {
208 m_lastStatus = 200; 254 m_lastStatus = 200;
209 } 255 }
210 m_done = true; 256 m_done = true;
211 return; 257 return;
212 } 258 }
213 259
214 if (createCacheFile()) {
215 #ifdef DEBUG_FILE_SOURCE
216 std::cerr << "FileSource::init: Already have this one" << std::endl;
217 #endif
218 m_ok = true;
219 if (!QFileInfo(m_localFilename).exists()) {
220 m_lastStatus = 404;
221 } else {
222 m_lastStatus = 200;
223 }
224 m_done = true;
225 return;
226 }
227
228 if (m_localFilename == "") return; 260 if (m_localFilename == "") return;
229 m_localFile = new QFile(m_localFilename); 261 m_localFile = new QFile(m_localFilename);
230 m_localFile->open(QFile::WriteOnly); 262 m_localFile->open(QFile::WriteOnly);
231 263
232 QString scheme = m_url.scheme().toLower(); 264 QString scheme = m_url.scheme().toLower();
236 << m_url.toString().toStdString() << "\", retrieving" << std::endl; 268 << m_url.toString().toStdString() << "\", retrieving" << std::endl;
237 #endif 269 #endif
238 270
239 if (scheme == "http") { 271 if (scheme == "http") {
240 initHttp(); 272 initHttp();
273 std::cerr << "FileSource: initHttp succeeded" << std::endl;
241 } else if (scheme == "ftp") { 274 } else if (scheme == "ftp") {
242 initFtp(); 275 initFtp();
243 } else { 276 } else {
244 m_remote = false; 277 m_remote = false;
245 m_ok = false; 278 m_ok = false;
269 302
270 m_remoteLocalMap[m_url] = m_localFilename; 303 m_remoteLocalMap[m_url] = m_localFilename;
271 m_refCountMap[m_url]++; 304 m_refCountMap[m_url]++;
272 m_refCounted = true; 305 m_refCounted = true;
273 306
274 if (showProgress) { 307 switch (m_progressType) {
275 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100); 308
309 case ProgressNone: break;
310
311 case ProgressDialog:
312 m_progressDialog = new QProgressDialog
313 (tr("Downloading %1...").arg(m_url.toString()),
314 tr("Cancel"), 0, 100);
276 m_progressDialog->hide(); 315 m_progressDialog->hide();
277 connect(&m_progressShowTimer, SIGNAL(timeout()), 316 connect(&m_progressShowTimer, SIGNAL(timeout()),
278 this, SLOT(showProgressDialog())); 317 this, SLOT(showProgressDialog()));
279 connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); 318 connect(m_progressDialog, SIGNAL(canceled()),
319 this, SLOT(cancelled()));
280 m_progressShowTimer.setSingleShot(true); 320 m_progressShowTimer.setSingleShot(true);
281 m_progressShowTimer.start(2000); 321 m_progressShowTimer.start(2000);
322 break;
323
324 case ProgressToConsole:
325 m_progressPrinter = new ProgressPrinter(tr("Downloading..."));
326 connect(this, SIGNAL(progress(int)),
327 m_progressPrinter, SLOT(progress(int)));
328 break;
282 } 329 }
283 } 330 }
284 } 331 }
285 332
286 void 333 void
394 f->abort(); 441 f->abort();
395 f->deleteLater(); 442 f->deleteLater();
396 } 443 }
397 delete m_progressDialog; 444 delete m_progressDialog;
398 m_progressDialog = 0; 445 m_progressDialog = 0;
446 delete m_progressPrinter;
447 m_progressPrinter = 0;
399 delete m_localFile; // does not actually delete the file 448 delete m_localFile; // does not actually delete the file
400 m_localFile = 0; 449 m_localFile = 0;
401 } 450 }
402 451
403 bool 452 bool
404 FileSource::isRemote(QString fileOrUrl) 453 FileSource::isRemote(QString fileOrUrl)
405 { 454 {
455 // Note that a "scheme" with length 1 is probably a DOS drive letter
406 QString scheme = QUrl(fileOrUrl).scheme().toLower(); 456 QString scheme = QUrl(fileOrUrl).scheme().toLower();
407 return (scheme == "http" || scheme == "ftp"); 457 if (scheme == "" || scheme == "file" || scheme.length() == 1) return false;
458 return true;
408 } 459 }
409 460
410 bool 461 bool
411 FileSource::canHandleScheme(QUrl url) 462 FileSource::canHandleScheme(QUrl url)
412 { 463 {
464 // Note that a "scheme" with length 1 is probably a DOS drive letter
413 QString scheme = url.scheme().toLower(); 465 QString scheme = url.scheme().toLower();
414 return (scheme == "http" || scheme == "ftp" || 466 return (scheme == "http" || scheme == "ftp" ||
415 scheme == "file" || scheme == ""); 467 scheme == "file" || scheme == "" || scheme.length() == 1);
416 } 468 }
417 469
418 bool 470 bool
419 FileSource::isAvailable() 471 FileSource::isAvailable()
420 { 472 {
440 492
441 void 493 void
442 FileSource::waitForData() 494 FileSource::waitForData()
443 { 495 {
444 while (m_ok && !m_done) { 496 while (m_ok && !m_done) {
497 // std::cerr << "FileSource::waitForData: calling QApplication::processEvents" << std::endl;
445 QApplication::processEvents(); 498 QApplication::processEvents();
446 } 499 }
447 } 500 }
448 501
449 void 502 void
793 m_localFilename = filepath; 846 m_localFilename = filepath;
794 847
795 return false; 848 return false;
796 } 849 }
797 850
798 FileSourceProgressPrinter::FileSourceProgressPrinter() :
799 m_lastProgress(0)
800 {
801 }
802
803 FileSourceProgressPrinter::~FileSourceProgressPrinter()
804 {
805 if (m_lastProgress > 0 && m_lastProgress != 100) {
806 std::cerr << "\r\n";
807 }
808 }
809
810 void
811 FileSourceProgressPrinter::progress(int progress)
812 {
813 if (progress == m_lastProgress) return;
814 if (progress == 100) std::cerr << "\r\n";
815 else std::cerr << "\r" << progress << "%";
816 m_lastProgress = progress;
817 }
818