annotate widgets/InteractiveFileFinder.cpp @ 1571:9cd77efef37c

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