annotate widgets/InteractiveFileFinder.cpp @ 1274:97d977091d4e

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