annotate widgets/InteractiveFileFinder.cpp @ 1431:af824022bffd single-point

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