Mercurial > hg > easaier-soundaccess
comparison data/fileio/FileFinder.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children | 00b5875d8c30 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2007 QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "FileFinder.h" | |
17 #include "RemoteFile.h" | |
18 #include "AudioFileReaderFactory.h" | |
19 #include "DataFileReaderFactory.h" | |
20 | |
21 #include <QFileInfo> | |
22 #include <QMessageBox> | |
23 #include <QFileDialog> | |
24 #include <QInputDialog> | |
25 #include <QSettings> | |
26 | |
27 #include <iostream> | |
28 | |
29 FileFinder * | |
30 FileFinder::m_instance = 0; | |
31 | |
32 FileFinder::FileFinder() : | |
33 m_lastLocatedLocation("") | |
34 { | |
35 } | |
36 | |
37 FileFinder::~FileFinder() | |
38 { | |
39 } | |
40 | |
41 FileFinder * | |
42 FileFinder::getInstance() | |
43 { | |
44 if (m_instance == 0) { | |
45 m_instance = new FileFinder(); | |
46 } | |
47 return m_instance; | |
48 } | |
49 | |
50 QString | |
51 FileFinder::getOpenFileName(FileType type, QString fallbackLocation) | |
52 { | |
53 QString settingsKey; | |
54 QString lastPath = fallbackLocation; | |
55 | |
56 QString title = tr("Select file"); | |
57 QString filter = tr("All files (*.*)"); | |
58 | |
59 switch (type) { | |
60 | |
61 case SessionFile: | |
62 settingsKey = "sessionpath"; | |
63 title = tr("Select a session file"); | |
64 filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)"); | |
65 break; | |
66 | |
67 case AudioFile: | |
68 settingsKey = "audiopath"; | |
69 title = "Select an audio file"; | |
70 filter = tr("Audio files (%1)\nAll files (*.*)") | |
71 .arg(AudioFileReaderFactory::getKnownExtensions()); | |
72 break; | |
73 | |
74 case LayerFile: | |
75 settingsKey = "layerpath"; | |
76 filter = tr("All supported files (%1)\nSonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)").arg(DataFileReaderFactory::getKnownExtensions()); | |
77 break; | |
78 | |
79 case SessionOrAudioFile: | |
80 settingsKey = "lastpath"; | |
81 filter = tr("All supported files (*.sv %1)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nAll files (*.*)") | |
82 .arg(AudioFileReaderFactory::getKnownExtensions()); | |
83 break; | |
84 | |
85 case ImageFile: | |
86 settingsKey = "imagepath"; | |
87 filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)"); | |
88 break; | |
89 | |
90 case AnyFile: | |
91 settingsKey = "lastpath"; | |
92 filter = tr("All supported files (*.sv %1 %2)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nLayer files (%2)\nAll files (*.*)") | |
93 .arg(AudioFileReaderFactory::getKnownExtensions()) | |
94 .arg(DataFileReaderFactory::getKnownExtensions()); | |
95 break; | |
96 }; | |
97 | |
98 if (lastPath == "") { | |
99 char *home = getenv("HOME"); | |
100 if (home) lastPath = home; | |
101 else lastPath = "."; | |
102 } else if (QFileInfo(lastPath).isDir()) { | |
103 lastPath = QFileInfo(lastPath).canonicalPath(); | |
104 } else { | |
105 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); | |
106 } | |
107 | |
108 QSettings settings; | |
109 settings.beginGroup("FileFinder"); | |
110 lastPath = settings.value(settingsKey, lastPath).toString(); | |
111 | |
112 QString path = ""; | |
113 | |
114 // Use our own QFileDialog just for symmetry with getSaveFileName below | |
115 | |
116 QFileDialog dialog; | |
117 dialog.setFilters(filter.split('\n')); | |
118 dialog.setWindowTitle(title); | |
119 dialog.setDirectory(lastPath); | |
120 | |
121 dialog.setAcceptMode(QFileDialog::AcceptOpen); | |
122 dialog.setFileMode(QFileDialog::ExistingFile); | |
123 | |
124 if (dialog.exec()) { | |
125 QStringList files = dialog.selectedFiles(); | |
126 if (!files.empty()) path = *files.begin(); | |
127 | |
128 QFileInfo fi(path); | |
129 | |
130 if (!fi.exists()) { | |
131 | |
132 QMessageBox::critical(0, tr("File does not exist"), | |
133 tr("File \"%1\" does not exist").arg(path)); | |
134 path = ""; | |
135 | |
136 } else if (!fi.isReadable()) { | |
137 | |
138 QMessageBox::critical(0, tr("File is not readable"), | |
139 tr("File \"%1\" can not be read").arg(path)); | |
140 path = ""; | |
141 | |
142 } else if (fi.isDir()) { | |
143 | |
144 QMessageBox::critical(0, tr("Directory selected"), | |
145 tr("File \"%1\" is a directory").arg(path)); | |
146 path = ""; | |
147 | |
148 } else if (!fi.isFile()) { | |
149 | |
150 QMessageBox::critical(0, tr("Non-file selected"), | |
151 tr("Path \"%1\" is not a file").arg(path)); | |
152 path = ""; | |
153 | |
154 } else if (fi.size() == 0) { | |
155 | |
156 QMessageBox::critical(0, tr("File is empty"), | |
157 tr("File \"%1\" is empty").arg(path)); | |
158 path = ""; | |
159 } | |
160 } | |
161 | |
162 if (path != "") { | |
163 settings.setValue(settingsKey, | |
164 QFileInfo(path).absoluteDir().canonicalPath()); | |
165 } | |
166 | |
167 return path; | |
168 } | |
169 | |
170 QString | |
171 FileFinder::getSaveFileName(FileType type, QString fallbackLocation) | |
172 { | |
173 QString settingsKey; | |
174 QString lastPath = fallbackLocation; | |
175 | |
176 QString title = tr("Select file"); | |
177 QString filter = tr("All files (*.*)"); | |
178 | |
179 switch (type) { | |
180 | |
181 case SessionFile: | |
182 settingsKey = "savesessionpath"; | |
183 title = tr("Select a session file"); | |
184 filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)"); | |
185 break; | |
186 | |
187 case AudioFile: | |
188 settingsKey = "saveaudiopath"; | |
189 title = "Select an audio file"; | |
190 title = tr("Select a file to export to"); | |
191 filter = tr("WAV audio files (*.wav)\nAll files (*.*)"); | |
192 break; | |
193 | |
194 case LayerFile: | |
195 settingsKey = "savelayerpath"; | |
196 title = tr("Select a file to export to"); | |
197 filter = tr("Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nText files (*.txt)\nAll files (*.*)"); | |
198 break; | |
199 | |
200 case SessionOrAudioFile: | |
201 std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << std::endl; | |
202 abort(); | |
203 | |
204 case ImageFile: | |
205 settingsKey = "saveimagepath"; | |
206 title = tr("Select a file to export to"); | |
207 filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)"); | |
208 break; | |
209 | |
210 case AnyFile: | |
211 std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: AnyFile cannot be used here" << std::endl; | |
212 abort(); | |
213 }; | |
214 | |
215 if (lastPath == "") { | |
216 char *home = getenv("HOME"); | |
217 if (home) lastPath = home; | |
218 else lastPath = "."; | |
219 } else if (QFileInfo(lastPath).isDir()) { | |
220 lastPath = QFileInfo(lastPath).canonicalPath(); | |
221 } else { | |
222 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); | |
223 } | |
224 | |
225 QSettings settings; | |
226 settings.beginGroup("FileFinder"); | |
227 lastPath = settings.value(settingsKey, lastPath).toString(); | |
228 | |
229 QString path = ""; | |
230 | |
231 // Use our own QFileDialog instead of static functions, as we may | |
232 // need to adjust the file extension based on the selected filter | |
233 | |
234 QFileDialog dialog; | |
235 dialog.setFilters(filter.split('\n')); | |
236 dialog.setWindowTitle(title); | |
237 dialog.setDirectory(lastPath); | |
238 | |
239 dialog.setAcceptMode(QFileDialog::AcceptSave); | |
240 dialog.setFileMode(QFileDialog::AnyFile); | |
241 dialog.setConfirmOverwrite(false); // we'll do that | |
242 | |
243 if (type == SessionFile) { | |
244 dialog.setDefaultSuffix("sv"); | |
245 } else if (type == AudioFile) { | |
246 dialog.setDefaultSuffix("wav"); | |
247 } else if (type == ImageFile) { | |
248 dialog.setDefaultSuffix("png"); | |
249 } | |
250 | |
251 bool good = false; | |
252 | |
253 while (!good) { | |
254 | |
255 path = ""; | |
256 | |
257 if (!dialog.exec()) break; | |
258 | |
259 QStringList files = dialog.selectedFiles(); | |
260 if (files.empty()) break; | |
261 path = *files.begin(); | |
262 | |
263 QFileInfo fi(path); | |
264 | |
265 if (type == LayerFile && fi.suffix() == "") { | |
266 QString expectedExtension; | |
267 QString selectedFilter = dialog.selectedFilter(); | |
268 if (selectedFilter.contains(".svl")) { | |
269 expectedExtension = "svl"; | |
270 } else if (selectedFilter.contains(".txt")) { | |
271 expectedExtension = "txt"; | |
272 } else if (selectedFilter.contains(".csv")) { | |
273 expectedExtension = "csv"; | |
274 } | |
275 if (expectedExtension != "") { | |
276 path = QString("%1.%2").arg(path).arg(expectedExtension); | |
277 fi = QFileInfo(path); | |
278 } | |
279 } | |
280 | |
281 if (fi.isDir()) { | |
282 QMessageBox::critical(0, tr("Directory selected"), | |
283 tr("File \"%1\" is a directory").arg(path)); | |
284 continue; | |
285 } | |
286 | |
287 if (fi.exists()) { | |
288 if (QMessageBox::question(0, tr("File exists"), | |
289 tr("The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path), | |
290 QMessageBox::Ok, | |
291 QMessageBox::Cancel) != QMessageBox::Ok) { | |
292 continue; | |
293 } | |
294 } | |
295 | |
296 good = true; | |
297 } | |
298 | |
299 if (path != "") { | |
300 settings.setValue(settingsKey, | |
301 QFileInfo(path).absoluteDir().canonicalPath()); | |
302 } | |
303 | |
304 return path; | |
305 } | |
306 | |
307 void | |
308 FileFinder::registerLastOpenedFilePath(FileType type, QString path) | |
309 { | |
310 QString settingsKey; | |
311 | |
312 switch (type) { | |
313 case SessionFile: | |
314 settingsKey = "sessionpath"; | |
315 break; | |
316 | |
317 case AudioFile: | |
318 settingsKey = "audiopath"; | |
319 break; | |
320 | |
321 case LayerFile: | |
322 settingsKey = "layerpath"; | |
323 break; | |
324 | |
325 case SessionOrAudioFile: | |
326 settingsKey = "lastpath"; | |
327 break; | |
328 | |
329 case ImageFile: | |
330 settingsKey = "imagepath"; | |
331 break; | |
332 | |
333 case AnyFile: | |
334 settingsKey = "lastpath"; | |
335 break; | |
336 } | |
337 | |
338 if (path != "") { | |
339 QSettings settings; | |
340 settings.beginGroup("FileFinder"); | |
341 path = QFileInfo(path).absoluteDir().canonicalPath(); | |
342 settings.setValue(settingsKey, path); | |
343 settings.setValue("lastpath", path); | |
344 } | |
345 } | |
346 | |
347 QString | |
348 FileFinder::find(FileType type, QString location, QString lastKnownLocation) | |
349 { | |
350 if (QFileInfo(location).exists()) return location; | |
351 | |
352 if (RemoteFile::canHandleScheme(QUrl(location))) { | |
353 RemoteFile rf(location); | |
354 bool available = rf.isAvailable(); | |
355 rf.deleteLocalFile(); | |
356 if (available) return location; | |
357 } | |
358 | |
359 QString foundAt = ""; | |
360 | |
361 if ((foundAt = findRelative(location, lastKnownLocation)) != "") { | |
362 return foundAt; | |
363 } | |
364 | |
365 if ((foundAt = findRelative(location, m_lastLocatedLocation)) != "") { | |
366 return foundAt; | |
367 } | |
368 | |
369 return locateInteractive(type, location); | |
370 } | |
371 | |
372 QString | |
373 FileFinder::findRelative(QString location, QString relativeTo) | |
374 { | |
375 if (relativeTo == "") return ""; | |
376 | |
377 std::cerr << "Looking for \"" << location.toStdString() << "\" next to \"" | |
378 << relativeTo.toStdString() << "\"..." << std::endl; | |
379 | |
380 QString fileName; | |
381 QString resolved; | |
382 | |
383 if (RemoteFile::canHandleScheme(QUrl(location))) { | |
384 fileName = QUrl(location).path().section('/', -1, -1, | |
385 QString::SectionSkipEmpty); | |
386 } else { | |
387 fileName = QFileInfo(location).fileName(); | |
388 } | |
389 | |
390 if (RemoteFile::canHandleScheme(QUrl(relativeTo))) { | |
391 resolved = QUrl(relativeTo).resolved(fileName).toString(); | |
392 RemoteFile rf(resolved); | |
393 if (!rf.isAvailable()) resolved = ""; | |
394 std::cerr << "resolved: " << resolved.toStdString() << std::endl; | |
395 rf.deleteLocalFile(); | |
396 } else { | |
397 resolved = QFileInfo(relativeTo).dir().filePath(fileName); | |
398 if (!QFileInfo(resolved).exists() || | |
399 !QFileInfo(resolved).isFile() || | |
400 !QFileInfo(resolved).isReadable()) { | |
401 resolved = ""; | |
402 } | |
403 } | |
404 | |
405 return resolved; | |
406 } | |
407 | |
408 QString | |
409 FileFinder::locateInteractive(FileType type, QString thing) | |
410 { | |
411 QString question; | |
412 if (type == AudioFile) { | |
413 question = tr("Audio file \"%1\" could not be opened.\nDo you want to locate it?"); | |
414 } else { | |
415 question = tr("File \"%1\" could not be opened.\nDo you want to locate it?"); | |
416 } | |
417 | |
418 QString path = ""; | |
419 bool done = false; | |
420 | |
421 while (!done) { | |
422 | |
423 int rv = QMessageBox::question | |
424 (0, | |
425 tr("Failed to open file"), | |
426 question.arg(thing), | |
427 tr("Locate file..."), | |
428 tr("Use URL..."), | |
429 tr("Cancel"), | |
430 0, 2); | |
431 | |
432 switch (rv) { | |
433 | |
434 case 0: // Locate file | |
435 | |
436 if (QFileInfo(thing).dir().exists()) { | |
437 path = QFileInfo(thing).dir().canonicalPath(); | |
438 } | |
439 | |
440 path = getOpenFileName(type, path); | |
441 done = (path != ""); | |
442 break; | |
443 | |
444 case 1: // Use URL | |
445 { | |
446 bool ok = false; | |
447 path = QInputDialog::getText | |
448 (0, tr("Use URL"), | |
449 tr("Please enter the URL to use for this file:"), | |
450 QLineEdit::Normal, "", &ok); | |
451 | |
452 if (ok && path != "") { | |
453 RemoteFile rf(path); | |
454 if (rf.isAvailable()) { | |
455 done = true; | |
456 } else { | |
457 QMessageBox::critical | |
458 (0, tr("Failed to open location"), | |
459 tr("URL \"%1\" could not be opened").arg(path)); | |
460 path = ""; | |
461 } | |
462 rf.deleteLocalFile(); | |
463 } | |
464 break; | |
465 } | |
466 | |
467 case 2: // Cancel | |
468 path = ""; | |
469 done = true; | |
470 break; | |
471 } | |
472 } | |
473 | |
474 if (path != "") m_lastLocatedLocation = path; | |
475 return path; | |
476 } | |
477 | |
478 |