annotate widgets/InteractiveFileFinder.cpp @ 1447:8afea53332f3 single-point

Add option to make pane sizes auto-resize-only (i.e. remove user control via a splitter); also place alignment views above panes instead of below, meaning the extra bit of space that we currently have for the pane without one at least goes to the primary pane
author Chris Cannam
date Tue, 30 Apr 2019 15:53:21 +0100
parents 18101be79c9c
children c268fe2ad597
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@529 391 dialog.setConfirmOverwrite(false); // 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