# HG changeset patch # User Chris Cannam # Date 1146003283 0 # Node ID f277a171749dd2872eb275e58fecf0c937ead384 # Parent 8739096929dd01c514af98e9e956a027311da4e3 * Pull out temporary directory management into its own class * Make sure playback plugins get a default sample path in their original play parameters configuration * Save play parameters to .sv file (we aren't reloading yet though) diff -r 8739096929dd -r f277a171749d base/PlayParameterRepository.cpp --- a/base/PlayParameterRepository.cpp Mon Apr 24 17:06:32 2006 +0000 +++ b/base/PlayParameterRepository.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -17,6 +17,8 @@ #include "PlayParameters.h" //!!! shouldn't be including this here -- restructure needed + +//!!! should the AudioGenerator actually implement all this stuff itself? do we even want this class? #include "audioio/AudioGenerator.h" #include diff -r 8739096929dd -r f277a171749d base/PlayParameters.cpp --- a/base/PlayParameters.cpp Mon Apr 24 17:06:32 2006 +0000 +++ b/base/PlayParameters.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -17,6 +17,27 @@ #include +QString +PlayParameters::toXmlString(QString indent, + QString extraAttributes) const +{ + QString s; + s += indent; + s += QString("\n"; + } else { + s += "/>\n"; + } + return s; +} + void PlayParameters::setPlayMuted(bool muted) { diff -r 8739096929dd -r f277a171749d base/PlayParameters.h --- a/base/PlayParameters.h Mon Apr 24 17:06:32 2006 +0000 +++ b/base/PlayParameters.h Tue Apr 25 22:14:43 2006 +0000 @@ -18,7 +18,9 @@ #include -class PlayParameters : public QObject +#include "XmlExportable.h" + +class PlayParameters : public QObject, public XmlExportable { Q_OBJECT @@ -32,6 +34,9 @@ virtual QString getPlayPluginId() const { return m_playPluginId; } virtual QString getPlayPluginConfiguration() const { return m_playPluginConfiguration; } + virtual QString toXmlString(QString indent = "", + QString extraAttributes = "") const; + public slots: virtual void setPlayMuted(bool muted); virtual void setPlayAudible(bool nonMuted); diff -r 8739096929dd -r f277a171749d base/TempDirectory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/TempDirectory.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -0,0 +1,196 @@ +/* -*- 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 2006 Chris Cannam. + + 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 "TempDirectory.h" + +#include +#include +#include + +#include +#include + +TempDirectory * +TempDirectory::m_instance = new TempDirectory; + +TempDirectory * +TempDirectory::instance() +{ + return m_instance; +} + +TempDirectory::DirectoryCreationFailed::DirectoryCreationFailed(QString directory) throw() : + m_directory(directory) +{ + std::cerr << "ERROR: Directory creation failed for directory: " + << directory.toLocal8Bit().data() << std::endl; +} + +const char * +TempDirectory::DirectoryCreationFailed::what() const throw() +{ + return QString("Directory creation failed for \"%1\"") + .arg(m_directory).toLocal8Bit().data(); +} + +TempDirectory::TempDirectory() : + m_tmpdir("") +{ +} + +TempDirectory::~TempDirectory() +{ + std::cerr << "TempDirectory::~TempDirectory" << std::endl; + + cleanup(); +} + +void +TempDirectory::cleanup() +{ + cleanupDirectory(""); +} + +QString +TempDirectory::getPath() +{ + QMutexLocker locker(&m_mutex); + + if (m_tmpdir != "") return m_tmpdir; + + QDir systemTempDir = QDir::temp(); + + // Generate a temporary directory. Qt4.1 doesn't seem to be able + // to do this for us, and mkdtemp is not standard. This method is + // based on the way glibc does mkdtemp. + + static QString chars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + QString suffix; + int padlen = 6, attempts = 100; + unsigned int r = time(0) ^ getpid(); + + for (int i = 0; i < padlen; ++i) { + suffix += "X"; + } + + for (int j = 0; j < attempts; ++j) { + + unsigned int v = r; + + for (int i = 0; i < padlen; ++i) { + suffix[i] = chars[v % 62]; + v /= 62; + } + + QString candidate = QString("sv_%1").arg(suffix); + + if (QDir::temp().mkpath(candidate)) { + m_tmpdir = systemTempDir.filePath(candidate); + break; + } + + r = r + 7777; + } + + if (m_tmpdir == "") { + throw DirectoryCreationFailed(QString("temporary subdirectory in %1") + .arg(systemTempDir.canonicalPath())); + } + + return m_tmpdir; +} + +QString +TempDirectory::getSubDirectoryPath(QString subdir) +{ + QString tmpdirpath = getPath(); + + QMutexLocker locker(&m_mutex); + + QDir tmpdir(tmpdirpath); + QFileInfo fi(tmpdir.filePath(subdir)); + + if (!fi.exists()) { + if (!tmpdir.mkdir(subdir)) { + throw DirectoryCreationFailed(fi.filePath()); + } else { + return fi.filePath(); + } + } else if (fi.isDir()) { + return fi.filePath(); + } else { + throw DirectoryCreationFailed(fi.filePath()); + } +} + +void +TempDirectory::cleanupDirectory(QString tmpdir) +{ + bool isRoot = false; + + if (tmpdir == "") { + + m_mutex.lock(); + + isRoot = true; + tmpdir = m_tmpdir; + + if (tmpdir == "") { + m_mutex.unlock(); + return; + } + } + + QDir dir(tmpdir); + dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + + for (unsigned int i = 0; i < dir.count(); ++i) { + + QFileInfo fi(dir.filePath(dir[i])); + + if (fi.isDir()) { + cleanupDirectory(fi.absoluteFilePath()); + } else { + if (!QFile(fi.absoluteFilePath()).remove()) { + std::cerr << "WARNING: TempDirectory::cleanup: " + << "Failed to unlink file \"" + << fi.absoluteFilePath().toStdString() << "\"" + << std::endl; + } + } + } + + QString dirname = dir.dirName(); + if (dirname != "") { + if (!dir.cdUp()) { + std::cerr << "WARNING: TempDirectory::cleanup: " + << "Failed to cd to parent directory of " + << tmpdir.toStdString() << std::endl; + return; + } + if (!dir.rmdir(dirname)) { + std::cerr << "WARNING: TempDirectory::cleanup: " + << "Failed to remove directory " + << dirname.toStdString() << std::endl; + } + } + + if (isRoot) { + m_tmpdir = ""; + m_mutex.unlock(); + } +} diff -r 8739096929dd -r f277a171749d base/TempDirectory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/TempDirectory.h Tue Apr 25 22:14:43 2006 +0000 @@ -0,0 +1,81 @@ +/* -*- 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 2006 Chris Cannam. + + 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 _TEMP_DIRECTORY_H_ +#define _TEMP_DIRECTORY_H_ + +#include +#include + +#include + +/** + * A class that manages the creation and removal of a temporary + * directory tree to store data during the program run. There is one + * root temporary directory for the program, created on demand and + * deleted when the program exits. + * + * This class is thread safe. + */ + +class TempDirectory +{ +public: + static TempDirectory *instance(); + + virtual ~TempDirectory(); + + class DirectoryCreationFailed : virtual public std::exception + { + public: + DirectoryCreationFailed(QString directory) throw(); + virtual DirectoryCreationFailed::~DirectoryCreationFailed() throw() { } + virtual const char *what() const throw(); + + protected: + QString m_directory; + }; + + /** + * Create the root temporary directory if necessary, and return + * its path. Throw DirectoryCreationFailed if the directory + * cannot be created. + */ + QString getPath(); + + /** + * Create an immediate subdirectory of the root temporary + * directory of the given name, if it doesn't already exist, and + * return its path. Throw DirectoryCreationFailed if the + * directory cannot be created. + */ + QString getSubDirectoryPath(QString subdir); + + /** + * Delete the temporary directory (before exiting). + */ + void cleanup(); + +protected: + TempDirectory(); + void cleanupDirectory(QString tmpDir); + QString m_tmpdir; + QMutex m_mutex; + + static TempDirectory *m_instance; +}; + + +#endif diff -r 8739096929dd -r f277a171749d base/ViewManager.cpp --- a/base/ViewManager.cpp Mon Apr 24 17:06:32 2006 +0000 +++ b/base/ViewManager.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -20,11 +20,6 @@ #include -#include -#include - -#include - // #define DEBUG_VIEW_MANAGER 1 ViewManager::ViewManager() : @@ -52,7 +47,6 @@ ViewManager::~ViewManager() { - if (m_tmpdir != "") deleteTemporaryDirectory(m_tmpdir); } unsigned long @@ -361,94 +355,6 @@ } } -QString -ViewManager::getTemporaryDirectory() -{ - if (m_tmpdir != "") return m_tmpdir; - - // Generate a temporary directory. Qt4.1 doesn't seem to be able - // to do this for us, and mkdtemp is not standard. This method is - // based on the way glibc does mkdtemp. - - static QString chars = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - - QString suffix; - int padlen = 6, attempts = 100; - unsigned int r = time(0) ^ getpid(); - - for (int i = 0; i < padlen; ++i) { - suffix += "X"; - } - - for (int j = 0; j < attempts; ++j) { - - unsigned int v = r; - - for (int i = 0; i < padlen; ++i) { - suffix[i] = chars[v % 62]; - v /= 62; - } - - QString candidate = QString("sv_%1").arg(suffix); - - if (QDir::temp().mkpath(candidate)) { - m_tmpdir = QDir::temp().filePath(candidate); - break; - } - - r = r + 7777; - } - - if (m_tmpdir == "") { - std::cerr << "ERROR: ViewManager::getTemporaryDirectory: " - << "Unable to create a temporary directory!" << std::endl; - assert(0); - } - - return m_tmpdir; -} - -void -ViewManager::deleteTemporaryDirectory(QString tmpdir) -{ - if (tmpdir == "") return; - - QDir dir(tmpdir); - dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); - - for (unsigned int i = 0; i < dir.count(); ++i) { - - QFileInfo fi(dir.filePath(dir[i])); - - if (fi.isDir()) { - deleteTemporaryDirectory(fi.absoluteFilePath()); - } else { - if (!QFile(fi.absoluteFilePath()).remove()) { - std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: " - << "Failed to unlink file \"" - << fi.absoluteFilePath().toStdString() << "\"" - << std::endl; - } - } - } - - QString dirname = dir.dirName(); - if (dirname != "") { - if (!dir.cdUp()) { - std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: " - << "Failed to cd to parent directory of " - << tmpdir.toStdString() << std::endl; - return; - } - if (!dir.rmdir(dirname)) { - std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: " - << "Failed to remove directory " - << dirname.toStdString() << std::endl; - } - } -} - #ifdef INCLUDE_MOCFILES #include "ViewManager.moc.cpp" #endif diff -r 8739096929dd -r f277a171749d base/ViewManager.h --- a/base/ViewManager.h Mon Apr 24 17:06:32 2006 +0000 +++ b/base/ViewManager.h Tue Apr 25 22:14:43 2006 +0000 @@ -105,8 +105,6 @@ void setOverlayMode(OverlayMode mode); OverlayMode getOverlayMode() const { return m_overlayMode; } - QString getTemporaryDirectory(); - signals: /** Emitted when a widget pans. The originator identifies the widget. */ void centreFrameChanged(void *originator, unsigned long frame, bool locked); @@ -184,9 +182,6 @@ }; OverlayMode m_overlayMode; - - void deleteTemporaryDirectory(QString); - QString m_tmpdir; }; #endif diff -r 8739096929dd -r f277a171749d plugin/PluginXml.cpp --- a/plugin/PluginXml.cpp Mon Apr 24 17:06:32 2006 +0000 +++ b/plugin/PluginXml.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -36,6 +36,24 @@ PluginXml::~PluginXml() { } QString +PluginXml::encodeConfigurationChars(QString text) +{ + QString rv(text); + rv.replace(";", "[[SEMICOLON]]"); + rv.replace("=", "[[EQUALS]]"); + return rv; +} + +QString +PluginXml::decodeConfigurationChars(QString text) +{ + QString rv(text); + rv.replace("[[SEMICOLON]]", ";"); + rv.replace("[[EQUALS]]", "="); + return rv; +} + +QString PluginXml::toXmlString(QString indent, QString extraAttributes) const { QString s; @@ -74,10 +92,8 @@ i != configurePairs.end(); ++i) { QString key = i->first.c_str(); QString value = i->second.c_str(); - key.replace(";", "[[SEMICOLON]]"); - key.replace("=", "[[EQUALS]]"); - value.replace(";", "[[SEMICOLON]]"); - value.replace("=", "[[EQUALS]]"); + key = encodeConfigurationChars(key); + value = encodeConfigurationChars(value); if (config != "") config += ";"; config += QString("%1=%2").arg(key).arg(value); } @@ -128,10 +144,8 @@ continue; } QString key(kv[0]), value(kv[1]); - key.replace("[[SEMICOLON]]", ";"); - key.replace("[[EQUALS]]", ";"); - value.replace("[[SEMICOLON]]", ";"); - value.replace("[[SEMICOLON]]", ";"); + key = decodeConfigurationChars(key); + value = decodeConfigurationChars(value); rtpi->configure(key.toStdString(), value.toStdString()); } } diff -r 8739096929dd -r f277a171749d plugin/PluginXml.h --- a/plugin/PluginXml.h Mon Apr 24 17:06:32 2006 +0000 +++ b/plugin/PluginXml.h Tue Apr 25 22:14:43 2006 +0000 @@ -47,6 +47,9 @@ */ virtual void setParametersFromXml(QString xml); + static QString encodeConfigurationChars(QString text); + static QString decodeConfigurationChars(QString text); + protected: QString stripInvalidParameterNameCharacters(QString) const; diff -r 8739096929dd -r f277a171749d plugin/plugins/SamplePlayer.cpp --- a/plugin/plugins/SamplePlayer.cpp Mon Apr 24 17:06:32 2006 +0000 +++ b/plugin/plugins/SamplePlayer.cpp Tue Apr 25 22:14:43 2006 +0000 @@ -217,6 +217,9 @@ QMutexLocker locker(&player->m_mutex); + + //!!! What do we do if receiving an antique path pointing at things that no longer exist? + player->m_samplePath = value; if (player->m_sampleSearchComplete) { @@ -340,6 +343,8 @@ { if (m_sampleSearchComplete) return; + m_samples.clear(); + std::cerr << "Current working directory is \"" << getcwd(0, 0) << "\"" << std::endl; std::cerr << "SamplePlayer::searchSamples: Path is \""