# HG changeset patch # User Chris Cannam # Date 1238171152 0 # Node ID 3228b7913aa44eb82ab55571f7f2875540b00572 # Parent 44f391ec2172f9a3410d1cd47ffaa075f99d7e9f * Pull out the widgetry part of FileFinder into widgets/InteractiveFileFinder (essentially this is just to avoid a dependency from data/fileio to widgets/ which is problematic for non-gui programs) diff -r 44f391ec2172 -r 3228b7913aa4 widgets/FileFinder.cpp --- a/widgets/FileFinder.cpp Fri Mar 27 13:10:01 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,521 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2007 QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FileFinder.h" -#include "data/fileio/FileSource.h" -#include "data/fileio/AudioFileReaderFactory.h" -#include "data/fileio/DataFileReaderFactory.h" -#include "rdf/RDFImporter.h" -#include "rdf/RDFExporter.h" - -#include -#include -#include -#include -#include -#include - -#include - -FileFinder * -FileFinder::m_instance = 0; - -FileFinder::FileFinder() : - m_lastLocatedLocation("") -{ -} - -FileFinder::~FileFinder() -{ -} - -FileFinder * -FileFinder::getInstance() -{ - if (m_instance == 0) { - m_instance = new FileFinder(); - } - return m_instance; -} - -QString -FileFinder::getOpenFileName(FileType type, QString fallbackLocation) -{ - QString settingsKey; - QString lastPath = fallbackLocation; - - QString title = tr("Select file"); - QString filter = tr("All files (*.*)"); - - switch (type) { - - case SessionFile: - settingsKey = "sessionpath"; - title = tr("Select a session file"); - filter = tr("Sonic Visualiser session files (*.sv)\nRDF files (%1)\nAll files (*.*)").arg(RDFImporter::getKnownExtensions()); - break; - - case AudioFile: - settingsKey = "audiopath"; - title = "Select an audio file"; - filter = tr("Audio files (%1)\nAll files (*.*)") - .arg(AudioFileReaderFactory::getKnownExtensions()); - break; - - case LayerFile: - settingsKey = "layerpath"; - 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 (*.*)") - .arg(DataFileReaderFactory::getKnownExtensions()) - .arg(RDFImporter::getKnownExtensions()); - break; - - case LayerFileNoMidi: - settingsKey = "layerpath"; - 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 (*.*)") - .arg(DataFileReaderFactory::getKnownExtensions()) - .arg(RDFImporter::getKnownExtensions()); - break; - - case SessionOrAudioFile: - settingsKey = "lastpath"; - filter = tr("All supported files (*.sv %1 %2)\nSonic Visualiser session files (*.sv)\nAudio files (%2)\nRDF files (%1)\nAll files (*.*)") - .arg(RDFImporter::getKnownExtensions()) - .arg(AudioFileReaderFactory::getKnownExtensions()); - break; - - case ImageFile: - settingsKey = "imagepath"; - { - QStringList fmts; - QList formats = QImageReader::supportedImageFormats(); - for (QList::iterator i = formats.begin(); - i != formats.end(); ++i) { - fmts.push_back(QString("*.%1") - .arg(QString::fromLocal8Bit(*i).toLower())); - } - filter = tr("Image files (%1)\nAll files (*.*)").arg(fmts.join(" ")); - } - break; - - case AnyFile: - settingsKey = "lastpath"; - filter = tr("All supported files (*.sv %1 %2 %3)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nLayer files (%2)\nRDF files (%3)\nAll files (*.*)") - .arg(AudioFileReaderFactory::getKnownExtensions()) - .arg(DataFileReaderFactory::getKnownExtensions()) - .arg(RDFImporter::getKnownExtensions()); - break; - }; - - if (lastPath == "") { - char *home = getenv("HOME"); - if (home) lastPath = home; - else lastPath = "."; - } else if (QFileInfo(lastPath).isDir()) { - lastPath = QFileInfo(lastPath).canonicalPath(); - } else { - lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); - } - - QSettings settings; - settings.beginGroup("FileFinder"); - lastPath = settings.value(settingsKey, lastPath).toString(); - - QString path = ""; - - // Use our own QFileDialog just for symmetry with getSaveFileName below - - QFileDialog dialog; - dialog.setFilters(filter.split('\n')); - dialog.setWindowTitle(title); - dialog.setDirectory(lastPath); - - dialog.setAcceptMode(QFileDialog::AcceptOpen); - dialog.setFileMode(QFileDialog::ExistingFile); - - if (dialog.exec()) { - QStringList files = dialog.selectedFiles(); - if (!files.empty()) path = *files.begin(); - - QFileInfo fi(path); - - if (!fi.exists()) { - - QMessageBox::critical(0, tr("File does not exist"), - tr("File not found

File \"%1\" does not exist").arg(path)); - path = ""; - - } else if (!fi.isReadable()) { - - QMessageBox::critical(0, tr("File is not readable"), - tr("File is not readable

File \"%1\" can not be read").arg(path)); - path = ""; - - } else if (fi.isDir()) { - - QMessageBox::critical(0, tr("Directory selected"), - tr("Directory selected

File \"%1\" is a directory").arg(path)); - path = ""; - - } else if (!fi.isFile()) { - - QMessageBox::critical(0, tr("Non-file selected"), - tr("Not a file

Path \"%1\" is not a file").arg(path)); - path = ""; - - } else if (fi.size() == 0) { - - QMessageBox::critical(0, tr("File is empty"), - tr("File is empty

File \"%1\" is empty").arg(path)); - path = ""; - } - } - - if (path != "") { - settings.setValue(settingsKey, - QFileInfo(path).absoluteDir().canonicalPath()); - } - - return path; -} - -QString -FileFinder::getSaveFileName(FileType type, QString fallbackLocation) -{ - QString settingsKey; - QString lastPath = fallbackLocation; - - QString title = tr("Select file"); - QString filter = tr("All files (*.*)"); - - switch (type) { - - case SessionFile: - settingsKey = "savesessionpath"; - title = tr("Select a session file"); - filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)"); - break; - - case AudioFile: - settingsKey = "saveaudiopath"; - title = "Select an audio file"; - title = tr("Select a file to export to"); - filter = tr("WAV audio files (*.wav)\nAll files (*.*)"); - break; - - case LayerFile: - settingsKey = "savelayerpath"; - title = tr("Select a file to export to"); - 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()); - break; - - case LayerFileNoMidi: - settingsKey = "savelayerpath"; - title = tr("Select a file to export to"); - 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()); - break; - - case SessionOrAudioFile: - std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << std::endl; - abort(); - - case ImageFile: - settingsKey = "saveimagepath"; - title = tr("Select a file to export to"); - filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)"); - break; - - case AnyFile: - std::cerr << "ERROR: Internal error: FileFinder::getSaveFileName: AnyFile cannot be used here" << std::endl; - abort(); - }; - - if (lastPath == "") { - char *home = getenv("HOME"); - if (home) lastPath = home; - else lastPath = "."; - } else if (QFileInfo(lastPath).isDir()) { - lastPath = QFileInfo(lastPath).canonicalPath(); - } else { - lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); - } - - QSettings settings; - settings.beginGroup("FileFinder"); - lastPath = settings.value(settingsKey, lastPath).toString(); - - QString path = ""; - - // Use our own QFileDialog instead of static functions, as we may - // need to adjust the file extension based on the selected filter - - QFileDialog dialog; - dialog.setFilters(filter.split('\n')); - dialog.setWindowTitle(title); - dialog.setDirectory(lastPath); - - dialog.setAcceptMode(QFileDialog::AcceptSave); - dialog.setFileMode(QFileDialog::AnyFile); - dialog.setConfirmOverwrite(false); // we'll do that - - if (type == SessionFile) { - dialog.setDefaultSuffix("sv"); - } else if (type == AudioFile) { - dialog.setDefaultSuffix("wav"); - } else if (type == ImageFile) { - dialog.setDefaultSuffix("png"); - } - - bool good = false; - - while (!good) { - - path = ""; - - if (!dialog.exec()) break; - - QStringList files = dialog.selectedFiles(); - if (files.empty()) break; - path = *files.begin(); - - QFileInfo fi(path); - - std::cerr << "type = " << type << ", suffix = " << fi.suffix().toStdString() << std::endl; - - if ((type == LayerFile || type == LayerFileNoMidi) - && fi.suffix() == "") { - QString expectedExtension; - QString selectedFilter = dialog.selectedFilter(); - if (selectedFilter.contains(".svl")) { - expectedExtension = "svl"; - } else if (selectedFilter.contains(".txt")) { - expectedExtension = "txt"; - } else if (selectedFilter.contains(".csv")) { - expectedExtension = "csv"; - } else if (selectedFilter.contains(".mid")) { - expectedExtension = "mid"; - } else if (selectedFilter.contains(".ttl")) { - expectedExtension = "ttl"; - } - std::cerr << "expected extension = " << expectedExtension.toStdString() << std::endl; - if (expectedExtension != "") { - path = QString("%1.%2").arg(path).arg(expectedExtension); - fi = QFileInfo(path); - } - } - - if (fi.isDir()) { - QMessageBox::critical(0, tr("Directory selected"), - tr("Directory selected

File \"%1\" is a directory").arg(path)); - continue; - } - - if (fi.exists()) { - if (QMessageBox::question(0, tr("File exists"), - tr("File exists

The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path), - QMessageBox::Ok, - QMessageBox::Cancel) != QMessageBox::Ok) { - continue; - } - } - - good = true; - } - - if (path != "") { - settings.setValue(settingsKey, - QFileInfo(path).absoluteDir().canonicalPath()); - } - - return path; -} - -void -FileFinder::registerLastOpenedFilePath(FileType type, QString path) -{ - QString settingsKey; - - switch (type) { - case SessionFile: - settingsKey = "sessionpath"; - break; - - case AudioFile: - settingsKey = "audiopath"; - break; - - case LayerFile: - settingsKey = "layerpath"; - break; - - case LayerFileNoMidi: - settingsKey = "layerpath"; - break; - - case SessionOrAudioFile: - settingsKey = "lastpath"; - break; - - case ImageFile: - settingsKey = "imagepath"; - break; - - case AnyFile: - settingsKey = "lastpath"; - break; - } - - if (path != "") { - QSettings settings; - settings.beginGroup("FileFinder"); - path = QFileInfo(path).absoluteDir().canonicalPath(); - settings.setValue(settingsKey, path); - settings.setValue("lastpath", path); - } -} - -QString -FileFinder::find(FileType type, QString location, QString lastKnownLocation) -{ - if (FileSource::canHandleScheme(location)) { - if (FileSource(location).isAvailable()) { - std::cerr << "FileFinder::find: ok, it's available... returning" << std::endl; - return location; - } - } - - if (QFileInfo(location).exists()) return location; - - QString foundAt = ""; - - if ((foundAt = findRelative(location, lastKnownLocation)) != "") { - return foundAt; - } - - if ((foundAt = findRelative(location, m_lastLocatedLocation)) != "") { - return foundAt; - } - - return locateInteractive(type, location); -} - -QString -FileFinder::findRelative(QString location, QString relativeTo) -{ - if (relativeTo == "") return ""; - - std::cerr << "Looking for \"" << location.toStdString() << "\" next to \"" - << relativeTo.toStdString() << "\"..." << std::endl; - - QString fileName; - QString resolved; - - if (FileSource::isRemote(location)) { - fileName = QUrl(location).path().section('/', -1, -1, - QString::SectionSkipEmpty); - } else { - if (QUrl(location).scheme() == "file") { - location = QUrl(location).toLocalFile(); - } - fileName = QFileInfo(location).fileName(); - } - - if (FileSource::isRemote(relativeTo)) { - resolved = QUrl(relativeTo).resolved(fileName).toString(); - if (!FileSource(resolved).isAvailable()) resolved = ""; - std::cerr << "resolved: " << resolved.toStdString() << std::endl; - } else { - if (QUrl(relativeTo).scheme() == "file") { - relativeTo = QUrl(relativeTo).toLocalFile(); - } - resolved = QFileInfo(relativeTo).dir().filePath(fileName); - if (!QFileInfo(resolved).exists() || - !QFileInfo(resolved).isFile() || - !QFileInfo(resolved).isReadable()) { - resolved = ""; - } - } - - return resolved; -} - -QString -FileFinder::locateInteractive(FileType type, QString thing) -{ - QString question; - if (type == AudioFile) { - question = tr("File not found

Audio file \"%1\" could not be opened.\nDo you want to locate it?"); - } else { - question = tr("File not found

File \"%1\" could not be opened.\nDo you want to locate it?"); - } - - QString path = ""; - bool done = false; - - while (!done) { - - int rv = QMessageBox::question - (0, - tr("Failed to open file"), - question.arg(thing), - tr("Locate file..."), - tr("Use URL..."), - tr("Cancel"), - 0, 2); - - switch (rv) { - - case 0: // Locate file - - if (QFileInfo(thing).dir().exists()) { - path = QFileInfo(thing).dir().canonicalPath(); - } - - path = getOpenFileName(type, path); - done = (path != ""); - break; - - case 1: // Use URL - { - bool ok = false; - path = QInputDialog::getText - (0, tr("Use URL"), - tr("Please enter the URL to use for this file:"), - QLineEdit::Normal, "", &ok); - - if (ok && path != "") { - if (FileSource(path).isAvailable()) { - done = true; - } else { - QMessageBox::critical - (0, tr("Failed to open location"), - tr("Failed to open location

URL \"%1\" could not be opened").arg(path)); - path = ""; - } - } - break; - } - - case 2: // Cancel - path = ""; - done = true; - break; - } - } - - if (path != "") m_lastLocatedLocation = path; - return path; -} - - diff -r 44f391ec2172 -r 3228b7913aa4 widgets/FileFinder.h --- a/widgets/FileFinder.h Fri Mar 27 13:10:01 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2007 QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FILE_FINDER_H_ -#define _FILE_FINDER_H_ - -#include -#include - -class FileFinder : public QObject -{ - Q_OBJECT - -public: - virtual ~FileFinder(); - - enum FileType { - SessionFile, - AudioFile, - LayerFile, - LayerFileNoMidi, - SessionOrAudioFile, - ImageFile, - AnyFile - }; - - QString getOpenFileName(FileType type, QString fallbackLocation = ""); - QString getSaveFileName(FileType type, QString fallbackLocation = ""); - void registerLastOpenedFilePath(FileType type, QString path); - - QString find(FileType type, QString location, QString lastKnownLocation = ""); - - static FileFinder *getInstance(); - -protected: - FileFinder(); - static FileFinder *m_instance; - - QString findRelative(QString location, QString relativeTo); - QString locateInteractive(FileType type, QString thing); - - QString m_lastLocatedLocation; -}; - -#endif - diff -r 44f391ec2172 -r 3228b7913aa4 widgets/ImageDialog.cpp --- a/widgets/ImageDialog.cpp Fri Mar 27 13:10:01 2009 +0000 +++ b/widgets/ImageDialog.cpp Fri Mar 27 16:25:52 2009 +0000 @@ -29,7 +29,7 @@ #include "ProgressDialog.h" #include "data/fileio/FileSource.h" -#include "FileFinder.h" +#include "InteractiveFileFinder.h" #include @@ -228,7 +228,7 @@ ImageDialog::browseClicked() { QString file = - FileFinder::getInstance()->getOpenFileName(FileFinder::ImageFile); + InteractiveFileFinder::getInstance()->getOpenFileName(FileFinder::ImageFile); if (file != "") { setImage(file); diff -r 44f391ec2172 -r 3228b7913aa4 widgets/InteractiveFileFinder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/InteractiveFileFinder.cpp Fri Mar 27 16:25:52 2009 +0000 @@ -0,0 +1,514 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2007 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "InteractiveFileFinder.h" +#include "data/fileio/FileSource.h" +#include "data/fileio/AudioFileReaderFactory.h" +#include "data/fileio/DataFileReaderFactory.h" +#include "rdf/RDFImporter.h" +#include "rdf/RDFExporter.h" + +#include +#include +#include +#include +#include +#include + +#include + +InteractiveFileFinder +InteractiveFileFinder::m_instance; + +InteractiveFileFinder::InteractiveFileFinder() : + m_lastLocatedLocation("") +{ + std::cerr << "Registering interactive file finder" << std::endl; + FileFinder::registerFileFinder(this); +} + +InteractiveFileFinder::~InteractiveFileFinder() +{ +} + +QString +InteractiveFileFinder::getOpenFileName(FileType type, QString fallbackLocation) +{ + QString settingsKey; + QString lastPath = fallbackLocation; + + QString title = tr("Select file"); + QString filter = tr("All files (*.*)"); + + switch (type) { + + case SessionFile: + settingsKey = "sessionpath"; + title = tr("Select a session file"); + filter = tr("Sonic Visualiser session files (*.sv)\nRDF files (%1)\nAll files (*.*)").arg(RDFImporter::getKnownExtensions()); + break; + + case AudioFile: + settingsKey = "audiopath"; + title = "Select an audio file"; + filter = tr("Audio files (%1)\nAll files (*.*)") + .arg(AudioFileReaderFactory::getKnownExtensions()); + break; + + case LayerFile: + settingsKey = "layerpath"; + 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 (*.*)") + .arg(DataFileReaderFactory::getKnownExtensions()) + .arg(RDFImporter::getKnownExtensions()); + break; + + case LayerFileNoMidi: + settingsKey = "layerpath"; + 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 (*.*)") + .arg(DataFileReaderFactory::getKnownExtensions()) + .arg(RDFImporter::getKnownExtensions()); + break; + + case SessionOrAudioFile: + settingsKey = "lastpath"; + filter = tr("All supported files (*.sv %1 %2)\nSonic Visualiser session files (*.sv)\nAudio files (%2)\nRDF files (%1)\nAll files (*.*)") + .arg(RDFImporter::getKnownExtensions()) + .arg(AudioFileReaderFactory::getKnownExtensions()); + break; + + case ImageFile: + settingsKey = "imagepath"; + { + QStringList fmts; + QList formats = QImageReader::supportedImageFormats(); + for (QList::iterator i = formats.begin(); + i != formats.end(); ++i) { + fmts.push_back(QString("*.%1") + .arg(QString::fromLocal8Bit(*i).toLower())); + } + filter = tr("Image files (%1)\nAll files (*.*)").arg(fmts.join(" ")); + } + break; + + case AnyFile: + settingsKey = "lastpath"; + filter = tr("All supported files (*.sv %1 %2 %3)\nSonic Visualiser session files (*.sv)\nAudio files (%1)\nLayer files (%2)\nRDF files (%3)\nAll files (*.*)") + .arg(AudioFileReaderFactory::getKnownExtensions()) + .arg(DataFileReaderFactory::getKnownExtensions()) + .arg(RDFImporter::getKnownExtensions()); + break; + }; + + if (lastPath == "") { + char *home = getenv("HOME"); + if (home) lastPath = home; + else lastPath = "."; + } else if (QFileInfo(lastPath).isDir()) { + lastPath = QFileInfo(lastPath).canonicalPath(); + } else { + lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); + } + + QSettings settings; + settings.beginGroup("FileFinder"); + lastPath = settings.value(settingsKey, lastPath).toString(); + + QString path = ""; + + // Use our own QFileDialog just for symmetry with getSaveFileName below + + QFileDialog dialog; + dialog.setFilters(filter.split('\n')); + dialog.setWindowTitle(title); + dialog.setDirectory(lastPath); + + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::ExistingFile); + + if (dialog.exec()) { + QStringList files = dialog.selectedFiles(); + if (!files.empty()) path = *files.begin(); + + QFileInfo fi(path); + + if (!fi.exists()) { + + QMessageBox::critical(0, tr("File does not exist"), + tr("File not found

File \"%1\" does not exist").arg(path)); + path = ""; + + } else if (!fi.isReadable()) { + + QMessageBox::critical(0, tr("File is not readable"), + tr("File is not readable

File \"%1\" can not be read").arg(path)); + path = ""; + + } else if (fi.isDir()) { + + QMessageBox::critical(0, tr("Directory selected"), + tr("Directory selected

File \"%1\" is a directory").arg(path)); + path = ""; + + } else if (!fi.isFile()) { + + QMessageBox::critical(0, tr("Non-file selected"), + tr("Not a file

Path \"%1\" is not a file").arg(path)); + path = ""; + + } else if (fi.size() == 0) { + + QMessageBox::critical(0, tr("File is empty"), + tr("File is empty

File \"%1\" is empty").arg(path)); + path = ""; + } + } + + if (path != "") { + settings.setValue(settingsKey, + QFileInfo(path).absoluteDir().canonicalPath()); + } + + return path; +} + +QString +InteractiveFileFinder::getSaveFileName(FileType type, QString fallbackLocation) +{ + QString settingsKey; + QString lastPath = fallbackLocation; + + QString title = tr("Select file"); + QString filter = tr("All files (*.*)"); + + switch (type) { + + case SessionFile: + settingsKey = "savesessionpath"; + title = tr("Select a session file"); + filter = tr("Sonic Visualiser session files (*.sv)\nAll files (*.*)"); + break; + + case AudioFile: + settingsKey = "saveaudiopath"; + title = "Select an audio file"; + title = tr("Select a file to export to"); + filter = tr("WAV audio files (*.wav)\nAll files (*.*)"); + break; + + case LayerFile: + settingsKey = "savelayerpath"; + title = tr("Select a file to export to"); + 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()); + break; + + case LayerFileNoMidi: + settingsKey = "savelayerpath"; + title = tr("Select a file to export to"); + 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()); + break; + + case SessionOrAudioFile: + std::cerr << "ERROR: Internal error: InteractiveFileFinder::getSaveFileName: SessionOrAudioFile cannot be used here" << std::endl; + abort(); + + case ImageFile: + settingsKey = "saveimagepath"; + title = tr("Select a file to export to"); + filter = tr("Portable Network Graphics files (*.png)\nAll files (*.*)"); + break; + + case AnyFile: + std::cerr << "ERROR: Internal error: InteractiveFileFinder::getSaveFileName: AnyFile cannot be used here" << std::endl; + abort(); + }; + + if (lastPath == "") { + char *home = getenv("HOME"); + if (home) lastPath = home; + else lastPath = "."; + } else if (QFileInfo(lastPath).isDir()) { + lastPath = QFileInfo(lastPath).canonicalPath(); + } else { + lastPath = QFileInfo(lastPath).absoluteDir().canonicalPath(); + } + + QSettings settings; + settings.beginGroup("FileFinder"); + lastPath = settings.value(settingsKey, lastPath).toString(); + + QString path = ""; + + // Use our own QFileDialog instead of static functions, as we may + // need to adjust the file extension based on the selected filter + + QFileDialog dialog; + dialog.setFilters(filter.split('\n')); + dialog.setWindowTitle(title); + dialog.setDirectory(lastPath); + + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setConfirmOverwrite(false); // we'll do that + + if (type == SessionFile) { + dialog.setDefaultSuffix("sv"); + } else if (type == AudioFile) { + dialog.setDefaultSuffix("wav"); + } else if (type == ImageFile) { + dialog.setDefaultSuffix("png"); + } + + bool good = false; + + while (!good) { + + path = ""; + + if (!dialog.exec()) break; + + QStringList files = dialog.selectedFiles(); + if (files.empty()) break; + path = *files.begin(); + + QFileInfo fi(path); + + std::cerr << "type = " << type << ", suffix = " << fi.suffix().toStdString() << std::endl; + + if ((type == LayerFile || type == LayerFileNoMidi) + && fi.suffix() == "") { + QString expectedExtension; + QString selectedFilter = dialog.selectedFilter(); + if (selectedFilter.contains(".svl")) { + expectedExtension = "svl"; + } else if (selectedFilter.contains(".txt")) { + expectedExtension = "txt"; + } else if (selectedFilter.contains(".csv")) { + expectedExtension = "csv"; + } else if (selectedFilter.contains(".mid")) { + expectedExtension = "mid"; + } else if (selectedFilter.contains(".ttl")) { + expectedExtension = "ttl"; + } + std::cerr << "expected extension = " << expectedExtension.toStdString() << std::endl; + if (expectedExtension != "") { + path = QString("%1.%2").arg(path).arg(expectedExtension); + fi = QFileInfo(path); + } + } + + if (fi.isDir()) { + QMessageBox::critical(0, tr("Directory selected"), + tr("Directory selected

File \"%1\" is a directory").arg(path)); + continue; + } + + if (fi.exists()) { + if (QMessageBox::question(0, tr("File exists"), + tr("File exists

The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path), + QMessageBox::Ok, + QMessageBox::Cancel) != QMessageBox::Ok) { + continue; + } + } + + good = true; + } + + if (path != "") { + settings.setValue(settingsKey, + QFileInfo(path).absoluteDir().canonicalPath()); + } + + return path; +} + +void +InteractiveFileFinder::registerLastOpenedFilePath(FileType type, QString path) +{ + QString settingsKey; + + switch (type) { + case SessionFile: + settingsKey = "sessionpath"; + break; + + case AudioFile: + settingsKey = "audiopath"; + break; + + case LayerFile: + settingsKey = "layerpath"; + break; + + case LayerFileNoMidi: + settingsKey = "layerpath"; + break; + + case SessionOrAudioFile: + settingsKey = "lastpath"; + break; + + case ImageFile: + settingsKey = "imagepath"; + break; + + case AnyFile: + settingsKey = "lastpath"; + break; + } + + if (path != "") { + QSettings settings; + settings.beginGroup("FileFinder"); + path = QFileInfo(path).absoluteDir().canonicalPath(); + settings.setValue(settingsKey, path); + settings.setValue("lastpath", path); + } +} + +QString +InteractiveFileFinder::find(FileType type, QString location, QString lastKnownLocation) +{ + if (FileSource::canHandleScheme(location)) { + if (FileSource(location).isAvailable()) { + std::cerr << "InteractiveFileFinder::find: ok, it's available... returning" << std::endl; + return location; + } + } + + if (QFileInfo(location).exists()) return location; + + QString foundAt = ""; + + if ((foundAt = findRelative(location, lastKnownLocation)) != "") { + return foundAt; + } + + if ((foundAt = findRelative(location, m_lastLocatedLocation)) != "") { + return foundAt; + } + + return locateInteractive(type, location); +} + +QString +InteractiveFileFinder::findRelative(QString location, QString relativeTo) +{ + if (relativeTo == "") return ""; + + std::cerr << "Looking for \"" << location.toStdString() << "\" next to \"" + << relativeTo.toStdString() << "\"..." << std::endl; + + QString fileName; + QString resolved; + + if (FileSource::isRemote(location)) { + fileName = QUrl(location).path().section('/', -1, -1, + QString::SectionSkipEmpty); + } else { + if (QUrl(location).scheme() == "file") { + location = QUrl(location).toLocalFile(); + } + fileName = QFileInfo(location).fileName(); + } + + if (FileSource::isRemote(relativeTo)) { + resolved = QUrl(relativeTo).resolved(fileName).toString(); + if (!FileSource(resolved).isAvailable()) resolved = ""; + std::cerr << "resolved: " << resolved.toStdString() << std::endl; + } else { + if (QUrl(relativeTo).scheme() == "file") { + relativeTo = QUrl(relativeTo).toLocalFile(); + } + resolved = QFileInfo(relativeTo).dir().filePath(fileName); + if (!QFileInfo(resolved).exists() || + !QFileInfo(resolved).isFile() || + !QFileInfo(resolved).isReadable()) { + resolved = ""; + } + } + + return resolved; +} + +QString +InteractiveFileFinder::locateInteractive(FileType type, QString thing) +{ + QString question; + if (type == AudioFile) { + question = tr("File not found

Audio file \"%1\" could not be opened.\nDo you want to locate it?"); + } else { + question = tr("File not found

File \"%1\" could not be opened.\nDo you want to locate it?"); + } + + QString path = ""; + bool done = false; + + while (!done) { + + int rv = QMessageBox::question + (0, + tr("Failed to open file"), + question.arg(thing), + tr("Locate file..."), + tr("Use URL..."), + tr("Cancel"), + 0, 2); + + switch (rv) { + + case 0: // Locate file + + if (QFileInfo(thing).dir().exists()) { + path = QFileInfo(thing).dir().canonicalPath(); + } + + path = getOpenFileName(type, path); + done = (path != ""); + break; + + case 1: // Use URL + { + bool ok = false; + path = QInputDialog::getText + (0, tr("Use URL"), + tr("Please enter the URL to use for this file:"), + QLineEdit::Normal, "", &ok); + + if (ok && path != "") { + if (FileSource(path).isAvailable()) { + done = true; + } else { + QMessageBox::critical + (0, tr("Failed to open location"), + tr("Failed to open location

URL \"%1\" could not be opened").arg(path)); + path = ""; + } + } + break; + } + + case 2: // Cancel + path = ""; + done = true; + break; + } + } + + if (path != "") m_lastLocatedLocation = path; + return path; +} + + diff -r 44f391ec2172 -r 3228b7913aa4 widgets/InteractiveFileFinder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/InteractiveFileFinder.h Fri Mar 27 16:25:52 2009 +0000 @@ -0,0 +1,51 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2007 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _INTERACTIVE_FILE_FINDER_H_ +#define _INTERACTIVE_FILE_FINDER_H_ + +#include "data/fileio/FileFinder.h" + +#include +#include + +class InteractiveFileFinder : public QObject, + public FileFinder +{ + Q_OBJECT + +public: + virtual ~InteractiveFileFinder(); + + QString getOpenFileName(FileType type, QString fallbackLocation = ""); + QString getSaveFileName(FileType type, QString fallbackLocation = ""); + void registerLastOpenedFilePath(FileType type, QString path); + + QString find(FileType type, QString location, QString lastKnownLocation = ""); + + static InteractiveFileFinder *getInstance() { return &m_instance; } + +protected: + InteractiveFileFinder(); + static InteractiveFileFinder m_instance; + + QString findRelative(QString location, QString relativeTo); + QString locateInteractive(FileType type, QString thing); + + QString m_lastLocatedLocation; +}; + +#endif + diff -r 44f391ec2172 -r 3228b7913aa4 widgets/widgets.pro --- a/widgets/widgets.pro Fri Mar 27 13:10:01 2009 +0000 +++ b/widgets/widgets.pro Fri Mar 27 16:25:52 2009 +0000 @@ -21,7 +21,7 @@ CommandHistory.h \ CSVFormatDialog.h \ Fader.h \ - FileFinder.h \ + InteractiveFileFinder.h \ IconLoader.h \ ImageDialog.h \ ItemEditDialog.h \ @@ -58,7 +58,7 @@ CommandHistory.cpp \ CSVFormatDialog.cpp \ Fader.cpp \ - FileFinder.cpp \ + InteractiveFileFinder.cpp \ IconLoader.cpp \ ImageDialog.cpp \ ItemEditDialog.cpp \