annotate document/Document.h @ 45:6b6bca31ad53

* When setting a new model on a layer, don't delete the old one until after the new one has been set (a layer's setModel may want to compare against the old one, as WaveformLayer does)
author Chris Cannam
date Thu, 05 Oct 2006 11:00:59 +0000
parents 61259228d029
children ca1e3f5657d5
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #ifndef _DOCUMENT_H_
Chris@0 17 #define _DOCUMENT_H_
Chris@0 18
Chris@0 19 #include "layer/LayerFactory.h"
Chris@0 20 #include "transform/Transform.h"
Chris@27 21 #include "transform/PluginTransform.h"
Chris@0 22 #include "base/Command.h"
Chris@0 23
Chris@0 24 #include <map>
Chris@0 25 #include <set>
Chris@0 26
Chris@0 27 class Model;
Chris@0 28 class Layer;
Chris@0 29 class View;
Chris@0 30 class WaveFileModel;
Chris@0 31
Chris@0 32 /**
Chris@0 33 * A Sonic Visualiser document consists of a set of data models, and
Chris@0 34 * also the visualisation layers used to display them. Changes to the
Chris@0 35 * layers and their layout need to be stored and managed in much the
Chris@0 36 * same way as changes to the underlying data.
Chris@0 37 *
Chris@0 38 * The document manages:
Chris@0 39 *
Chris@0 40 * -- A main data model, which provides the underlying sample rate and
Chris@0 41 * such like. This must be a wave file model.
Chris@0 42 *
Chris@0 43 * -- Any number of imported models, which contain data without any
Chris@0 44 * requirement to remember where the data came from or how to
Chris@0 45 * regenerate it.
Chris@0 46 *
Chris@0 47 * -- Any number of models generated by transforms such as feature
Chris@0 48 * extraction plugins. For these, we also record the source model and
Chris@0 49 * the name of the transform used to generate the model so that we can
Chris@0 50 * regenerate it (potentially from a different source) on demand.
Chris@0 51 *
Chris@0 52 * -- A flat list of layers. Elsewhere, the GUI may distribute these
Chris@0 53 * across any number of view widgets. A layer may be viewable on more
Chris@0 54 * than one view at once, in principle. A layer refers to one model,
Chris@0 55 * but the same model can be in use in more than one layer.
Chris@0 56 *
Chris@0 57 * The document does *not* manage the existence or structure of Pane
Chris@0 58 * and other view widgets. However, it does provide convenience
Chris@0 59 * methods for reference-counted command-based management of the
Chris@0 60 * association between layers and views (addLayerToView,
Chris@0 61 * removeLayerFromView).
Chris@0 62 */
Chris@0 63
Chris@0 64 class Document : public QObject,
Chris@0 65 public XmlExportable
Chris@0 66 {
Chris@0 67 Q_OBJECT
Chris@0 68
Chris@0 69 public:
Chris@0 70 Document();
Chris@0 71 virtual ~Document();
Chris@0 72
Chris@0 73 /**
Chris@0 74 * Create and return a new layer of the given type, associated
Chris@0 75 * with no model. The caller may set any model on this layer, but
Chris@0 76 * the model must also be registered with the document via the
Chris@0 77 * add-model methods below.
Chris@0 78 */
Chris@0 79 Layer *createLayer(LayerFactory::LayerType);
Chris@0 80
Chris@0 81 /**
Chris@0 82 * Create and return a new layer of the given type, associated
Chris@0 83 * with the current main model (if appropriate to the layer type).
Chris@0 84 */
Chris@0 85 Layer *createMainModelLayer(LayerFactory::LayerType);
Chris@0 86
Chris@0 87 /**
Chris@0 88 * Create and return a new layer associated with the given model,
Chris@0 89 * and register the model as an imported model.
Chris@0 90 */
Chris@0 91 Layer *createImportedLayer(Model *);
Chris@0 92
Chris@0 93 /**
Chris@0 94 * Create and return a new layer of the given type, with an
Chris@0 95 * appropriate empty model. If the given type is not one for
Chris@0 96 * which an empty model can meaningfully be created, return 0.
Chris@0 97 */
Chris@0 98 Layer *createEmptyLayer(LayerFactory::LayerType);
Chris@0 99
Chris@0 100 /**
Chris@0 101 * Create and return a new layer of the given type, associated
Chris@0 102 * with the given transform name. This method does not run the
Chris@0 103 * transform itself, nor create a model. The caller can safely
Chris@0 104 * add a model to the layer later, but note that all models used
Chris@0 105 * by a transform layer _must_ be registered with the document
Chris@0 106 * using addDerivedModel below.
Chris@0 107 */
Chris@0 108 Layer *createDerivedLayer(LayerFactory::LayerType, TransformName);
Chris@0 109
Chris@0 110 /**
Chris@0 111 * Create and return a suitable layer for the given transform,
Chris@0 112 * running the transform and associating the resulting model with
Chris@0 113 * the new layer.
Chris@0 114 */
Chris@0 115 Layer *createDerivedLayer(TransformName,
Chris@0 116 Model *inputModel,
Chris@27 117 const PluginTransform::ExecutionContext &context,
Chris@0 118 QString configurationXml);
Chris@0 119
Chris@0 120 /**
Chris@0 121 * Set the main model (the source for playback sample rate, etc)
Chris@0 122 * to the given wave file model. This will regenerate any derived
Chris@0 123 * models that were based on the previous main model.
Chris@0 124 */
Chris@0 125 void setMainModel(WaveFileModel *);
Chris@0 126
Chris@0 127 /**
Chris@0 128 * Get the main model (the source for playback sample rate, etc).
Chris@0 129 */
Chris@0 130 WaveFileModel *getMainModel() { return m_mainModel; }
Chris@0 131
Chris@0 132 /**
Chris@0 133 * Add a derived model associated with the given transform name.
Chris@0 134 * This is necessary to register any derived model that was not
Chris@0 135 * created by the document using
Chris@0 136 * e.g. createDerivedLayer(TransformName) above.
Chris@0 137 */
Chris@0 138 void addDerivedModel(TransformName,
Chris@0 139 Model *inputModel,
Chris@27 140 const PluginTransform::ExecutionContext &context,
Chris@0 141 Model *outputModelToAdd,
Chris@0 142 QString configurationXml);
Chris@0 143
Chris@0 144 /**
Chris@0 145 * Add an imported (non-derived, non-main) model. This is
Chris@0 146 * necessary to register any imported model that is associated
Chris@0 147 * with a layer.
Chris@0 148 */
Chris@0 149 void addImportedModel(Model *);
Chris@0 150
Chris@0 151 /**
Chris@0 152 * Associate the given model with the given layer. The model must
Chris@0 153 * have already been registered using one of the addXXModel
Chris@0 154 * methods above.
Chris@0 155 */
Chris@0 156 void setModel(Layer *, Model *);
Chris@0 157
Chris@0 158 /**
Chris@0 159 * Set the given layer to use the given channel of its model (-1
Chris@0 160 * means all available channels).
Chris@0 161 */
Chris@0 162 void setChannel(Layer *, int);
Chris@0 163
Chris@0 164 /**
Chris@0 165 * Add the given layer to the given view. If the layer is
Chris@0 166 * intended to show a particular model, the model should normally
Chris@0 167 * be set using setModel before this method is called.
Chris@0 168 */
Chris@0 169 void addLayerToView(View *, Layer *);
Chris@0 170
Chris@0 171 /**
Chris@0 172 * Remove the given layer from the given view.
Chris@0 173 */
Chris@0 174 void removeLayerFromView(View *, Layer *);
Chris@0 175
Chris@0 176 void toXml(QTextStream &, QString indent, QString extraAttributes) const;
Chris@0 177 QString toXmlString(QString indent, QString extraAttributes) const;
Chris@0 178
Chris@0 179 signals:
Chris@0 180 void layerAdded(Layer *);
Chris@0 181 void layerRemoved(Layer *);
Chris@0 182 void layerAboutToBeDeleted(Layer *);
Chris@0 183
Chris@0 184 // Emitted when a layer is first added to a view, or when it is
Chris@0 185 // last removed from a view
Chris@0 186 void layerInAView(Layer *, bool);
Chris@0 187
Chris@0 188 void modelAdded(Model *);
Chris@0 189 void mainModelChanged(WaveFileModel *); // emitted after modelAdded
Chris@0 190 void modelAboutToBeDeleted(Model *);
Chris@0 191
Chris@0 192 void modelGenerationFailed(QString transformName);
Chris@0 193 void modelRegenerationFailed(QString layerName, QString transformName);
Chris@0 194
Chris@0 195 protected:
Chris@0 196 Model *createModelForTransform(TransformName transform,
Chris@0 197 Model *inputModel,
Chris@27 198 const PluginTransform::ExecutionContext &context,
Chris@0 199 QString configurationXml);
Chris@0 200 void releaseModel(Model *model);
Chris@0 201
Chris@0 202 /**
Chris@0 203 * Delete the given layer, and also its associated model if no
Chris@0 204 * longer used by any other layer. In general, this should be the
Chris@0 205 * only method used to delete layers -- doing so directly is a bit
Chris@0 206 * of a social gaffe.
Chris@0 207 */
Chris@0 208 void deleteLayer(Layer *, bool force = false);
Chris@0 209
Chris@0 210 /*
Chris@0 211 * Every model that is in use by a layer in the document must be
Chris@0 212 * found in either m_mainModel, m_derivedModels or
Chris@0 213 * m_importedModels. We own and control the lifespan of all of
Chris@0 214 * these models.
Chris@0 215 */
Chris@0 216
Chris@0 217 /**
Chris@0 218 * The model that provides the underlying sample rate, etc. This
Chris@0 219 * model is not reference counted for layers, and is not freed
Chris@0 220 * unless it is replaced or the document is deleted.
Chris@0 221 */
Chris@0 222 WaveFileModel *m_mainModel;
Chris@0 223
Chris@0 224 struct ModelRecord
Chris@0 225 {
Chris@0 226 // Information associated with a non-main model. If this
Chris@0 227 // model is derived from another, then source will be non-NULL
Chris@0 228 // and the transform name will be set appropriately. If the
Chris@0 229 // transform name is set but source is NULL, then there was a
Chris@0 230 // transform involved but the (target) model has been modified
Chris@0 231 // since being generated from it.
Chris@0 232 const Model *source;
Chris@0 233 TransformName transform;
Chris@27 234 PluginTransform::ExecutionContext context;
Chris@0 235 QString configurationXml;
Chris@0 236
Chris@0 237 // Count of the number of layers using this model.
Chris@0 238 int refcount;
Chris@0 239 };
Chris@0 240
Chris@0 241 typedef std::map<Model *, ModelRecord> ModelMap;
Chris@0 242 ModelMap m_models;
Chris@0 243
Chris@0 244 class AddLayerCommand : public Command
Chris@0 245 {
Chris@0 246 public:
Chris@0 247 AddLayerCommand(Document *d, View *view, Layer *layer);
Chris@0 248 virtual ~AddLayerCommand();
Chris@0 249
Chris@0 250 virtual void execute();
Chris@0 251 virtual void unexecute();
Chris@0 252 virtual QString getName() const { return m_name; }
Chris@0 253
Chris@0 254 protected:
Chris@0 255 Document *m_d;
Chris@0 256 View *m_view; // I don't own this
Chris@0 257 Layer *m_layer; // Document owns this, but I determine its lifespans
Chris@0 258 QString m_name;
Chris@0 259 bool m_added;
Chris@0 260 };
Chris@0 261
Chris@0 262 class RemoveLayerCommand : public Command
Chris@0 263 {
Chris@0 264 public:
Chris@0 265 RemoveLayerCommand(Document *d, View *view, Layer *layer);
Chris@0 266 virtual ~RemoveLayerCommand();
Chris@0 267
Chris@0 268 virtual void execute();
Chris@0 269 virtual void unexecute();
Chris@0 270 virtual QString getName() const { return m_name; }
Chris@0 271
Chris@0 272 protected:
Chris@0 273 Document *m_d;
Chris@0 274 View *m_view; // I don't own this
Chris@0 275 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@0 276 QString m_name;
Chris@0 277 bool m_added;
Chris@0 278 };
Chris@0 279
Chris@0 280 typedef std::map<Layer *, std::set<View *> > LayerViewMap;
Chris@0 281 LayerViewMap m_layerViewMap;
Chris@0 282
Chris@0 283 void addToLayerViewMap(Layer *, View *);
Chris@0 284 void removeFromLayerViewMap(Layer *, View *);
Chris@0 285
Chris@0 286 QString getUniqueLayerName(QString candidate);
Chris@0 287
Chris@0 288 /**
Chris@0 289 * And these are the layers. We also control the lifespans of
Chris@0 290 * these (usually through the commands used to add and remove them).
Chris@0 291 */
Chris@0 292 typedef std::set<Layer *> LayerSet;
Chris@0 293 LayerSet m_layers;
Chris@0 294 };
Chris@0 295
Chris@0 296 #endif