annotate widgets/InteractiveFileFinder.cpp @ 854:c17719e488c9

Fix some potential null-pointer derefs, and simplify some logic where loops were used with an unconditional "break" that meant they could only happen once (from coverity scan)
author Chris Cannam
date Wed, 03 Sep 2014 12:04:22 +0100
parents 831188672987
children c02c51ae5238 a429b2acb45d
rev   line source
Chris@529 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@529 2
Chris@529 3 /*
Chris@529 4 Sonic Visualiser
Chris@529 5 An audio file viewer and annotation editor.
Chris@529 6 Centre for Digital Music, Queen Mary, University of London.
Chris@529 7 This file copyright 2007 QMUL.
Chris@529 8
Chris@529 9 This program is free software; you can redistribute it and/or
Chris@529 10 modify it under the terms of the GNU General Public License as
Chris@529 11 published by the Free Software Foundation; either version 2 of the
Chris@529 12 License, or (at your option) any later version. See the file
Chris@529 13 COPYING included with this distribution for more information.
Chris@529 14 */
Chris@529 15
Chris@529 16 #include "InteractiveFileFinder.h"
Chris@529 17 #include "data/fileio/FileSource.h"
Chris@529 18 #include "data/fileio/AudioFileReaderFactory.h"
Chris@529 19 #include "data/fileio/DataFileReaderFactory.h"
Chris@529 20 #include "rdf/RDFImporter.h"
Chris@529 21 #include "rdf/RDFExporter.h"
Chris@529 22
Chris@529 23 #include <QFileInfo>
Chris@529 24 #include <QMessageBox>
Chris@529 25 #include <QFileDialog>
Chris@529 26 #include <QInputDialog>
Chris@529 27 #include <QImageReader>
Chris@529 28 #include <QSettings>
Chris@529 29
Chris@529 30 #include <iostream>
Chris@529 31
Chris@529 32 InteractiveFileFinder
Chris@529 33 InteractiveFileFinder::m_instance;
Chris@529 34
Chris@529 35 InteractiveFileFinder::InteractiveFileFinder() :
Chris@760 36 m_sessionExtension("sv"),
Chris@831 37 m_lastLocatedLocation(""),
Chris@831 38 m_parent(0)
Chris@529 39 {
Chris@587 40 SVDEBUG << "Registering interactive file finder" << endl;
Chris@529 41 FileFinder::registerFileFinder(this);
Chris@529 42 }
Chris@529 43
Chris@529 44 InteractiveFileFinder::~InteractiveFileFinder()
Chris@529 45 {
Chris@529 46 }
Chris@529 47
Chris@760 48 void
Chris@831 49 InteractiveFileFinder::setParentWidget(QWidget *parent)
Chris@831 50 {
Chris@831 51 getInstance()->m_parent = parent;
Chris@831 52 }
Chris@831 53
Chris@831 54 void
Chris@760 55 InteractiveFileFinder::setApplicationSessionExtension(QString extension)
Chris@760 56 {
Chris@760 57 m_sessionExtension = extension;
Chris@760 58 }
Chris@760 59
Chris@529 60 QString
Chris@529 61 InteractiveFileFinder::getOpenFileName(FileType type, QString fallbackLocation)
Chris@529 62 {
Chris@778 63 QString settingsKeyStub;
Chris@529 64 QString lastPath = fallbackLocation;
Chris@529 65
Chris@529 66 QString title = tr("Select file");
Chris@529 67 QString filter = tr("All files (*.*)");
Chris@529 68
Chris@529 69 switch (type) {
Chris@529 70
Chris@529 71 case SessionFile:
Chris@778 72 settingsKeyStub = "session";
Chris@529 73 title = tr("Select a session file");
Chris@760 74 filter = tr("%1 session files (*.%1)\nRDF files (%3)\nAll files (*.*)")
Chris@760 75 .arg(QApplication::applicationName())
Chris@760 76 .arg(m_sessionExtension)
Chris@760 77 .arg(RDFImporter::getKnownExtensions());
Chris@529 78 break;
Chris@529 79
Chris@529 80 case AudioFile:
Chris@778 81 settingsKeyStub = "audio";
Chris@529 82 title = "Select an audio file";
Chris@529 83 filter = tr("Audio files (%1)\nAll files (*.*)")
Chris@529 84 .arg(AudioFileReaderFactory::getKnownExtensions());
Chris@529 85 break;
Chris@529 86
Chris@529 87 case LayerFile:
Chris@778 88 settingsKeyStub = "layer";
Chris@529 89 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 (*.*)")
Chris@529 90 .arg(DataFileReaderFactory::getKnownExtensions())
Chris@529 91 .arg(RDFImporter::getKnownExtensions());
Chris@529 92 break;
Chris@529 93
Chris@529 94 case LayerFileNoMidi:
Chris@778 95 settingsKeyStub = "layer";
Chris@529 96 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 (*.*)")
Chris@529 97 .arg(DataFileReaderFactory::getKnownExtensions())
Chris@529 98 .arg(RDFImporter::getKnownExtensions());
Chris@529 99 break;
Chris@529 100
Chris@705 101 case LayerFileNonSV:
Chris@778 102 settingsKeyStub = "layer";
Chris@705 103 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 (*.*)")
Chris@705 104 .arg(DataFileReaderFactory::getKnownExtensions())
Chris@705 105 .arg(RDFImporter::getKnownExtensions());
Chris@705 106 break;
Chris@705 107
Chris@705 108 case LayerFileNoMidiNonSV:
Chris@778 109 settingsKeyStub = "layer";
Chris@705 110 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 (*.*)")
Chris@705 111 .arg(DataFileReaderFactory::getKnownExtensions())
Chris@705 112 .arg(RDFImporter::getKnownExtensions());
Chris@705 113 break;
Chris@705 114
Chris@529 115 case SessionOrAudioFile:
Chris@778 116 settingsKeyStub = "last";
Chris@760 117 filter = tr("All supported files (*.sv %1 %2)\n%3 session files (*.%4)\nAudio files (%2)\nRDF files (%1)\nAll files (*.*)")
Chris@529 118 .arg(RDFImporter::getKnownExtensions())
Chris@760 119 .arg(AudioFileReaderFactory::getKnownExtensions())
Chris@760 120 .arg(QApplication::applicationName())
Chris@760 121 .arg(m_sessionExtension);
Chris@529 122 break;
Chris@529 123
Chris@529 124 case ImageFile:
Chris@778 125 settingsKeyStub = "image";
Chris@529 126 {
Chris@529 127 QStringList fmts;
Chris@529 128 QList<QByteArray> formats = QImageReader::supportedImageFormats();
Chris@529 129 for (QList<QByteArray>::iterator i = formats.begin();
Chris@529 130 i != formats.end(); ++i) {
Chris@529 131 fmts.push_back(QString("*.%1")
Chris@529 132 .arg(QString::fromLocal8Bit(*i).toLower()));
Chris@529 133 }
Chris@529 134 filter = tr("Image files (%1)\nAll files (*.*)").arg(fmts.join(" "));
Chris@529 135 }
Chris@529 136 break;
Chris@529 137
Chris@672 138 case CSVFile:
Chris@778 139 settingsKeyStub = "layer";
Chris@672 140 filter = tr("Comma-separated data files (*.csv)\nSpace-separated .lab files (*.lab)\nText files (*.txt)\nAll files (*.*)");
Chris@672 141 break;
Chris@672 142
Chris@529 143 case AnyFile:
Chris@778 144 settingsKeyStub = "last";
Chris@760 145 filter = tr("All supported files (*.sv %1 %2 %3)\n%4 session files (*.%5)\nAudio files (%1)\nLayer files (%2)\nRDF files (%3)\nAll files (*.*)")
Chris@529 146 .arg(AudioFileReaderFactory::getKnownExtensions())
Chris@529 147 .arg(DataFileReaderFactory::getKnownExtensions())
Chris@760 148 .arg(RDFImporter::getKnownExtensions())
Chris@760 149 .arg(QApplication::applicationName())
Chris@760 150 .arg(m_sessionExtension);
Chris@529 151 break;
Chris@529 152 };
Chris@529 153
Chris@529 154 if (lastPath == "") {
Chris@529 155 char *home = getenv("HOME");
Chris@529 156 if (home) lastPath = home;
Chris@529 157 else lastPath = ".";
Chris@529 158 } else if (QFileInfo(lastPath).isDir()) {
Chris@529 159 lastPath = QFileInfo(lastPath).canonicalPath();
Chris@529 160 } else {
Chris@529 161 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
Chris@529 162 }
Chris@529 163
Chris@529 164 QSettings settings;
Chris@529 165 settings.beginGroup("FileFinder");
Chris@778 166 lastPath = settings.value(settingsKeyStub + "path", lastPath).toString();
Chris@529 167
Chris@529 168 QString path = "";
Chris@529 169
Chris@529 170 // Use our own QFileDialog just for symmetry with getSaveFileName below
Chris@529 171
Chris@831 172 QFileDialog dialog(m_parent);
Chris@616 173 dialog.setNameFilters(filter.split('\n'));
Chris@529 174 dialog.setWindowTitle(title);
Chris@529 175 dialog.setDirectory(lastPath);
Chris@529 176
Chris@529 177 dialog.setAcceptMode(QFileDialog::AcceptOpen);
Chris@529 178 dialog.setFileMode(QFileDialog::ExistingFile);
Chris@529 179
Chris@529 180 if (dialog.exec()) {
Chris@529 181 QStringList files = dialog.selectedFiles();
Chris@529 182 if (!files.empty()) path = *files.begin();
Chris@529 183
Chris@529 184 QFileInfo fi(path);
Chris@529 185
Chris@529 186 if (!fi.exists()) {
Chris@529 187
Chris@529 188 QMessageBox::critical(0, tr("File does not exist"),
Chris@529 189 tr("<b>File not found</b><p>File \"%1\" does not exist").arg(path));
Chris@529 190 path = "";
Chris@529 191
Chris@529 192 } else if (!fi.isReadable()) {
Chris@529 193
Chris@529 194 QMessageBox::critical(0, tr("File is not readable"),
Chris@529 195 tr("<b>File is not readable</b><p>File \"%1\" can not be read").arg(path));
Chris@529 196 path = "";
Chris@529 197
Chris@529 198 } else if (fi.isDir()) {
Chris@529 199
Chris@529 200 QMessageBox::critical(0, tr("Directory selected"),
Chris@529 201 tr("<b>Directory selected</b><p>File \"%1\" is a directory").arg(path));
Chris@529 202 path = "";
Chris@529 203
Chris@529 204 } else if (!fi.isFile()) {
Chris@529 205
Chris@529 206 QMessageBox::critical(0, tr("Non-file selected"),
Chris@529 207 tr("<b>Not a file</b><p>Path \"%1\" is not a file").arg(path));
Chris@529 208 path = "";
Chris@529 209
Chris@529 210 } else if (fi.size() == 0) {
Chris@529 211
Chris@529 212 QMessageBox::critical(0, tr("File is empty"),
Chris@529 213 tr("<b>File is empty</b><p>File \"%1\" is empty").arg(path));
Chris@529 214 path = "";
Chris@529 215 }
Chris@529 216 }
Chris@529 217
Chris@529 218 if (path != "") {
Chris@778 219 settings.setValue(settingsKeyStub + "path",
Chris@529 220 QFileInfo(path).absoluteDir().canonicalPath());
Chris@529 221 }
Chris@529 222
Chris@529 223 return path;
Chris@529 224 }
Chris@529 225
Chris@529 226 QString
Chris@794 227 InteractiveFileFinder::getSaveFileName(FileType type,
Chris@794 228 QString fallbackLocation)
Chris@529 229 {
Chris@778 230 QString settingsKeyStub;
Chris@529 231 QString lastPath = fallbackLocation;
Chris@529 232
Chris@529 233 QString title = tr("Select file");
Chris@529 234 QString filter = tr("All files (*.*)");
Chris@529 235
Chris@529 236 switch (type) {
Chris@529 237
Chris@529 238 case SessionFile:
Chris@778 239 settingsKeyStub = "savesession";
Chris@529 240 title = tr("Select a session file");
Chris@760 241 filter = tr("%1 session files (*.%2)\nAll files (*.*)")
Chris@760 242 .arg(QApplication::applicationName()).arg(m_sessionExtension);
Chris@529 243 break;
Chris@529 244
Chris@529 245 case AudioFile:
Chris@778 246 settingsKeyStub = "saveaudio";
Chris@529 247 title = "Select an audio file";
Chris@529 248 title = tr("Select a file to export to");
Chris@529 249 filter = tr("WAV audio files (*.wav)\nAll files (*.*)");
Chris@529 250 break;
Chris@529 251
Chris@529 252 case LayerFile:
Chris@778 253 settingsKeyStub = "savelayer";
Chris@529 254 title = tr("Select a file to export to");
Chris@529 255 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 (*.*)").arg(RDFExporter::getSupportedExtensions());
Chris@529 256 break;
Chris@529 257
Chris@529 258 case LayerFileNoMidi:
Chris@778 259 settingsKeyStub = "savelayer";
Chris@529 260 title = tr("Select a file to export to");
Chris@529 261 filter = tr("Sonic Visualiser Layer XML files (*.svl)\nComma-separated data files (*.csv)\nRDF/Turtle files (%1)\nText files (*.txt)\nAll files (*.*)").arg(RDFExporter::getSupportedExtensions());
Chris@529 262 break;
Chris@529 263
Chris@705 264 case LayerFileNonSV:
Chris@778 265 settingsKeyStub = "savelayer";
Chris@705 266 title = tr("Select a file to export to");
Chris@705 267 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 (*.*)").arg(RDFExporter::getSupportedExtensions());
Chris@705 268 break;
Chris@705 269
Chris@705 270 case LayerFileNoMidiNonSV:
Chris@778 271 settingsKeyStub = "savelayer";
Chris@705 272 title = tr("Select a file to export to");
Chris@705 273 filter = tr("Comma-separated data files (*.csv)\nSonic Visualiser Layer XML files (*.svl)\nRDF/Turtle files (%1)\nText files (*.txt)\nAll files (*.*)").arg(RDFExporter::getSupportedExtensions());
Chris@705 274 break;
Chris@705 275
Chris@529 276 case SessionOrAudioFile:
Chris@682 277 cerr << "ERROR: Internal error: InteractiveFileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << endl;
Chris@529 278 abort();
Chris@529 279
Chris@529 280 case ImageFile:
Chris@778 281 settingsKeyStub = "saveimage";
Chris@529 282 title = tr("Select a file to export to");
Chris@529 283 filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)");
Chris@529 284 break;
Chris@529 285
Chris@672 286 case CSVFile:
Chris@778 287 settingsKeyStub = "savelayer";
Chris@672 288 title = tr("Select a file to export to");
Chris@672 289 filter = tr("Comma-separated data files (*.csv)\nText files (*.txt)\nAll files (*.*)");
Chris@672 290 break;
Chris@672 291
Chris@529 292 case AnyFile:
Chris@682 293 cerr << "ERROR: Internal error: InteractiveFileFinder::getSaveFileName: AnyFile cannot be used here" << endl;
Chris@529 294 abort();
Chris@529 295 };
Chris@529 296
Chris@529 297 if (lastPath == "") {
Chris@529 298 char *home = getenv("HOME");
Chris@529 299 if (home) lastPath = home;
Chris@529 300 else lastPath = ".";
Chris@529 301 } else if (QFileInfo(lastPath).isDir()) {
Chris@529 302 lastPath = QFileInfo(lastPath).canonicalPath();
Chris@529 303 } else {
Chris@529 304 lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath();
Chris@529 305 }
Chris@529 306
Chris@529 307 QSettings settings;
Chris@529 308 settings.beginGroup("FileFinder");
Chris@778 309 lastPath = settings.value(settingsKeyStub + "path", lastPath).toString();
Chris@529 310
Chris@529 311 QString path = "";
Chris@529 312
Chris@529 313 // Use our own QFileDialog instead of static functions, as we may
Chris@529 314 // need to adjust the file extension based on the selected filter
Chris@529 315
Chris@831 316 QFileDialog dialog(m_parent);
Chris@778 317
Chris@778 318 QStringList filters = filter.split('\n');
Chris@778 319
Chris@778 320 dialog.setNameFilters(filters);
Chris@529 321 dialog.setWindowTitle(title);
Chris@529 322 dialog.setDirectory(lastPath);
Chris@529 323 dialog.setAcceptMode(QFileDialog::AcceptSave);
Chris@529 324 dialog.setFileMode(QFileDialog::AnyFile);
Chris@529 325 dialog.setConfirmOverwrite(false); // we'll do that
Chris@778 326
Chris@778 327 QString defaultSuffix;
Chris@529 328 if (type == SessionFile) {
Chris@778 329 defaultSuffix = m_sessionExtension;
Chris@529 330 } else if (type == AudioFile) {
Chris@778 331 defaultSuffix = "wav";
Chris@529 332 } else if (type == ImageFile) {
Chris@778 333 defaultSuffix = "png";
Chris@672 334 } else if (type == CSVFile) {
Chris@778 335 defaultSuffix = "csv";
Chris@778 336 }
Chris@778 337
Chris@778 338 defaultSuffix =
Chris@778 339 settings.value(settingsKeyStub + "suffix", defaultSuffix).toString();
Chris@778 340
Chris@778 341 dialog.setDefaultSuffix(defaultSuffix);
Chris@778 342
Chris@778 343 foreach (QString f, filters) {
Chris@778 344 if (f.contains("." + defaultSuffix)) {
Chris@778 345 dialog.selectNameFilter(f);
Chris@778 346 }
Chris@529 347 }
Chris@529 348
Chris@529 349 bool good = false;
Chris@529 350
Chris@529 351 while (!good) {
Chris@529 352
Chris@529 353 path = "";
Chris@529 354
Chris@529 355 if (!dialog.exec()) break;
Chris@529 356
Chris@529 357 QStringList files = dialog.selectedFiles();
Chris@529 358 if (files.empty()) break;
Chris@529 359 path = *files.begin();
Chris@529 360
Chris@529 361 QFileInfo fi(path);
Chris@529 362
Chris@682 363 cerr << "type = " << type << ", suffix = " << fi.suffix() << endl;
Chris@529 364
Chris@705 365 if ((type == LayerFile || type == LayerFileNoMidi ||
Chris@705 366 type == LayerFileNonSV || type == LayerFileNoMidiNonSV)
Chris@529 367 && fi.suffix() == "") {
Chris@529 368 QString expectedExtension;
Chris@616 369 QString selectedFilter = dialog.selectedNameFilter();
Chris@529 370 if (selectedFilter.contains(".svl")) {
Chris@529 371 expectedExtension = "svl";
Chris@529 372 } else if (selectedFilter.contains(".txt")) {
Chris@529 373 expectedExtension = "txt";
Chris@529 374 } else if (selectedFilter.contains(".csv")) {
Chris@529 375 expectedExtension = "csv";
Chris@529 376 } else if (selectedFilter.contains(".mid")) {
Chris@529 377 expectedExtension = "mid";
Chris@529 378 } else if (selectedFilter.contains(".ttl")) {
Chris@529 379 expectedExtension = "ttl";
Chris@529 380 }
Chris@682 381 cerr << "expected extension = " << expectedExtension << endl;
Chris@529 382 if (expectedExtension != "") {
Chris@529 383 path = QString("%1.%2").arg(path).arg(expectedExtension);
Chris@529 384 fi = QFileInfo(path);
Chris@529 385 }
Chris@529 386 }
Chris@529 387
Chris@529 388 if (fi.isDir()) {
Chris@529 389 QMessageBox::critical(0, tr("Directory selected"),
Chris@529 390 tr("<b>Directory selected</b><p>File \"%1\" is a directory").arg(path));
Chris@529 391 continue;
Chris@529 392 }
Chris@529 393
Chris@529 394 if (fi.exists()) {
Chris@529 395 if (QMessageBox::question(0, tr("File exists"),
Chris@529 396 tr("<b>File exists</b><p>The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path),
Chris@529 397 QMessageBox::Ok,
Chris@529 398 QMessageBox::Cancel) != QMessageBox::Ok) {
Chris@529 399 continue;
Chris@529 400 }
Chris@529 401 }
Chris@529 402
Chris@529 403 good = true;
Chris@529 404 }
Chris@529 405
Chris@529 406 if (path != "") {
Chris@778 407 settings.setValue(settingsKeyStub + "path",
Chris@529 408 QFileInfo(path).absoluteDir().canonicalPath());
Chris@778 409 settings.setValue(settingsKeyStub + "suffix",
Chris@778 410 QFileInfo(path).suffix());
Chris@529 411 }
Chris@529 412
Chris@529 413 return path;
Chris@529 414 }
Chris@529 415
Chris@529 416 void
Chris@529 417 InteractiveFileFinder::registerLastOpenedFilePath(FileType type, QString path)
Chris@529 418 {
Chris@778 419 QString settingsKeyStub;
Chris@529 420
Chris@529 421 switch (type) {
Chris@529 422 case SessionFile:
Chris@778 423 settingsKeyStub = "session";
Chris@529 424 break;
Chris@529 425
Chris@529 426 case AudioFile:
Chris@778 427 settingsKeyStub = "audio";
Chris@529 428 break;
Chris@529 429
Chris@529 430 case LayerFile:
Chris@778 431 settingsKeyStub = "layer";
Chris@529 432 break;
Chris@529 433
Chris@529 434 case LayerFileNoMidi:
Chris@778 435 settingsKeyStub = "layer";
Chris@529 436 break;
Chris@529 437
Chris@705 438 case LayerFileNonSV:
Chris@778 439 settingsKeyStub = "layer";
Chris@705 440 break;
Chris@705 441
Chris@705 442 case LayerFileNoMidiNonSV:
Chris@778 443 settingsKeyStub = "layer";
Chris@705 444 break;
Chris@705 445
Chris@529 446 case SessionOrAudioFile:
Chris@778 447 settingsKeyStub = "last";
Chris@529 448 break;
Chris@529 449
Chris@529 450 case ImageFile:
Chris@778 451 settingsKeyStub = "image";
Chris@529 452 break;
Chris@529 453
Chris@672 454 case CSVFile:
Chris@778 455 settingsKeyStub = "layer";
Chris@672 456 break;
Chris@672 457
Chris@529 458 case AnyFile:
Chris@778 459 settingsKeyStub = "last";
Chris@529 460 break;
Chris@529 461 }
Chris@529 462
Chris@529 463 if (path != "") {
Chris@529 464 QSettings settings;
Chris@529 465 settings.beginGroup("FileFinder");
Chris@529 466 path = QFileInfo(path).absoluteDir().canonicalPath();
Chris@778 467 QString suffix = QFileInfo(path).suffix();
Chris@778 468 settings.setValue(settingsKeyStub + "path", path);
Chris@778 469 settings.setValue(settingsKeyStub + "suffix", suffix);
Chris@529 470 settings.setValue("lastpath", path);
Chris@529 471 }
Chris@529 472 }
Chris@529 473
Chris@529 474 QString
Chris@529 475 InteractiveFileFinder::find(FileType type, QString location, QString lastKnownLocation)
Chris@529 476 {
Chris@529 477 if (FileSource::canHandleScheme(location)) {
Chris@529 478 if (FileSource(location).isAvailable()) {
Chris@587 479 SVDEBUG << "InteractiveFileFinder::find: ok, it's available... returning" << endl;
Chris@529 480 return location;
Chris@529 481 }
Chris@529 482 }
Chris@529 483
Chris@529 484 if (QFileInfo(location).exists()) return location;
Chris@529 485
Chris@529 486 QString foundAt = "";
Chris@529 487
Chris@529 488 if ((foundAt = findRelative(location, lastKnownLocation)) != "") {
Chris@529 489 return foundAt;
Chris@529 490 }
Chris@529 491
Chris@529 492 if ((foundAt = findRelative(location, m_lastLocatedLocation)) != "") {
Chris@529 493 return foundAt;
Chris@529 494 }
Chris@529 495
Chris@529 496 return locateInteractive(type, location);
Chris@529 497 }
Chris@529 498
Chris@529 499 QString
Chris@529 500 InteractiveFileFinder::findRelative(QString location, QString relativeTo)
Chris@529 501 {
Chris@529 502 if (relativeTo == "") return "";
Chris@529 503
Chris@587 504 SVDEBUG << "Looking for \"" << location << "\" next to \""
Chris@585 505 << relativeTo << "\"..." << endl;
Chris@529 506
Chris@529 507 QString fileName;
Chris@529 508 QString resolved;
Chris@529 509
Chris@529 510 if (FileSource::isRemote(location)) {
Chris@529 511 fileName = QUrl(location).path().section('/', -1, -1,
Chris@529 512 QString::SectionSkipEmpty);
Chris@529 513 } else {
Chris@529 514 if (QUrl(location).scheme() == "file") {
Chris@529 515 location = QUrl(location).toLocalFile();
Chris@529 516 }
Chris@529 517 fileName = QFileInfo(location).fileName();
Chris@529 518 }
Chris@529 519
Chris@529 520 if (FileSource::isRemote(relativeTo)) {
Chris@529 521 resolved = QUrl(relativeTo).resolved(fileName).toString();
Chris@529 522 if (!FileSource(resolved).isAvailable()) resolved = "";
Chris@682 523 cerr << "resolved: " << resolved << endl;
Chris@529 524 } else {
Chris@529 525 if (QUrl(relativeTo).scheme() == "file") {
Chris@529 526 relativeTo = QUrl(relativeTo).toLocalFile();
Chris@529 527 }
Chris@529 528 resolved = QFileInfo(relativeTo).dir().filePath(fileName);
Chris@529 529 if (!QFileInfo(resolved).exists() ||
Chris@529 530 !QFileInfo(resolved).isFile() ||
Chris@529 531 !QFileInfo(resolved).isReadable()) {
Chris@529 532 resolved = "";
Chris@529 533 }
Chris@529 534 }
Chris@529 535
Chris@529 536 return resolved;
Chris@529 537 }
Chris@529 538
Chris@529 539 QString
Chris@529 540 InteractiveFileFinder::locateInteractive(FileType type, QString thing)
Chris@529 541 {
Chris@529 542 QString question;
Chris@529 543 if (type == AudioFile) {
Chris@529 544 question = tr("<b>File not found</b><p>Audio file \"%1\" could not be opened.\nDo you want to locate it?");
Chris@529 545 } else {
Chris@529 546 question = tr("<b>File not found</b><p>File \"%1\" could not be opened.\nDo you want to locate it?");
Chris@529 547 }
Chris@529 548
Chris@529 549 QString path = "";
Chris@529 550 bool done = false;
Chris@529 551
Chris@529 552 while (!done) {
Chris@529 553
Chris@529 554 int rv = QMessageBox::question
Chris@529 555 (0,
Chris@529 556 tr("Failed to open file"),
Chris@529 557 question.arg(thing),
Chris@529 558 tr("Locate file..."),
Chris@529 559 tr("Use URL..."),
Chris@529 560 tr("Cancel"),
Chris@529 561 0, 2);
Chris@529 562
Chris@529 563 switch (rv) {
Chris@529 564
Chris@529 565 case 0: // Locate file
Chris@529 566
Chris@529 567 if (QFileInfo(thing).dir().exists()) {
Chris@529 568 path = QFileInfo(thing).dir().canonicalPath();
Chris@529 569 }
Chris@529 570
Chris@529 571 path = getOpenFileName(type, path);
Chris@529 572 done = (path != "");
Chris@529 573 break;
Chris@529 574
Chris@529 575 case 1: // Use URL
Chris@529 576 {
Chris@529 577 bool ok = false;
Chris@529 578 path = QInputDialog::getText
Chris@529 579 (0, tr("Use URL"),
Chris@529 580 tr("Please enter the URL to use for this file:"),
Chris@529 581 QLineEdit::Normal, "", &ok);
Chris@529 582
Chris@529 583 if (ok && path != "") {
Chris@529 584 if (FileSource(path).isAvailable()) {
Chris@529 585 done = true;
Chris@529 586 } else {
Chris@529 587 QMessageBox::critical
Chris@529 588 (0, tr("Failed to open location"),
Chris@529 589 tr("<b>Failed to open location</b><p>URL \"%1\" could not be opened").arg(path));
Chris@529 590 path = "";
Chris@529 591 }
Chris@529 592 }
Chris@529 593 break;
Chris@529 594 }
Chris@529 595
Chris@529 596 case 2: // Cancel
Chris@529 597 path = "";
Chris@529 598 done = true;
Chris@529 599 break;
Chris@529 600 }
Chris@529 601 }
Chris@529 602
Chris@529 603 if (path != "") m_lastLocatedLocation = path;
Chris@529 604 return path;
Chris@529 605 }
Chris@529 606
Chris@529 607