comparison data/fileio/RemoteFile.cpp @ 211:e2bbb58e6df6

Several changes related to referring to remote URLs for sessions and files: * Pull file dialog wrapper functions out from MainWindow into FileFinder * If a file referred to in a session is not found at its expected location, try a few other alternatives (same location as the session file or same location as the last audio file) before asking the user to locate it * Allow user to give a URL when locating an audio file, not just locate on the filesystem * Make wave file models remember the "original" location (e.g. URL) of the audio file, not just the actual location from which the data was loaded (e.g. local copy of that URL) -- when saving a session, use the original location so as not to refer to a temporary file * Clean up incompletely-downloaded local copies of files
author Chris Cannam
date Thu, 11 Jan 2007 13:29:58 +0000
parents a06afefe45ee
children ce6f65ab3327
comparison
equal deleted inserted replaced
210:a06afefe45ee 211:e2bbb58e6df6
55 55
56 QString scheme = url.scheme().toLower(); 56 QString scheme = url.scheme().toLower();
57 57
58 if (scheme == "http") { 58 if (scheme == "http") {
59 59
60 m_ok = true;
60 m_http = new QHttp(url.host(), url.port(80)); 61 m_http = new QHttp(url.host(), url.port(80));
61 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); 62 connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
62 connect(m_http, SIGNAL(dataReadProgress(int, int)), 63 connect(m_http, SIGNAL(dataReadProgress(int, int)),
63 this, SLOT(dataReadProgress(int, int))); 64 this, SLOT(dataReadProgress(int, int)));
64 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), 65 connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
65 this, SLOT(responseHeaderReceived(const QHttpResponseHeader &))); 66 this, SLOT(responseHeaderReceived(const QHttpResponseHeader &)));
66 m_http->get(url.path(), m_localFile); 67 m_http->get(url.path(), m_localFile);
68
69 } else if (scheme == "ftp") {
70
67 m_ok = true; 71 m_ok = true;
68
69 } else if (scheme == "ftp") {
70
71 m_ftp = new QFtp; 72 m_ftp = new QFtp;
72 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); 73 connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool)));
73 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), 74 connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
74 this, SLOT(dataTransferProgress(qint64, qint64))); 75 this, SLOT(dataTransferProgress(qint64, qint64)));
75 m_ftp->connectToHost(url.host(), url.port(21)); 76 m_ftp->connectToHost(url.host(), url.port(21));
92 m_ftp->cd(*i); 93 m_ftp->cd(*i);
93 } else { 94 } else {
94 m_ftp->get(*i, m_localFile); 95 m_ftp->get(*i, m_localFile);
95 } 96 }
96 } 97 }
97
98 m_ok = true;
99 } 98 }
100 99
101 if (m_ok) { 100 if (m_ok) {
102 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); 101 m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100);
103 m_progressDialog->hide(); 102 m_progressDialog->hide();
109 } 108 }
110 } 109 }
111 110
112 RemoteFile::~RemoteFile() 111 RemoteFile::~RemoteFile()
113 { 112 {
114 delete m_ftp; 113 cleanup();
115 delete m_http; 114 }
116 delete m_localFile; 115
117 delete m_progressDialog; 116 void
118 } 117 RemoteFile::cleanup()
119 118 {
120 bool 119 // std::cerr << "RemoteFile::cleanup" << std::endl;
121 RemoteFile::canHandleScheme(QUrl url) 120 m_done = true;
122 {
123 QString scheme = url.scheme().toLower();
124 return (scheme == "http" || scheme == "ftp");
125 }
126
127 bool
128 RemoteFile::isAvailable()
129 {
130 while (!m_done && m_lastStatus == 0) {
131 QApplication::processEvents();
132 }
133 return (m_lastStatus / 100 == 2);
134 }
135
136 void
137 RemoteFile::wait()
138 {
139 while (!m_done) {
140 QApplication::processEvents();
141 }
142 }
143
144 bool
145 RemoteFile::isOK() const
146 {
147 return m_ok;
148 }
149
150 bool
151 RemoteFile::isDone() const
152 {
153 return m_done;
154 }
155
156 QString
157 RemoteFile::getLocalFilename() const
158 {
159 return m_localFilename;
160 }
161
162 QString
163 RemoteFile::getErrorString() const
164 {
165 return m_errorString;
166 }
167
168 void
169 RemoteFile::dataReadProgress(int done, int total)
170 {
171 dataTransferProgress(done, total);
172 }
173
174 void
175 RemoteFile::responseHeaderReceived(const QHttpResponseHeader &resp)
176 {
177 m_lastStatus = resp.statusCode();
178 if (m_lastStatus / 100 >= 4) {
179 m_errorString = QString("%1 %2")
180 .arg(resp.statusCode()).arg(resp.reasonPhrase());
181 }
182 }
183
184 void
185 RemoteFile::dataTransferProgress(qint64 done, qint64 total)
186 {
187 int percent = int((double(done) / double(total)) * 100.0 - 0.1);
188 emit progress(percent);
189
190 m_progressDialog->setValue(percent);
191 m_progressDialog->show();
192 }
193
194 void
195 RemoteFile::cancelled()
196 {
197 delete m_http; 121 delete m_http;
198 m_http = 0; 122 m_http = 0;
199 delete m_ftp; 123 delete m_ftp;
200 m_ftp = 0; 124 m_ftp = 0;
201 delete m_progressDialog; 125 delete m_progressDialog;
202 m_progressDialog = 0; 126 m_progressDialog = 0;
203 delete m_localFile; 127 delete m_localFile;
204 m_localFile = 0; 128 m_localFile = 0;
129 }
130
131 bool
132 RemoteFile::canHandleScheme(QUrl url)
133 {
134 QString scheme = url.scheme().toLower();
135 return (scheme == "http" || scheme == "ftp");
136 }
137
138 bool
139 RemoteFile::isAvailable()
140 {
141 while (m_ok && (!m_done && m_lastStatus == 0)) {
142 QApplication::processEvents();
143 }
144 bool available = true;
145 if (!m_ok) available = false;
146 else available = (m_lastStatus / 100 == 2);
147 std::cerr << "RemoteFile::isAvailable: " << (available ? "yes" : "no")
148 << std::endl;
149 return available;
150 }
151
152 void
153 RemoteFile::wait()
154 {
155 while (m_ok && !m_done) {
156 QApplication::processEvents();
157 }
158 }
159
160 bool
161 RemoteFile::isOK() const
162 {
163 return m_ok;
164 }
165
166 bool
167 RemoteFile::isDone() const
168 {
169 return m_done;
170 }
171
172 QString
173 RemoteFile::getLocalFilename() const
174 {
175 return m_localFilename;
176 }
177
178 QString
179 RemoteFile::getErrorString() const
180 {
181 return m_errorString;
182 }
183
184 void
185 RemoteFile::dataReadProgress(int done, int total)
186 {
187 dataTransferProgress(done, total);
188 }
189
190 void
191 RemoteFile::responseHeaderReceived(const QHttpResponseHeader &resp)
192 {
193 m_lastStatus = resp.statusCode();
194 if (m_lastStatus / 100 >= 4) {
195 m_errorString = QString("%1 %2")
196 .arg(resp.statusCode()).arg(resp.reasonPhrase());
197 std::cerr << "RemoteFile::responseHeaderReceived: "
198 << m_errorString.toStdString() << std::endl;
199 } else {
200 std::cerr << "RemoteFile::responseHeaderReceived: "
201 << m_lastStatus << std::endl;
202 }
203 }
204
205 void
206 RemoteFile::dataTransferProgress(qint64 done, qint64 total)
207 {
208 if (!m_progressDialog) return;
209
210 int percent = int((double(done) / double(total)) * 100.0 - 0.1);
211 emit progress(percent);
212
213 if (percent > 0) {
214 m_progressDialog->setValue(percent);
215 m_progressDialog->show();
216 }
217 }
218
219 void
220 RemoteFile::cancelled()
221 {
222 deleteLocalFile();
205 m_done = true; 223 m_done = true;
206 m_ok = false; 224 m_ok = false;
207 m_errorString = tr("Download cancelled"); 225 m_errorString = tr("Download cancelled");
208 } 226 }
209 227
210 void 228 void
211 RemoteFile::done(bool error) 229 RemoteFile::done(bool error)
212 { 230 {
231 // std::cerr << "RemoteFile::done(" << error << ")" << std::endl;
232
233 if (m_done) return;
234
213 emit progress(100); 235 emit progress(100);
214 m_ok = !error;
215 236
216 if (error) { 237 if (error) {
217 if (m_http) { 238 if (m_http) {
218 m_errorString = m_http->errorString(); 239 m_errorString = m_http->errorString();
219 } else if (m_ftp) { 240 } else if (m_ftp) {
220 m_errorString = m_ftp->errorString(); 241 m_errorString = m_ftp->errorString();
221 } 242 }
222 } 243 }
223 244
224 if (m_lastStatus / 100 >= 4) { 245 if (m_lastStatus / 100 >= 4) {
225 m_ok = false; 246 error = true;
226 } 247 }
227 248
228 delete m_localFile; 249 cleanup();
229 m_localFile = 0; 250
230 251 if (!error) {
231 delete m_progressDialog;
232 m_progressDialog = 0;
233
234 if (m_ok) {
235 QFileInfo fi(m_localFilename); 252 QFileInfo fi(m_localFilename);
236 if (!fi.exists()) { 253 if (!fi.exists()) {
237 m_errorString = tr("Failed to create local file %1").arg(m_localFilename); 254 m_errorString = tr("Failed to create local file %1").arg(m_localFilename);
238 m_ok = false; 255 error = true;
239 } else if (fi.size() == 0) { 256 } else if (fi.size() == 0) {
240 m_errorString = tr("File contains no data!"); 257 m_errorString = tr("File contains no data!");
241 m_ok = false; 258 error = true;
242 } 259 }
243 } 260 }
261
262 if (error) {
263 deleteLocalFile();
264 }
265
266 m_ok = !error;
267 m_done = true;
268 }
269
270 void
271 RemoteFile::deleteLocalFile()
272 {
273 // std::cerr << "RemoteFile::deleteLocalFile" << std::endl;
274
275 cleanup();
276
277 if (m_localFilename == "") return;
278
279 m_fileCreationMutex.lock();
280
281 if (!QFile(m_localFilename).remove()) {
282 std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl;
283 } else {
284 m_localFilename = "";
285 }
286
287 m_fileCreationMutex.unlock();
288
244 m_done = true; 289 m_done = true;
245 } 290 }
246 291
247 void 292 void
248 RemoteFile::showProgressDialog() 293 RemoteFile::showProgressDialog()
251 } 296 }
252 297
253 QString 298 QString
254 RemoteFile::createLocalFile(QUrl url) 299 RemoteFile::createLocalFile(QUrl url)
255 { 300 {
256 //!!! should we actually put up dialogs for these errors? or propagate an exception?
257
258 QDir dir; 301 QDir dir;
259 try { 302 try {
260 dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); 303 dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
261 } catch (DirectoryCreationFailed f) { 304 } catch (DirectoryCreationFailed f) {
262 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; 305 std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;