annotate document/Document.h @ 88:51be0daa1386

Several changes related to referring to remote URLs for sessions and files: * Pull file dialog wrapper functions out from MainWindow into FileFinder * If a file referred to in a session is not found at its expected location, try a few other alternatives (same location as the session file or same location as the last audio file) before asking the user to locate it * Allow user to give a URL when locating an audio file, not just locate on the filesystem * Make wave file models remember the "original" location (e.g. URL) of the audio file, not just the actual location from which the data was loaded (e.g. local copy of that URL) -- when saving a session, use the original location so as not to refer to a temporary file * Clean up incompletely-downloaded local copies of files
author Chris Cannam
date Thu, 11 Jan 2007 13:29:58 +0000
parents bedc7517b6e8
children dd11619b73ba
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@77 7 This file copyright 2006 Chris Cannam and QMUL.
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@66 132 std::vector<Model *> getTransformInputModels();
Chris@66 133
Chris@0 134 /**
Chris@55 135 * Add a derived model associated with the given transform,
Chris@55 136 * running the transform and returning the resulting model.
Chris@55 137 */
Chris@55 138 Model *addDerivedModel(TransformName transform,
Chris@55 139 Model *inputModel,
Chris@55 140 const PluginTransform::ExecutionContext &context,
Chris@55 141 QString configurationXml);
Chris@55 142
Chris@55 143 /**
Chris@55 144 * Add a derived model associated with the given transform. This
Chris@55 145 * is necessary to register any derived model that was not created
Chris@55 146 * by the document using createDerivedModel or createDerivedLayer.
Chris@0 147 */
Chris@0 148 void addDerivedModel(TransformName,
Chris@0 149 Model *inputModel,
Chris@27 150 const PluginTransform::ExecutionContext &context,
Chris@0 151 Model *outputModelToAdd,
Chris@0 152 QString configurationXml);
Chris@0 153
Chris@0 154 /**
Chris@0 155 * Add an imported (non-derived, non-main) model. This is
Chris@0 156 * necessary to register any imported model that is associated
Chris@0 157 * with a layer.
Chris@0 158 */
Chris@0 159 void addImportedModel(Model *);
Chris@0 160
Chris@0 161 /**
Chris@0 162 * Associate the given model with the given layer. The model must
Chris@0 163 * have already been registered using one of the addXXModel
Chris@0 164 * methods above.
Chris@0 165 */
Chris@0 166 void setModel(Layer *, Model *);
Chris@0 167
Chris@0 168 /**
Chris@0 169 * Set the given layer to use the given channel of its model (-1
Chris@0 170 * means all available channels).
Chris@0 171 */
Chris@0 172 void setChannel(Layer *, int);
Chris@0 173
Chris@0 174 /**
Chris@0 175 * Add the given layer to the given view. If the layer is
Chris@0 176 * intended to show a particular model, the model should normally
Chris@0 177 * be set using setModel before this method is called.
Chris@0 178 */
Chris@0 179 void addLayerToView(View *, Layer *);
Chris@0 180
Chris@0 181 /**
Chris@0 182 * Remove the given layer from the given view.
Chris@0 183 */
Chris@0 184 void removeLayerFromView(View *, Layer *);
Chris@0 185
Chris@0 186 void toXml(QTextStream &, QString indent, QString extraAttributes) const;
Chris@0 187 QString toXmlString(QString indent, QString extraAttributes) const;
Chris@0 188
Chris@0 189 signals:
Chris@0 190 void layerAdded(Layer *);
Chris@0 191 void layerRemoved(Layer *);
Chris@0 192 void layerAboutToBeDeleted(Layer *);
Chris@0 193
Chris@0 194 // Emitted when a layer is first added to a view, or when it is
Chris@0 195 // last removed from a view
Chris@0 196 void layerInAView(Layer *, bool);
Chris@0 197
Chris@0 198 void modelAdded(Model *);
Chris@0 199 void mainModelChanged(WaveFileModel *); // emitted after modelAdded
Chris@0 200 void modelAboutToBeDeleted(Model *);
Chris@0 201
Chris@0 202 void modelGenerationFailed(QString transformName);
Chris@0 203 void modelRegenerationFailed(QString layerName, QString transformName);
Chris@0 204
Chris@0 205 protected:
Chris@0 206 void releaseModel(Model *model);
Chris@0 207
Chris@0 208 /**
Chris@0 209 * Delete the given layer, and also its associated model if no
Chris@0 210 * longer used by any other layer. In general, this should be the
Chris@0 211 * only method used to delete layers -- doing so directly is a bit
Chris@0 212 * of a social gaffe.
Chris@0 213 */
Chris@0 214 void deleteLayer(Layer *, bool force = false);
Chris@0 215
Chris@0 216 /*
Chris@0 217 * Every model that is in use by a layer in the document must be
Chris@0 218 * found in either m_mainModel, m_derivedModels or
Chris@0 219 * m_importedModels. We own and control the lifespan of all of
Chris@0 220 * these models.
Chris@0 221 */
Chris@0 222
Chris@0 223 /**
Chris@0 224 * The model that provides the underlying sample rate, etc. This
Chris@0 225 * model is not reference counted for layers, and is not freed
Chris@0 226 * unless it is replaced or the document is deleted.
Chris@0 227 */
Chris@0 228 WaveFileModel *m_mainModel;
Chris@0 229
Chris@0 230 struct ModelRecord
Chris@0 231 {
Chris@0 232 // Information associated with a non-main model. If this
Chris@0 233 // model is derived from another, then source will be non-NULL
Chris@0 234 // and the transform name will be set appropriately. If the
Chris@0 235 // transform name is set but source is NULL, then there was a
Chris@0 236 // transform involved but the (target) model has been modified
Chris@0 237 // since being generated from it.
Chris@0 238 const Model *source;
Chris@0 239 TransformName transform;
Chris@27 240 PluginTransform::ExecutionContext context;
Chris@0 241 QString configurationXml;
Chris@0 242
Chris@0 243 // Count of the number of layers using this model.
Chris@0 244 int refcount;
Chris@0 245 };
Chris@0 246
Chris@0 247 typedef std::map<Model *, ModelRecord> ModelMap;
Chris@0 248 ModelMap m_models;
Chris@0 249
Chris@0 250 class AddLayerCommand : public Command
Chris@0 251 {
Chris@0 252 public:
Chris@0 253 AddLayerCommand(Document *d, View *view, Layer *layer);
Chris@0 254 virtual ~AddLayerCommand();
Chris@0 255
Chris@0 256 virtual void execute();
Chris@0 257 virtual void unexecute();
Chris@0 258 virtual QString getName() const { return m_name; }
Chris@0 259
Chris@0 260 protected:
Chris@0 261 Document *m_d;
Chris@0 262 View *m_view; // I don't own this
Chris@0 263 Layer *m_layer; // Document owns this, but I determine its lifespans
Chris@0 264 QString m_name;
Chris@0 265 bool m_added;
Chris@0 266 };
Chris@0 267
Chris@0 268 class RemoveLayerCommand : public Command
Chris@0 269 {
Chris@0 270 public:
Chris@0 271 RemoveLayerCommand(Document *d, View *view, Layer *layer);
Chris@0 272 virtual ~RemoveLayerCommand();
Chris@0 273
Chris@0 274 virtual void execute();
Chris@0 275 virtual void unexecute();
Chris@0 276 virtual QString getName() const { return m_name; }
Chris@0 277
Chris@0 278 protected:
Chris@0 279 Document *m_d;
Chris@0 280 View *m_view; // I don't own this
Chris@0 281 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@0 282 QString m_name;
Chris@0 283 bool m_added;
Chris@0 284 };
Chris@0 285
Chris@0 286 typedef std::map<Layer *, std::set<View *> > LayerViewMap;
Chris@0 287 LayerViewMap m_layerViewMap;
Chris@0 288
Chris@0 289 void addToLayerViewMap(Layer *, View *);
Chris@0 290 void removeFromLayerViewMap(Layer *, View *);
Chris@0 291
Chris@0 292 QString getUniqueLayerName(QString candidate);
Chris@0 293
Chris@0 294 /**
Chris@0 295 * And these are the layers. We also control the lifespans of
Chris@0 296 * these (usually through the commands used to add and remove them).
Chris@0 297 */
Chris@0 298 typedef std::set<Layer *> LayerSet;
Chris@0 299 LayerSet m_layers;
Chris@0 300 };
Chris@0 301
Chris@0 302 #endif