# HG changeset patch # User Chris Cannam # Date 1142617108 0 # Node ID bac8b14ab35506f445f46df8879febf33d3abdb3 # Parent 5364a9d338a2690b9997017a5a0969f5e2f6af34 * Add menu for re-adding existing layers * Fix layer tree window so that it at least approximates correct * Add bundled operations in command history, for use with things like multiple consecutive changes to a parameter value * Disambiguate plugins that happen to have identical descriptions * Add spectral centroid plugin (could use some parameters!) * Some other fixes diff -r 5364a9d338a2 -r bac8b14ab355 base/Command.cpp --- a/base/Command.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/base/Command.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -41,6 +41,12 @@ } } +bool +MacroCommand::haveCommands() const +{ + return !m_commands.empty(); +} + void MacroCommand::execute() { @@ -57,3 +63,15 @@ } } +QString +MacroCommand::getName() const +{ + return m_name; +} + +void +MacroCommand::setName(QString name) +{ + m_name = name; +} + diff -r 5364a9d338a2 -r bac8b14ab355 base/Command.h --- a/base/Command.h Thu Mar 16 18:46:00 2006 +0000 +++ b/base/Command.h Fri Mar 17 17:38:28 2006 +0000 @@ -31,13 +31,13 @@ virtual void addCommand(Command *command); virtual void deleteCommand(Command *command); - virtual bool haveCommands() const { return !m_commands.empty(); } + virtual bool haveCommands() const; virtual void execute(); virtual void unexecute(); - virtual QString getName() const { return m_name; } - virtual void setName(QString name) { m_name = name; } + virtual QString getName() const; + virtual void setName(QString name); protected: QString m_name; diff -r 5364a9d338a2 -r bac8b14ab355 base/CommandHistory.cpp --- a/base/CommandHistory.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/base/CommandHistory.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -35,8 +36,11 @@ m_redoLimit(50), m_menuLimit(15), m_savedAt(0), - m_currentMacro(0), - m_executeMacro(false) + m_currentCompound(0), + m_executeCompound(false), + m_currentBundle(0), + m_bundleTimer(0), + m_bundleTimeout(5000) { m_undoAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this); m_undoAction->setShortcut(tr("Ctrl+Z")); @@ -83,6 +87,8 @@ void CommandHistory::clear() { + std::cerr << "CommandHistory::clear()" << std::endl; + closeBundle(); m_savedAt = -1; clearStack(m_undoStack); clearStack(m_redoStack); @@ -104,18 +110,26 @@ } void -CommandHistory::addCommand(Command *command, bool execute) +CommandHistory::addCommand(Command *command, bool execute, bool bundle) { if (!command) return; - if (m_currentMacro) { - addToMacro(command); + if (m_currentCompound) { + addToCompound(command); return; } - std::cerr << "MVCH::addCommand: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; + if (bundle) { + addToBundle(command, execute); + return; + } else if (m_currentBundle) { + closeBundle(); + } + + std::cerr << "CommandHistory::addCommand: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; // We can't redo after adding a command + std::cerr << "CommandHistory::clearing redo stack" << std::endl; clearStack(m_redoStack); // can we reach savedAt? @@ -137,39 +151,83 @@ } void -CommandHistory::addToMacro(Command *command) +CommandHistory::addToBundle(Command *command, bool execute) { - std::cerr << "MVCH::addToMacro: " << command->getName().toLocal8Bit().data() << std::endl; + if (m_currentBundle) { + if (!command || (command->getName() != m_currentBundleName)) { + closeBundle(); + } + } - if (m_executeMacro) command->execute(); - m_currentMacro->addCommand(command); + if (!command) return; + + if (!m_currentBundle) { + // need to addCommand before setting m_currentBundle, as addCommand + // with bundle false will reset m_currentBundle to 0 + MacroCommand *mc = new MacroCommand(command->getName()); + addCommand(mc, false); + m_currentBundle = mc; + m_currentBundleName = command->getName(); + } + + if (execute) command->execute(); + m_currentBundle->addCommand(command); + + delete m_bundleTimer; + m_bundleTimer = new QTimer(this); + connect(m_bundleTimer, SIGNAL(timeout()), this, SLOT(bundleTimerTimeout())); + m_bundleTimer->start(m_bundleTimeout); +} + +void +CommandHistory::closeBundle() +{ + m_currentBundle = 0; + m_currentBundleName = ""; +} + +void +CommandHistory::bundleTimerTimeout() +{ + closeBundle(); +} + +void +CommandHistory::addToCompound(Command *command) +{ + std::cerr << "CommandHistory::addToCompound: " << command->getName().toLocal8Bit().data() << std::endl; + + if (m_executeCompound) command->execute(); + m_currentCompound->addCommand(command); } void CommandHistory::startCompoundOperation(QString name, bool execute) { - if (m_currentMacro) { - std::cerr << "MVCH::startCompoundOperation: ERROR: compound operation already in progress!" << std::endl; - std::cerr << "(name is " << m_currentMacro->getName().toLocal8Bit().data() << ")" << std::endl; + if (m_currentCompound) { + std::cerr << "CommandHistory::startCompoundOperation: ERROR: compound operation already in progress!" << std::endl; + std::cerr << "(name is " << m_currentCompound->getName().toLocal8Bit().data() << ")" << std::endl; } - - m_currentMacro = new MacroCommand(name); - m_executeMacro = execute; + + closeBundle(); + + m_currentCompound = new MacroCommand(name); + m_executeCompound = execute; } void CommandHistory::endCompoundOperation() { - if (!m_currentMacro) { - std::cerr << "MVCH::endCompoundOperation: ERROR: no compound operation in progress!" << std::endl; + if (!m_currentCompound) { + std::cerr << "CommandHistory::endCompoundOperation: ERROR: no compound operation in progress!" << std::endl; } - Command *toAdd = m_currentMacro; - m_currentMacro = 0; + Command *toAdd = m_currentCompound; + m_currentCompound = 0; // We don't execute the macro command here, because we have been // executing the individual commands as we went along if - // m_executeMacro was true. + // m_executeCompound was true. addCommand(toAdd, false); } @@ -190,6 +248,8 @@ { if (m_undoStack.empty()) return; + closeBundle(); + Command *command = m_undoStack.top(); command->unexecute(); emit commandExecuted(); @@ -209,6 +269,8 @@ { if (m_redoStack.empty()) return; + closeBundle(); + Command *command = m_redoStack.top(); command->execute(); emit commandExecuted(); @@ -249,8 +311,15 @@ } void +CommandHistory::setBundleTimeout(int ms) +{ + m_bundleTimeout = ms; +} + +void CommandHistory::documentSaved() { + closeBundle(); m_savedAt = m_undoStack.size(); } @@ -276,7 +345,7 @@ for (i = 0; i < limit; ++i) { Command *command = stack.top(); - std::cerr << "MVCH::clipStack: Saving recent command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; + std::cerr << "CommandHistory::clipStack: Saving recent command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl; tempStack.push(stack.top()); stack.pop(); } @@ -296,7 +365,7 @@ while (!stack.empty()) { Command *command = stack.top(); // Not safe to call getName() on a command about to be deleted - std::cerr << "MVCH::clearStack: About to delete command " << command << std::endl; + std::cerr << "CommandHistory::clearStack: About to delete command " << command << std::endl; delete command; stack.pop(); } diff -r 5364a9d338a2 -r bac8b14ab355 base/CommandHistory.h --- a/base/CommandHistory.h Thu Mar 16 18:46:00 2006 +0000 +++ b/base/CommandHistory.h Fri Mar 17 17:38:28 2006 +0000 @@ -32,6 +32,7 @@ class QAction; class QMenu; class QToolBar; +class QTimer; /** * The CommandHistory class stores a list of executed commands and @@ -57,7 +58,27 @@ void registerMenu(QMenu *menu); void registerToolbar(QToolBar *toolbar); - void addCommand(Command *command, bool execute = true); + /** + * Add a command to the command history. + * + * If execute is true, the command will be executed before being + * added. Otherwise it will be assumed to have been already + * executed -- a command should not be added to the history unless + * its work has actually been done somehow! + * + * If a compound operation is in use (see startCompoundOperation + * below), the execute status of the compound operation will + * override any value of execute passed to this method. + * + * If bundle is true, the command will be a candidate for bundling + * with any adjacent bundeable commands that have the same name, + * into a single compound command. This is useful for small + * commands that may be executed repeatedly altering the same data + * (e.g. type text, set a parameter) whose number and extent is + * not known in advance. The bundle parameter will be ignored if + * a compound operation is already in use. + */ + void addCommand(Command *command, bool execute = true, bool bundle = false); /// Return the maximum number of items in the undo history. int getUndoLimit() const { return m_undoLimit; } @@ -77,6 +98,12 @@ /// Set the maximum number of items in the menus. void setMenuLimit(int limit); + /// Return the time after which a bundle will be closed if nothing is added. + int getBundleTimeout() const { return m_bundleTimeout; } + + /// Set the time after which a bundle will be closed if nothing is added. + void setBundleTimeout(int msec); + /// Start recording commands to batch up into a single compound command. void startCompoundOperation(QString name, bool execute); @@ -109,7 +136,8 @@ void redo(); void undoActivated(QAction *); void redoActivated(QAction *); - + void bundleTimerTimeout(); + signals: /** * Emitted whenever a command has just been executed or @@ -157,9 +185,16 @@ int m_menuLimit; int m_savedAt; - MacroCommand *m_currentMacro; - bool m_executeMacro; - void addToMacro(Command *command); + MacroCommand *m_currentCompound; + bool m_executeCompound; + void addToCompound(Command *command); + + MacroCommand *m_currentBundle; + QString m_currentBundleName; + QTimer *m_bundleTimer; + int m_bundleTimeout; + void addToBundle(Command *command, bool execute); + void closeBundle(); void updateActions(); diff -r 5364a9d338a2 -r bac8b14ab355 base/Layer.cpp --- a/base/Layer.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/base/Layer.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -9,6 +9,7 @@ #include "Layer.h" #include "View.h" +#include "Model.h" #include @@ -31,6 +32,23 @@ (LayerFactory::instance()->getLayerType(this)); } +QString +Layer::getLayerPresentationName() const +{ + QString layerName = objectName(); + QString modelName; + if (getModel()) modelName = getModel()->objectName(); + + QString text; + if (modelName != "") { + text = QString("%1: %2").arg(modelName).arg(layerName); + } else { + text = layerName; + } + + return text; +} + void Layer::setObjectName(const QString &name) { diff -r 5364a9d338a2 -r bac8b14ab355 base/Layer.h --- a/base/Layer.h Thu Mar 16 18:46:00 2006 +0000 +++ b/base/Layer.h Fri Mar 17 17:38:28 2006 +0000 @@ -66,6 +66,8 @@ return objectName(); } + virtual QString getLayerPresentationName() const; + virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; } virtual void paintVerticalScale(View *, QPainter &, QRect) const { } diff -r 5364a9d338a2 -r bac8b14ab355 base/PropertyContainer.cpp --- a/base/PropertyContainer.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/base/PropertyContainer.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -57,7 +57,7 @@ if (value == currentValue) return; CommandHistory::getInstance()->addCommand - (new SetPropertyCommand(this, name, value)); + (new SetPropertyCommand(this, name, value), true, true); // bundled } PropertyContainer::SetPropertyCommand::SetPropertyCommand(PropertyContainer *pc, diff -r 5364a9d338a2 -r bac8b14ab355 plugin/FeatureExtractionPluginFactory.cpp --- a/plugin/FeatureExtractionPluginFactory.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/plugin/FeatureExtractionPluginFactory.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -13,7 +13,7 @@ #include "plugins/BeatDetect.h" //!!! #include "plugins/ChromagramPlugin.h" //!!! #include "plugins/ZeroCrossing.h" //!!! -// NOTE: added by Martin Gasser +#include "plugins/SpectralCentroid.h" //!!! #include "plugins/TonalChangeDetect.h" //!!! #include @@ -69,8 +69,8 @@ rv.push_back("sv:_builtin:beats"); //!!! rv.push_back("sv:_builtin:chromagram"); //!!! rv.push_back("sv:_builtin:zerocrossing"); //!!! - // NOTE: added by Martin Gasser - rv.push_back("sv:_builtin:tonalchange"); //!!! + rv.push_back("sv:_builtin:spectralcentroid"); //!!! + rv.push_back("sv:_builtin:tonalchange"); //!!! return rv; } @@ -103,7 +103,10 @@ return new ZeroCrossing(inputSampleRate); //!!! } - // NOTE: added by Martin Gasser + if (label == "spectralcentroid") { + return new SpectralCentroid(inputSampleRate); //!!! + } + if (label == "tonalchange") { return new TonalChangeDetect(inputSampleRate); //!!! } diff -r 5364a9d338a2 -r bac8b14ab355 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Thu Mar 16 18:46:00 2006 +0000 +++ b/transform/TransformFactory.cpp Fri Mar 17 17:38:28 2006 +0000 @@ -47,10 +47,11 @@ void TransformFactory::populateTransforms() { - //!!! std::vector fexplugs = FeatureExtractionPluginFactory::getAllPluginIdentifiers(); + std::map makers; + for (size_t i = 0; i < fexplugs.size(); ++i) { QString pluginId = fexplugs[i]; @@ -63,8 +64,6 @@ continue; } - //!!! well, really we want to be able to query this without having to instantiate - FeatureExtractionPlugin *plugin = factory->instantiatePlugin(pluginId, 48000); @@ -93,8 +92,44 @@ } m_transforms[transformName] = userDescription; + + makers[transformName] = plugin->getMaker().c_str(); } } + + // disambiguate plugins with similar descriptions + + std::map descriptions; + + for (TransformMap::iterator i = m_transforms.begin(); i != m_transforms.end(); + ++i) { + + QString name = i->first, description = i->second; + + ++descriptions[description]; + ++descriptions[QString("%1 [%2]").arg(description).arg(makers[name])]; + } + + std::map counts; + TransformMap newMap; + + for (TransformMap::iterator i = m_transforms.begin(); i != m_transforms.end(); + ++i) { + + QString name = i->first, description = i->second; + + if (descriptions[description] > 1) { + description = QString("%1 [%2]").arg(description).arg(makers[name]); + if (descriptions[description] > 1) { + description = QString("%1 <%2>") + .arg(description).arg(++counts[description]); + } + } + + newMap[name] = description; + } + + m_transforms = newMap; } QString diff -r 5364a9d338a2 -r bac8b14ab355 transform/TransformFactory.h --- a/transform/TransformFactory.h Thu Mar 16 18:46:00 2006 +0000 +++ b/transform/TransformFactory.h Fri Mar 17 17:38:28 2006 +0000 @@ -24,8 +24,10 @@ static TransformFactory *instance(); // The name is intended to be computer-referencable, and unique - // within the application. The description should be - // human-readable, and does not have to be unique. + // within the application. The description is intended to be + // human readable. In principle it doesn't have to be unique, but + // the factory will add suffixes to ensure that it is, all the + // same (just to avoid user confusion). struct TransformDesc { TransformDesc(TransformName _name, QString _description = "") :