17 #include "data/fileio/FileSource.h" 18 #include "data/fileio/AudioFileReaderFactory.h" 19 #include "data/fileio/DataFileReaderFactory.h" 20 #include "rdf/RDFImporter.h" 21 #include "rdf/RDFExporter.h" 22 #include "system/System.h" 25 #include <QMessageBox> 26 #include <QFileDialog> 27 #include <QInputDialog> 28 #include <QImageReader> 37 m_sessionExtension(
"sv"),
38 m_lastLocatedLocation(
""),
41 FileFinder::registerFileFinder(
this);
62 QString fallbackLocation)
67 if (names.empty())
return "";
73 QString fallbackLocation)
82 QString fallbackLocation,
85 QString settingsKeyStub;
86 QString lastPath = fallbackLocation;
90 title = tr(
"Select one or more files");
92 title = tr(
"Select file");
94 QString filter = tr(
"All files (*.*)");
101 settingsKeyStub =
"session";
103 title = tr(
"Select one or more session files");
105 title = tr(
"Select a session file");
107 filter = tr(
"%1 session files (*.%2)\nRDF files (%3)\nAll files (*.*)")
108 .arg(QApplication::applicationName())
110 .arg(RDFImporter::getKnownExtensions());
114 settingsKeyStub =
"audio";
116 title = tr(
"Select one or more audio files");
118 title = tr(
"Select an audio file");
120 filter = tr(
"Audio files (%1)\nAll files (*.*)")
121 .arg(AudioFileReaderFactory::getKnownExtensions());
125 settingsKeyStub =
"layer";
126 filter = tr(
"All supported files (%1 %2)\nSonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nRDF files (%2)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)")
127 .arg(DataFileReaderFactory::getKnownExtensions())
128 .arg(RDFImporter::getKnownExtensions());
131 case LayerFileNoMidi:
132 settingsKeyStub =
"layer";
133 filter = tr(
"All supported files (%1 %2)\nSonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nRDF files (%2)\nText files (*.txt)\nAll files (*.*)")
134 .arg(DataFileReaderFactory::getKnownExtensions())
135 .arg(RDFImporter::getKnownExtensions());
139 settingsKeyStub =
"layer";
140 filter = tr(
"All supported files (%1 %2)\nComma-separated data files (*.csv)\nSonic Visualiser Layer XML files (*.svl)\nSpace-separated .lab files (*.lab)\nRDF files (%2)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)")
141 .arg(DataFileReaderFactory::getKnownExtensions())
142 .arg(RDFImporter::getKnownExtensions());
145 case LayerFileNoMidiNonSV:
146 settingsKeyStub =
"layer";
147 filter = tr(
"All supported files (%1 %2)\nComma-separated data files (*.csv)\nSonic Visualiser Layer XML files (*.svl)\nSpace-separated .lab files (*.lab)\nRDF files (%2)\nText files (*.txt)\nAll files (*.*)")
148 .arg(DataFileReaderFactory::getKnownExtensions())
149 .arg(RDFImporter::getKnownExtensions());
152 case SessionOrAudioFile:
153 settingsKeyStub =
"last";
154 filter = tr(
"All supported files (*.%1 %2 %3)\n%4 session files (*.%1)\nAudio files (%3)\nRDF files (%2)\nAll files (*.*)")
156 .arg(RDFImporter::getKnownExtensions())
157 .arg(AudioFileReaderFactory::getKnownExtensions())
158 .arg(QApplication::applicationName());
162 settingsKeyStub =
"image";
165 QList<QByteArray> formats = QImageReader::supportedImageFormats();
166 for (QList<QByteArray>::iterator i = formats.begin();
167 i != formats.end(); ++i) {
168 fmts.push_back(QString(
"*.%1")
169 .arg(QString::fromLocal8Bit(*i).toLower()));
171 filter = tr(
"Image files (%1)\nAll files (*.*)").arg(fmts.join(
" "));
176 settingsKeyStub =
"svg";
177 filter = tr(
"Scalable Vector Graphics files (*.svg)\nAll files (*.*)");
181 settingsKeyStub =
"layer";
182 filter = tr(
"Comma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nText files (*.txt)\nAll files (*.*)");
186 settingsKeyStub =
"last";
187 filter = tr(
"All supported files (*.%1 %2 %3 %4)\n%5 session files (*.%1)\nAudio files (%2)\nLayer files (%3)\nRDF files (%4)\nAll files (*.*)")
189 .arg(AudioFileReaderFactory::getKnownExtensions())
190 .arg(DataFileReaderFactory::getKnownExtensions())
191 .arg(RDFImporter::getKnownExtensions())
192 .arg(QApplication::applicationName());
196 if (lastPath ==
"") {
198 if (getEnvUtf8(
"HOME", home)) {
199 lastPath = QString::fromStdString(home);
203 }
else if (QFileInfo(lastPath).isDir()) {
204 lastPath = QFileInfo(lastPath).canonicalPath();
206 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
210 settings.beginGroup(
"FileFinder");
211 lastPath = settings.value(settingsKeyStub +
"path", lastPath).toString();
216 dialog.setNameFilters(filter.split(
'\n'));
217 dialog.setWindowTitle(title);
218 dialog.setDirectory(lastPath);
220 dialog.setAcceptMode(QFileDialog::AcceptOpen);
223 dialog.setFileMode(QFileDialog::ExistingFiles);
225 dialog.setFileMode(QFileDialog::ExistingFile);
228 QString testPath =
"";
229 QString pathToRemember =
"";
232 names = dialog.selectedFiles();
234 if (!multiple && !names.empty()) {
235 testPath = *names.begin();
236 QFileInfo fi(testPath);
239 QMessageBox::critical(
nullptr, tr(
"File does not exist"),
240 tr(
"<b>File not found</b><p>File \"%1\" does not exist").arg(testPath));
242 }
else if (!fi.isReadable()) {
244 QMessageBox::critical(
nullptr, tr(
"File is not readable"),
245 tr(
"<b>File is not readable</b><p>File \"%1\" can not be read").arg(testPath));
247 }
else if (fi.isDir()) {
249 QMessageBox::critical(
nullptr, tr(
"Directory selected"),
250 tr(
"<b>Directory selected</b><p>File \"%1\" is a directory").arg(testPath));
252 }
else if (!fi.isFile()) {
254 QMessageBox::critical(
nullptr, tr(
"Non-file selected"),
255 tr(
"<b>Not a file</b><p>Path \"%1\" is not a file").arg(testPath));
257 }
else if (fi.size() == 0) {
259 QMessageBox::critical(
nullptr, tr(
"File is empty"),
260 tr(
"<b>File is empty</b><p>File \"%1\" is empty").arg(testPath));
263 pathToRemember = testPath;
268 if (pathToRemember !=
"") {
269 settings.setValue(settingsKeyStub +
"path",
270 QFileInfo(pathToRemember)
280 QString fallbackLocation)
282 QString settingsKeyStub;
283 QString lastPath = fallbackLocation;
285 QString title = tr(
"Select file");
286 QString filter = tr(
"All files (*.*)");
291 settingsKeyStub =
"savesession";
292 title = tr(
"Select a session file");
293 filter = tr(
"%1 session files (*.%2)\nAll files (*.*)")
294 .arg(QApplication::applicationName())
299 settingsKeyStub =
"saveaudio";
300 title =
"Select an audio file";
301 title = tr(
"Select a file to export to");
302 filter = tr(
"WAV audio files (*.wav)\nAll files (*.*)");
306 settingsKeyStub =
"savelayer";
307 title = tr(
"Select a file to export to");
308 filter = tr(
"Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nRDF/Turtle files (%1)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)")
309 .arg(RDFExporter::getSupportedExtensions());
312 case LayerFileNoMidi:
313 settingsKeyStub =
"savelayer";
314 title = tr(
"Select a file to export to");
315 filter = tr(
"Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nRDF/Turtle files (%1)\nText files (*.txt)\nAll files (*.*)")
316 .arg(RDFExporter::getSupportedExtensions());
320 settingsKeyStub =
"savelayer";
321 title = tr(
"Select a file to export to");
322 filter = tr(
"Comma-separated data files (*.csv)\nSonic Visualiser Layer XML files (*.svl)\nRDF/Turtle files (%1)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)")
323 .arg(RDFExporter::getSupportedExtensions());
326 case LayerFileNoMidiNonSV:
327 settingsKeyStub =
"savelayer";
328 title = tr(
"Select a file to export to");
329 filter = tr(
"Comma-separated data files (*.csv)\nSonic Visualiser Layer XML files (*.svl)\nRDF/Turtle files (%1)\nText files (*.txt)\nAll files (*.*)")
330 .arg(RDFExporter::getSupportedExtensions());
333 case SessionOrAudioFile:
334 cerr <<
"ERROR: Internal error: InteractiveFileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << endl;
338 settingsKeyStub =
"saveimage";
339 title = tr(
"Select a file to export to");
340 filter = tr(
"Portable Network Graphics files (*.png)\nAll files (*.*)");
344 settingsKeyStub =
"savesvg";
345 title = tr(
"Select a file to export to");
346 filter = tr(
"Scalable Vector Graphics files (*.svg)\nAll files (*.*)");
350 settingsKeyStub =
"savelayer";
351 title = tr(
"Select a file to export to");
352 filter = tr(
"Comma-separated data files (*.csv)\nText files (*.txt)\nAll files (*.*)");
356 cerr <<
"ERROR: Internal error: InteractiveFileFinder::getSaveFileName: AnyFile cannot be used here" << endl;
360 if (lastPath ==
"") {
362 if (getEnvUtf8(
"HOME", home)) {
363 lastPath = QString::fromStdString(home);
367 }
else if (QFileInfo(lastPath).isDir()) {
368 lastPath = QFileInfo(lastPath).canonicalPath();
370 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
374 settings.beginGroup(
"FileFinder");
375 lastPath = settings.value(settingsKeyStub +
"path", lastPath).toString();
384 QStringList filters = filter.split(
'\n');
386 dialog.setNameFilters(filters);
387 dialog.setWindowTitle(title);
388 dialog.setDirectory(lastPath);
389 dialog.setAcceptMode(QFileDialog::AcceptSave);
390 dialog.setFileMode(QFileDialog::AnyFile);
391 dialog.setOption(QFileDialog::DontConfirmOverwrite,
true);
393 QString defaultSuffix;
394 if (type == SessionFile) {
396 }
else if (type == AudioFile) {
397 defaultSuffix =
"wav";
398 }
else if (type == ImageFile) {
399 defaultSuffix =
"png";
400 }
else if (type == SVGFile) {
401 defaultSuffix =
"svg";
402 }
else if (type == CSVFile) {
403 defaultSuffix =
"csv";
407 settings.value(settingsKeyStub +
"suffix", defaultSuffix).toString();
409 dialog.setDefaultSuffix(defaultSuffix);
411 foreach (QString f, filters) {
412 if (f.contains(
"." + defaultSuffix)) {
413 dialog.selectNameFilter(f);
423 if (!dialog.exec())
break;
425 QStringList files = dialog.selectedFiles();
426 if (files.empty())
break;
427 path = *files.begin();
431 cerr <<
"type = " << type <<
", suffix = " << fi.suffix() << endl;
433 if ((type == LayerFile || type == LayerFileNoMidi ||
434 type == LayerFileNonSV || type == LayerFileNoMidiNonSV)
435 && fi.suffix() ==
"") {
436 QString expectedExtension;
437 QString selectedFilter = dialog.selectedNameFilter();
438 if (selectedFilter.contains(
".svl")) {
439 expectedExtension =
"svl";
440 }
else if (selectedFilter.contains(
".txt")) {
441 expectedExtension =
"txt";
442 }
else if (selectedFilter.contains(
".csv")) {
443 expectedExtension =
"csv";
444 }
else if (selectedFilter.contains(
".mid")) {
445 expectedExtension =
"mid";
446 }
else if (selectedFilter.contains(
".ttl")) {
447 expectedExtension =
"ttl";
449 cerr <<
"expected extension = " << expectedExtension << endl;
450 if (expectedExtension !=
"") {
451 path = QString(
"%1.%2").arg(path).arg(expectedExtension);
452 fi = QFileInfo(path);
457 QMessageBox::critical(
nullptr, tr(
"Directory selected"),
458 tr(
"<b>Directory selected</b><p>File \"%1\" is a directory").arg(path));
463 if (QMessageBox::question(
nullptr, tr(
"File exists"),
464 tr(
"<b>File exists</b><p>The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path),
466 QMessageBox::Cancel) != QMessageBox::Ok) {
475 settings.setValue(settingsKeyStub +
"path",
476 QFileInfo(path).absoluteDir().canonicalPath());
477 settings.setValue(settingsKeyStub +
"suffix",
478 QFileInfo(path).suffix());
487 QString settingsKeyStub;
491 settingsKeyStub =
"session";
495 settingsKeyStub =
"audio";
499 settingsKeyStub =
"layer";
502 case LayerFileNoMidi:
503 settingsKeyStub =
"layer";
507 settingsKeyStub =
"layer";
510 case LayerFileNoMidiNonSV:
511 settingsKeyStub =
"layer";
514 case SessionOrAudioFile:
515 settingsKeyStub =
"last";
519 settingsKeyStub =
"image";
523 settingsKeyStub =
"svg";
527 settingsKeyStub =
"layer";
531 settingsKeyStub =
"last";
537 settings.beginGroup(
"FileFinder");
538 path = QFileInfo(path).absoluteDir().canonicalPath();
539 QString suffix = QFileInfo(path).suffix();
540 settings.setValue(settingsKeyStub +
"path", path);
541 settings.setValue(settingsKeyStub +
"suffix", suffix);
542 settings.setValue(
"lastpath", path);
549 if (FileSource::canHandleScheme(location)) {
550 if (FileSource(location).isAvailable()) {
551 SVDEBUG <<
"InteractiveFileFinder::find: ok, it's available... returning" << endl;
556 if (QFileInfo(location).exists())
return location;
558 QString foundAt =
"";
560 if ((foundAt =
findRelative(location, lastKnownLocation)) !=
"") {
574 if (relativeTo ==
"")
return "";
576 SVDEBUG <<
"Looking for \"" << location <<
"\" next to \"" 577 << relativeTo <<
"\"..." << endl;
582 if (FileSource::isRemote(location)) {
583 fileName = QUrl(location).path().section(
'/', -1, -1,
584 QString::SectionSkipEmpty);
586 if (QUrl(location).scheme() ==
"file") {
587 location = QUrl(location).toLocalFile();
589 fileName = QFileInfo(location).fileName();
592 if (FileSource::isRemote(relativeTo)) {
593 resolved = QUrl(relativeTo).resolved(fileName).toString();
594 if (!FileSource(resolved).isAvailable()) resolved =
"";
595 cerr <<
"resolved: " << resolved << endl;
597 if (QUrl(relativeTo).scheme() ==
"file") {
598 relativeTo = QUrl(relativeTo).toLocalFile();
600 resolved = QFileInfo(relativeTo).dir().filePath(fileName);
601 if (!QFileInfo(resolved).exists() ||
602 !QFileInfo(resolved).isFile() ||
603 !QFileInfo(resolved).isReadable()) {
615 if (type == AudioFile) {
616 question = tr(
"<b>File not found</b><p>Audio file \"%1\" could not be opened.\nDo you want to locate it?");
618 question = tr(
"<b>File not found</b><p>File \"%1\" could not be opened.\nDo you want to locate it?");
626 int rv = QMessageBox::question
628 tr(
"Failed to open file"),
630 tr(
"Locate file..."),
639 if (QFileInfo(thing).dir().exists()) {
640 path = QFileInfo(thing).dir().canonicalPath();
650 path = QInputDialog::getText
651 (
nullptr, tr(
"Use URL"),
652 tr(
"Please enter the URL to use for this file:"),
653 QLineEdit::Normal,
"", &ok);
655 if (ok && path !=
"") {
656 if (FileSource(path).isAvailable()) {
659 QMessageBox::critical
660 (
nullptr, tr(
"Failed to open location"),
661 tr(
"<b>Failed to open location</b><p>URL \"%1\" could not be opened").arg(path));
static void setParentWidget(QWidget *)
void registerLastOpenedFilePath(FileType type, QString path) override
QString m_lastLocatedLocation
QString locateInteractive(FileType type, QString thing)
QString getSaveFileName(FileType type, QString fallbackLocation="") override
void setApplicationSessionExtension(QString extension)
Specify the extension for this application's session files (without the dot)
virtual ~InteractiveFileFinder()
QString getOpenFileName(FileType type, QString fallbackLocation="") override
QString find(FileType type, QString location, QString lastKnownLocation="") override
QStringList getOpenFileNames(FileType type, QString fallbackLocation="") override
QString findRelative(QString location, QString relativeTo)
static InteractiveFileFinder m_instance
QString m_sessionExtension
static InteractiveFileFinder * getInstance()