00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "FileFinder.h"
00017 #include "FileSource.h"
00018 #include "AudioFileReaderFactory.h"
00019 #include "DataFileReaderFactory.h"
00020
00021 #include <QFileInfo>
00022 #include <QMessageBox>
00023 #include <QFileDialog>
00024 #include <QInputDialog>
00025 #include <QImageReader>
00026 #include <QSettings>
00027
00028 #include <iostream>
00029
00030 FileFinder *
00031 FileFinder::m_instance = 0;
00032
00033 FileFinder::FileFinder() :
00034 m_lastLocatedLocation("")
00035 {
00036 }
00037
00038 FileFinder::~FileFinder()
00039 {
00040 }
00041
00042 FileFinder *
00043 FileFinder::getInstance()
00044 {
00045 if (m_instance == 0) {
00046 m_instance = new FileFinder();
00047 }
00048 return m_instance;
00049 }
00050
00051 QString
00052 FileFinder::getOpenFileName(FileType type, QString fallbackLocation)
00053 {
00054 QString settingsKey;
00055 QString lastPath = fallbackLocation;
00056
00057 QString title = tr("Select file");
00058 QString filter = tr("All files (*.*)");
00059
00060 switch (type) {
00061
00062 case SessionFile:
00063 settingsKey = "sessionpath";
00064 title = tr("Select a session file");
00065 filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)");
00066 break;
00067
00068 case AudioFile:
00069 settingsKey = "audiopath";
00070 title = "Select an audio file";
00071 filter = tr("Audio files (%1)\nAll files (*.*)")
00072 .arg(AudioFileReaderFactory::getKnownExtensions());
00073 break;
00074
00075 case LayerFile:
00076 settingsKey = "layerpath";
00077 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());
00078 break;
00079
00080 case LayerFileNoMidi:
00081 settingsKey = "layerpath";
00082 filter = tr("All supported files (%1)\nSonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nText files (*.txt)\nAll files (*.*)").arg(DataFileReaderFactory::getKnownExtensions());
00083 break;
00084
00085 case SessionOrAudioFile:
00086 settingsKey = "lastpath";
00087 filter = tr("All supported files (*.sv %1)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nAll files (*.*)")
00088 .arg(AudioFileReaderFactory::getKnownExtensions());
00089 break;
00090
00091 case ImageFile:
00092 settingsKey = "imagepath";
00093 {
00094 QStringList fmts;
00095 QList<QByteArray> formats = QImageReader::supportedImageFormats();
00096 for (QList<QByteArray>::iterator i = formats.begin();
00097 i != formats.end(); ++i) {
00098 fmts.push_back(QString("*.%1")
00099 .arg(QString::fromLocal8Bit(*i).toLower()));
00100 }
00101 filter = tr("Image files (%1)\nAll files (*.*)").arg(fmts.join(" "));
00102 }
00103 break;
00104
00105 case AnyFile:
00106 settingsKey = "lastpath";
00107 filter = tr("All supported files (*.sv %1 %2)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nLayer files (%2)\nAll files (*.*)")
00108 .arg(AudioFileReaderFactory::getKnownExtensions())
00109 .arg(DataFileReaderFactory::getKnownExtensions());
00110 break;
00111 };
00112
00113 if (lastPath == "") {
00114 char *home = getenv("HOME");
00115 if (home) lastPath = home;
00116 else lastPath = ".";
00117 } else if (QFileInfo(lastPath).isDir()) {
00118 lastPath = QFileInfo(lastPath).canonicalPath();
00119 } else {
00120 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
00121 }
00122
00123 QSettings settings;
00124 settings.beginGroup("FileFinder");
00125 lastPath = settings.value(settingsKey, lastPath).toString();
00126
00127 QString path = "";
00128
00129
00130
00131 QFileDialog dialog;
00132 dialog.setFilters(filter.split('\n'));
00133 dialog.setWindowTitle(title);
00134 dialog.setDirectory(lastPath);
00135
00136 dialog.setAcceptMode(QFileDialog::AcceptOpen);
00137 dialog.setFileMode(QFileDialog::ExistingFile);
00138
00139 if (dialog.exec()) {
00140 QStringList files = dialog.selectedFiles();
00141 if (!files.empty()) path = *files.begin();
00142
00143 QFileInfo fi(path);
00144
00145 if (!fi.exists()) {
00146
00147 QMessageBox::critical(0, tr("File does not exist"),
00148 tr("File \"%1\" does not exist").arg(path));
00149 path = "";
00150
00151 } else if (!fi.isReadable()) {
00152
00153 QMessageBox::critical(0, tr("File is not readable"),
00154 tr("File \"%1\" can not be read").arg(path));
00155 path = "";
00156
00157 } else if (fi.isDir()) {
00158
00159 QMessageBox::critical(0, tr("Directory selected"),
00160 tr("File \"%1\" is a directory").arg(path));
00161 path = "";
00162
00163 } else if (!fi.isFile()) {
00164
00165 QMessageBox::critical(0, tr("Non-file selected"),
00166 tr("Path \"%1\" is not a file").arg(path));
00167 path = "";
00168
00169 } else if (fi.size() == 0) {
00170
00171 QMessageBox::critical(0, tr("File is empty"),
00172 tr("File \"%1\" is empty").arg(path));
00173 path = "";
00174 }
00175 }
00176
00177 if (path != "") {
00178 settings.setValue(settingsKey,
00179 QFileInfo(path).absoluteDir().canonicalPath());
00180 }
00181
00182 return path;
00183 }
00184
00185 QString
00186 FileFinder::getSaveFileName(FileType type, QString fallbackLocation)
00187 {
00188 QString settingsKey;
00189 QString lastPath = fallbackLocation;
00190
00191 QString title = tr("Select file");
00192 QString filter = tr("All files (*.*)");
00193
00194 switch (type) {
00195
00196 case SessionFile:
00197 settingsKey = "savesessionpath";
00198 title = tr("Select a session file");
00199 filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)");
00200 break;
00201
00202 case AudioFile:
00203 settingsKey = "saveaudiopath";
00204 title = "Select an audio file";
00205 title = tr("Select a file to export to");
00206 filter = tr("WAV audio files (*.wav)\nAll files (*.*)");
00207 break;
00208
00209 case LayerFile:
00210 settingsKey = "savelayerpath";
00211 title = tr("Select a file to export to");
00212 filter = tr("Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nMIDI files (*.mid)\nText files (*.txt)\nAll files (*.*)");
00213 break;
00214
00215 case LayerFileNoMidi:
00216 settingsKey = "savelayerpath";
00217 title = tr("Select a file to export to");
00218 filter = tr("Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nText files (*.txt)\nAll files (*.*)");
00219 break;
00220
00221 case SessionOrAudioFile:
00222 std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << std::endl;
00223 abort();
00224
00225 case ImageFile:
00226 settingsKey = "saveimagepath";
00227 title = tr("Select a file to export to");
00228 filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)");
00229 break;
00230
00231 case AnyFile:
00232 std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: AnyFile cannot be used here" << std::endl;
00233 abort();
00234 };
00235
00236 if (lastPath == "") {
00237 char *home = getenv("HOME");
00238 if (home) lastPath = home;
00239 else lastPath = ".";
00240 } else if (QFileInfo(lastPath).isDir()) {
00241 lastPath = QFileInfo(lastPath).canonicalPath();
00242 } else {
00243 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
00244 }
00245
00246 QSettings settings;
00247 settings.beginGroup("FileFinder");
00248 lastPath = settings.value(settingsKey, lastPath).toString();
00249
00250 QString path = "";
00251
00252
00253
00254
00255 QFileDialog dialog;
00256 dialog.setFilters(filter.split('\n'));
00257 dialog.setWindowTitle(title);
00258 dialog.setDirectory(lastPath);
00259
00260 dialog.setAcceptMode(QFileDialog::AcceptSave);
00261 dialog.setFileMode(QFileDialog::AnyFile);
00262 dialog.setConfirmOverwrite(false);
00263
00264 if (type == SessionFile) {
00265 dialog.setDefaultSuffix("sv");
00266 } else if (type == AudioFile) {
00267 dialog.setDefaultSuffix("wav");
00268 } else if (type == ImageFile) {
00269 dialog.setDefaultSuffix("png");
00270 }
00271
00272 bool good = false;
00273
00274 while (!good) {
00275
00276 path = "";
00277
00278 if (!dialog.exec()) break;
00279
00280 QStringList files = dialog.selectedFiles();
00281 if (files.empty()) break;
00282 path = *files.begin();
00283
00284 QFileInfo fi(path);
00285
00286 std::cerr << "type = " << type << ", suffix = " << fi.suffix().toStdString() << std::endl;
00287
00288 if ((type == LayerFile || type == LayerFileNoMidi)
00289 && fi.suffix() == "") {
00290 QString expectedExtension;
00291 QString selectedFilter = dialog.selectedFilter();
00292 if (selectedFilter.contains(".svl")) {
00293 expectedExtension = "svl";
00294 } else if (selectedFilter.contains(".txt")) {
00295 expectedExtension = "txt";
00296 } else if (selectedFilter.contains(".csv")) {
00297 expectedExtension = "csv";
00298 } else if (selectedFilter.contains(".mid")) {
00299 expectedExtension = "mid";
00300 }
00301 std::cerr << "expected extension = " << expectedExtension.toStdString() << std::endl;
00302 if (expectedExtension != "") {
00303 path = QString("%1.%2").arg(path).arg(expectedExtension);
00304 fi = QFileInfo(path);
00305 }
00306 }
00307
00308 if (fi.isDir()) {
00309 QMessageBox::critical(0, tr("Directory selected"),
00310 tr("File \"%1\" is a directory").arg(path));
00311 continue;
00312 }
00313
00314 if (fi.exists()) {
00315 if (QMessageBox::question(0, tr("File exists"),
00316 tr("The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path),
00317 QMessageBox::Ok,
00318 QMessageBox::Cancel) != QMessageBox::Ok) {
00319 continue;
00320 }
00321 }
00322
00323 good = true;
00324 }
00325
00326 if (path != "") {
00327 settings.setValue(settingsKey,
00328 QFileInfo(path).absoluteDir().canonicalPath());
00329 }
00330
00331 return path;
00332 }
00333
00334 void
00335 FileFinder::registerLastOpenedFilePath(FileType type, QString path)
00336 {
00337 QString settingsKey;
00338
00339 switch (type) {
00340 case SessionFile:
00341 settingsKey = "sessionpath";
00342 break;
00343
00344 case AudioFile:
00345 settingsKey = "audiopath";
00346 break;
00347
00348 case LayerFile:
00349 settingsKey = "layerpath";
00350 break;
00351
00352 case LayerFileNoMidi:
00353 settingsKey = "layerpath";
00354 break;
00355
00356 case SessionOrAudioFile:
00357 settingsKey = "lastpath";
00358 break;
00359
00360 case ImageFile:
00361 settingsKey = "imagepath";
00362 break;
00363
00364 case AnyFile:
00365 settingsKey = "lastpath";
00366 break;
00367 }
00368
00369 if (path != "") {
00370 QSettings settings;
00371 settings.beginGroup("FileFinder");
00372 path = QFileInfo(path).absoluteDir().canonicalPath();
00373 settings.setValue(settingsKey, path);
00374 settings.setValue("lastpath", path);
00375 }
00376 }
00377
00378 QString
00379 FileFinder::find(FileType type, QString location, QString lastKnownLocation)
00380 {
00381 if (FileSource::canHandleScheme(location)) {
00382 if (FileSource(location).isAvailable()) {
00383 std::cerr << "FileFinder::find: ok, it's available... returning" << std::endl;
00384 return location;
00385 }
00386 }
00387
00388 if (QFileInfo(location).exists()) return location;
00389
00390 QString foundAt = "";
00391
00392 if ((foundAt = findRelative(location, lastKnownLocation)) != "") {
00393 return foundAt;
00394 }
00395
00396 if ((foundAt = findRelative(location, m_lastLocatedLocation)) != "") {
00397 return foundAt;
00398 }
00399
00400 return locateInteractive(type, location);
00401 }
00402
00403 QString
00404 FileFinder::findRelative(QString location, QString relativeTo)
00405 {
00406 if (relativeTo == "") return "";
00407
00408 std::cerr << "Looking for \"" << location.toStdString() << "\" next to \""
00409 << relativeTo.toStdString() << "\"..." << std::endl;
00410
00411 QString fileName;
00412 QString resolved;
00413
00414 if (FileSource::isRemote(location)) {
00415 fileName = QUrl(location).path().section('/', -1, -1,
00416 QString::SectionSkipEmpty);
00417 } else {
00418 if (QUrl(location).scheme() == "file") {
00419 location = QUrl(location).toLocalFile();
00420 }
00421 fileName = QFileInfo(location).fileName();
00422 }
00423
00424 if (FileSource::isRemote(relativeTo)) {
00425 resolved = QUrl(relativeTo).resolved(fileName).toString();
00426 if (!FileSource(resolved).isAvailable()) resolved = "";
00427 std::cerr << "resolved: " << resolved.toStdString() << std::endl;
00428 } else {
00429 if (QUrl(relativeTo).scheme() == "file") {
00430 relativeTo = QUrl(relativeTo).toLocalFile();
00431 }
00432 resolved = QFileInfo(relativeTo).dir().filePath(fileName);
00433 if (!QFileInfo(resolved).exists() ||
00434 !QFileInfo(resolved).isFile() ||
00435 !QFileInfo(resolved).isReadable()) {
00436 resolved = "";
00437 }
00438 }
00439
00440 return resolved;
00441 }
00442
00443 QString
00444 FileFinder::locateInteractive(FileType type, QString thing)
00445 {
00446 QString question;
00447 if (type == AudioFile) {
00448 question = tr("Audio file \"%1\" could not be opened.\nDo you want to locate it?");
00449 } else {
00450 question = tr("File \"%1\" could not be opened.\nDo you want to locate it?");
00451 }
00452
00453 QString path = "";
00454 bool done = false;
00455
00456 while (!done) {
00457
00458 int rv = QMessageBox::question
00459 (0,
00460 tr("Failed to open file"),
00461 question.arg(thing),
00462 tr("Locate file..."),
00463 tr("Use URL..."),
00464 tr("Cancel"),
00465 0, 2);
00466
00467 switch (rv) {
00468
00469 case 0:
00470
00471 if (QFileInfo(thing).dir().exists()) {
00472 path = QFileInfo(thing).dir().canonicalPath();
00473 }
00474
00475 path = getOpenFileName(type, path);
00476 done = (path != "");
00477 break;
00478
00479 case 1:
00480 {
00481 bool ok = false;
00482 path = QInputDialog::getText
00483 (0, tr("Use URL"),
00484 tr("Please enter the URL to use for this file:"),
00485 QLineEdit::Normal, "", &ok);
00486
00487 if (ok && path != "") {
00488 if (FileSource(path).isAvailable()) {
00489 done = true;
00490 } else {
00491 QMessageBox::critical
00492 (0, tr("Failed to open location"),
00493 tr("URL \"%1\" could not be opened").arg(path));
00494 path = "";
00495 }
00496 }
00497 break;
00498 }
00499
00500 case 2:
00501 path = "";
00502 done = true;
00503 break;
00504 }
00505 }
00506
00507 if (path != "") m_lastLocatedLocation = path;
00508 return path;
00509 }
00510
00511