Chris@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: Sonic Visualiser Chris@0: An audio file viewer and annotation editor. Chris@0: Centre for Digital Music, Queen Mary, University of London. Chris@0: This file copyright 2006 Chris Cannam. Chris@0: Chris@0: This program is free software; you can redistribute it and/or Chris@0: modify it under the terms of the GNU General Public License as Chris@0: published by the Free Software Foundation; either version 2 of the Chris@0: License, or (at your option) any later version. See the file Chris@0: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #ifndef _DOCUMENT_H_ Chris@0: #define _DOCUMENT_H_ Chris@0: Chris@0: #include "layer/LayerFactory.h" Chris@0: #include "transform/Transform.h" Chris@27: #include "transform/PluginTransform.h" Chris@0: #include "base/Command.h" Chris@0: Chris@0: #include Chris@0: #include Chris@0: Chris@0: class Model; Chris@0: class Layer; Chris@0: class View; Chris@0: class WaveFileModel; Chris@0: Chris@0: /** Chris@0: * A Sonic Visualiser document consists of a set of data models, and Chris@0: * also the visualisation layers used to display them. Changes to the Chris@0: * layers and their layout need to be stored and managed in much the Chris@0: * same way as changes to the underlying data. Chris@0: * Chris@0: * The document manages: Chris@0: * Chris@0: * -- A main data model, which provides the underlying sample rate and Chris@0: * such like. This must be a wave file model. Chris@0: * Chris@0: * -- Any number of imported models, which contain data without any Chris@0: * requirement to remember where the data came from or how to Chris@0: * regenerate it. Chris@0: * Chris@0: * -- Any number of models generated by transforms such as feature Chris@0: * extraction plugins. For these, we also record the source model and Chris@0: * the name of the transform used to generate the model so that we can Chris@0: * regenerate it (potentially from a different source) on demand. Chris@0: * Chris@0: * -- A flat list of layers. Elsewhere, the GUI may distribute these Chris@0: * across any number of view widgets. A layer may be viewable on more Chris@0: * than one view at once, in principle. A layer refers to one model, Chris@0: * but the same model can be in use in more than one layer. Chris@0: * Chris@0: * The document does *not* manage the existence or structure of Pane Chris@0: * and other view widgets. However, it does provide convenience Chris@0: * methods for reference-counted command-based management of the Chris@0: * association between layers and views (addLayerToView, Chris@0: * removeLayerFromView). Chris@0: */ Chris@0: Chris@0: class Document : public QObject, Chris@0: public XmlExportable Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@0: public: Chris@0: Document(); Chris@0: virtual ~Document(); Chris@0: Chris@0: /** Chris@0: * Create and return a new layer of the given type, associated Chris@0: * with no model. The caller may set any model on this layer, but Chris@0: * the model must also be registered with the document via the Chris@0: * add-model methods below. Chris@0: */ Chris@0: Layer *createLayer(LayerFactory::LayerType); Chris@0: Chris@0: /** Chris@0: * Create and return a new layer of the given type, associated Chris@0: * with the current main model (if appropriate to the layer type). Chris@0: */ Chris@0: Layer *createMainModelLayer(LayerFactory::LayerType); Chris@0: Chris@0: /** Chris@0: * Create and return a new layer associated with the given model, Chris@0: * and register the model as an imported model. Chris@0: */ Chris@0: Layer *createImportedLayer(Model *); Chris@0: Chris@0: /** Chris@0: * Create and return a new layer of the given type, with an Chris@0: * appropriate empty model. If the given type is not one for Chris@0: * which an empty model can meaningfully be created, return 0. Chris@0: */ Chris@0: Layer *createEmptyLayer(LayerFactory::LayerType); Chris@0: Chris@0: /** Chris@0: * Create and return a new layer of the given type, associated Chris@0: * with the given transform name. This method does not run the Chris@0: * transform itself, nor create a model. The caller can safely Chris@0: * add a model to the layer later, but note that all models used Chris@0: * by a transform layer _must_ be registered with the document Chris@0: * using addDerivedModel below. Chris@0: */ Chris@0: Layer *createDerivedLayer(LayerFactory::LayerType, TransformName); Chris@0: Chris@0: /** Chris@0: * Create and return a suitable layer for the given transform, Chris@0: * running the transform and associating the resulting model with Chris@0: * the new layer. Chris@0: */ Chris@0: Layer *createDerivedLayer(TransformName, Chris@0: Model *inputModel, Chris@27: const PluginTransform::ExecutionContext &context, Chris@0: QString configurationXml); Chris@0: Chris@0: /** Chris@0: * Set the main model (the source for playback sample rate, etc) Chris@0: * to the given wave file model. This will regenerate any derived Chris@0: * models that were based on the previous main model. Chris@0: */ Chris@0: void setMainModel(WaveFileModel *); Chris@0: Chris@0: /** Chris@0: * Get the main model (the source for playback sample rate, etc). Chris@0: */ Chris@0: WaveFileModel *getMainModel() { return m_mainModel; } Chris@0: Chris@0: /** Chris@0: * Add a derived model associated with the given transform name. Chris@0: * This is necessary to register any derived model that was not Chris@0: * created by the document using Chris@0: * e.g. createDerivedLayer(TransformName) above. Chris@0: */ Chris@0: void addDerivedModel(TransformName, Chris@0: Model *inputModel, Chris@27: const PluginTransform::ExecutionContext &context, Chris@0: Model *outputModelToAdd, Chris@0: QString configurationXml); Chris@0: Chris@0: /** Chris@0: * Add an imported (non-derived, non-main) model. This is Chris@0: * necessary to register any imported model that is associated Chris@0: * with a layer. Chris@0: */ Chris@0: void addImportedModel(Model *); Chris@0: Chris@0: /** Chris@0: * Associate the given model with the given layer. The model must Chris@0: * have already been registered using one of the addXXModel Chris@0: * methods above. Chris@0: */ Chris@0: void setModel(Layer *, Model *); Chris@0: Chris@0: /** Chris@0: * Set the given layer to use the given channel of its model (-1 Chris@0: * means all available channels). Chris@0: */ Chris@0: void setChannel(Layer *, int); Chris@0: Chris@0: /** Chris@0: * Add the given layer to the given view. If the layer is Chris@0: * intended to show a particular model, the model should normally Chris@0: * be set using setModel before this method is called. Chris@0: */ Chris@0: void addLayerToView(View *, Layer *); Chris@0: Chris@0: /** Chris@0: * Remove the given layer from the given view. Chris@0: */ Chris@0: void removeLayerFromView(View *, Layer *); Chris@0: Chris@0: void toXml(QTextStream &, QString indent, QString extraAttributes) const; Chris@0: QString toXmlString(QString indent, QString extraAttributes) const; Chris@0: Chris@0: signals: Chris@0: void layerAdded(Layer *); Chris@0: void layerRemoved(Layer *); Chris@0: void layerAboutToBeDeleted(Layer *); Chris@0: Chris@0: // Emitted when a layer is first added to a view, or when it is Chris@0: // last removed from a view Chris@0: void layerInAView(Layer *, bool); Chris@0: Chris@0: void modelAdded(Model *); Chris@0: void mainModelChanged(WaveFileModel *); // emitted after modelAdded Chris@0: void modelAboutToBeDeleted(Model *); Chris@0: Chris@0: void modelGenerationFailed(QString transformName); Chris@0: void modelRegenerationFailed(QString layerName, QString transformName); Chris@0: Chris@0: protected: Chris@0: Model *createModelForTransform(TransformName transform, Chris@0: Model *inputModel, Chris@27: const PluginTransform::ExecutionContext &context, Chris@0: QString configurationXml); Chris@0: void releaseModel(Model *model); Chris@0: Chris@0: /** Chris@0: * Delete the given layer, and also its associated model if no Chris@0: * longer used by any other layer. In general, this should be the Chris@0: * only method used to delete layers -- doing so directly is a bit Chris@0: * of a social gaffe. Chris@0: */ Chris@0: void deleteLayer(Layer *, bool force = false); Chris@0: Chris@0: /* Chris@0: * Every model that is in use by a layer in the document must be Chris@0: * found in either m_mainModel, m_derivedModels or Chris@0: * m_importedModels. We own and control the lifespan of all of Chris@0: * these models. Chris@0: */ Chris@0: Chris@0: /** Chris@0: * The model that provides the underlying sample rate, etc. This Chris@0: * model is not reference counted for layers, and is not freed Chris@0: * unless it is replaced or the document is deleted. Chris@0: */ Chris@0: WaveFileModel *m_mainModel; Chris@0: Chris@0: struct ModelRecord Chris@0: { Chris@0: // Information associated with a non-main model. If this Chris@0: // model is derived from another, then source will be non-NULL Chris@0: // and the transform name will be set appropriately. If the Chris@0: // transform name is set but source is NULL, then there was a Chris@0: // transform involved but the (target) model has been modified Chris@0: // since being generated from it. Chris@0: const Model *source; Chris@0: TransformName transform; Chris@27: PluginTransform::ExecutionContext context; Chris@0: QString configurationXml; Chris@0: Chris@0: // Count of the number of layers using this model. Chris@0: int refcount; Chris@0: }; Chris@0: Chris@0: typedef std::map ModelMap; Chris@0: ModelMap m_models; Chris@0: Chris@0: class AddLayerCommand : public Command Chris@0: { Chris@0: public: Chris@0: AddLayerCommand(Document *d, View *view, Layer *layer); Chris@0: virtual ~AddLayerCommand(); Chris@0: Chris@0: virtual void execute(); Chris@0: virtual void unexecute(); Chris@0: virtual QString getName() const { return m_name; } Chris@0: Chris@0: protected: Chris@0: Document *m_d; Chris@0: View *m_view; // I don't own this Chris@0: Layer *m_layer; // Document owns this, but I determine its lifespans Chris@0: QString m_name; Chris@0: bool m_added; Chris@0: }; Chris@0: Chris@0: class RemoveLayerCommand : public Command Chris@0: { Chris@0: public: Chris@0: RemoveLayerCommand(Document *d, View *view, Layer *layer); Chris@0: virtual ~RemoveLayerCommand(); Chris@0: Chris@0: virtual void execute(); Chris@0: virtual void unexecute(); Chris@0: virtual QString getName() const { return m_name; } Chris@0: Chris@0: protected: Chris@0: Document *m_d; Chris@0: View *m_view; // I don't own this Chris@0: Layer *m_layer; // Document owns this, but I determine its lifespan Chris@0: QString m_name; Chris@0: bool m_added; Chris@0: }; Chris@0: Chris@0: typedef std::map > LayerViewMap; Chris@0: LayerViewMap m_layerViewMap; Chris@0: Chris@0: void addToLayerViewMap(Layer *, View *); Chris@0: void removeFromLayerViewMap(Layer *, View *); Chris@0: Chris@0: QString getUniqueLayerName(QString candidate); Chris@0: Chris@0: /** Chris@0: * And these are the layers. We also control the lifespans of Chris@0: * these (usually through the commands used to add and remove them). Chris@0: */ Chris@0: typedef std::set LayerSet; Chris@0: LayerSet m_layers; Chris@0: }; Chris@0: Chris@0: #endif