| Chris@45 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@45 | 2 | 
| Chris@45 | 3 /* | 
| Chris@45 | 4     Sonic Visualiser | 
| Chris@45 | 5     An audio file viewer and annotation editor. | 
| Chris@45 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@45 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@45 | 8 | 
| Chris@45 | 9     This program is free software; you can redistribute it and/or | 
| Chris@45 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@45 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@45 | 12     License, or (at your option) any later version.  See the file | 
| Chris@45 | 13     COPYING included with this distribution for more information. | 
| Chris@45 | 14 */ | 
| Chris@45 | 15 | 
| Chris@45 | 16 #include "Document.h" | 
| Chris@45 | 17 | 
| Chris@45 | 18 #include "data/model/WaveFileModel.h" | 
| Chris@45 | 19 #include "data/model/WritableWaveFileModel.h" | 
| Chris@45 | 20 #include "data/model/DenseThreeDimensionalModel.h" | 
| Chris@45 | 21 #include "data/model/DenseTimeValueModel.h" | 
| Chris@45 | 22 #include "layer/Layer.h" | 
| Chris@45 | 23 #include "base/CommandHistory.h" | 
| Chris@45 | 24 #include "base/Command.h" | 
| Chris@45 | 25 #include "view/View.h" | 
| Chris@45 | 26 #include "base/PlayParameterRepository.h" | 
| Chris@45 | 27 #include "base/PlayParameters.h" | 
| Chris@45 | 28 #include "plugin/transform/TransformFactory.h" | 
| Chris@45 | 29 #include <QApplication> | 
| Chris@45 | 30 #include <QTextStream> | 
| Chris@45 | 31 #include <iostream> | 
| Chris@45 | 32 | 
| Chris@45 | 33 // For alignment: | 
| Chris@45 | 34 #include "data/model/AggregateWaveModel.h" | 
| Chris@45 | 35 #include "data/model/SparseTimeValueModel.h" | 
| Chris@45 | 36 #include "data/model/AlignmentModel.h" | 
| Chris@45 | 37 | 
| Chris@45 | 38 //!!! still need to handle command history, documentRestored/documentModified | 
| Chris@45 | 39 | 
| Chris@45 | 40 Document::Document() : | 
| Chris@47 | 41     m_mainModel(0), | 
| Chris@47 | 42     m_autoAlignment(false) | 
| Chris@45 | 43 { | 
| Chris@45 | 44     connect(this, SIGNAL(modelAboutToBeDeleted(Model *)), | 
| Chris@45 | 45             TransformFactory::getInstance(), | 
| Chris@45 | 46             SLOT(modelAboutToBeDeleted(Model *))); | 
| Chris@45 | 47 } | 
| Chris@45 | 48 | 
| Chris@45 | 49 Document::~Document() | 
| Chris@45 | 50 { | 
| Chris@45 | 51     //!!! Document should really own the command history.  atm we | 
| Chris@45 | 52     //still refer to it in various places that don't have access to | 
| Chris@45 | 53     //the document, be nice to fix that | 
| Chris@45 | 54 | 
| Chris@45 | 55 //    std::cerr << "\n\nDocument::~Document: about to clear command history" << std::endl; | 
| Chris@45 | 56     CommandHistory::getInstance()->clear(); | 
| Chris@45 | 57 | 
| Chris@45 | 58 //    std::cerr << "Document::~Document: about to delete layers" << std::endl; | 
| Chris@45 | 59     while (!m_layers.empty()) { | 
| Chris@45 | 60 	deleteLayer(*m_layers.begin(), true); | 
| Chris@45 | 61     } | 
| Chris@45 | 62 | 
| Chris@45 | 63     if (!m_models.empty()) { | 
| Chris@45 | 64 	std::cerr << "Document::~Document: WARNING: " | 
| Chris@45 | 65 		  << m_models.size() << " model(s) still remain -- " | 
| Chris@45 | 66 		  << "should have been garbage collected when deleting layers" | 
| Chris@45 | 67 		  << std::endl; | 
| Chris@45 | 68 	while (!m_models.empty()) { | 
| Chris@45 | 69             Model *model = m_models.begin()->first; | 
| Chris@45 | 70 	    if (model == m_mainModel) { | 
| Chris@45 | 71 		// just in case! | 
| Chris@45 | 72 		std::cerr << "Document::~Document: WARNING: Main model is also" | 
| Chris@45 | 73 			  << " in models list!" << std::endl; | 
| Chris@45 | 74 	    } else if (model) { | 
| Chris@45 | 75 		emit modelAboutToBeDeleted(model); | 
| Chris@45 | 76                 model->aboutToDelete(); | 
| Chris@45 | 77 		delete model; | 
| Chris@45 | 78 	    } | 
| Chris@45 | 79 	    m_models.erase(m_models.begin()); | 
| Chris@45 | 80 	} | 
| Chris@45 | 81     } | 
| Chris@45 | 82 | 
| Chris@45 | 83 //    std::cerr << "Document::~Document: About to get rid of main model" | 
| Chris@45 | 84 //	      << std::endl; | 
| Chris@45 | 85     if (m_mainModel) { | 
| Chris@45 | 86         emit modelAboutToBeDeleted(m_mainModel); | 
| Chris@45 | 87         m_mainModel->aboutToDelete(); | 
| Chris@45 | 88     } | 
| Chris@45 | 89 | 
| Chris@45 | 90     emit mainModelChanged(0); | 
| Chris@45 | 91     delete m_mainModel; | 
| Chris@45 | 92 | 
| Chris@45 | 93 } | 
| Chris@45 | 94 | 
| Chris@45 | 95 Layer * | 
| Chris@45 | 96 Document::createLayer(LayerFactory::LayerType type) | 
| Chris@45 | 97 { | 
| Chris@45 | 98     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 99     if (!newLayer) return 0; | 
| Chris@45 | 100 | 
| Chris@45 | 101     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 102 | 
| Chris@45 | 103     m_layers.insert(newLayer); | 
| Chris@45 | 104     emit layerAdded(newLayer); | 
| Chris@45 | 105 | 
| Chris@45 | 106     return newLayer; | 
| Chris@45 | 107 } | 
| Chris@45 | 108 | 
| Chris@45 | 109 Layer * | 
| Chris@45 | 110 Document::createMainModelLayer(LayerFactory::LayerType type) | 
| Chris@45 | 111 { | 
| Chris@45 | 112     Layer *newLayer = createLayer(type); | 
| Chris@45 | 113     if (!newLayer) return 0; | 
| Chris@45 | 114     setModel(newLayer, m_mainModel); | 
| Chris@45 | 115     return newLayer; | 
| Chris@45 | 116 } | 
| Chris@45 | 117 | 
| Chris@45 | 118 Layer * | 
| Chris@45 | 119 Document::createImportedLayer(Model *model) | 
| Chris@45 | 120 { | 
| Chris@45 | 121     LayerFactory::LayerTypeSet types = | 
| Chris@45 | 122 	LayerFactory::getInstance()->getValidLayerTypes(model); | 
| Chris@45 | 123 | 
| Chris@45 | 124     if (types.empty()) { | 
| Chris@45 | 125 	std::cerr << "WARNING: Document::importLayer: no valid display layer for model" << std::endl; | 
| Chris@45 | 126 	return 0; | 
| Chris@45 | 127     } | 
| Chris@45 | 128 | 
| Chris@45 | 129     //!!! for now, just use the first suitable layer type | 
| Chris@45 | 130     LayerFactory::LayerType type = *types.begin(); | 
| Chris@45 | 131 | 
| Chris@45 | 132     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 133     if (!newLayer) return 0; | 
| Chris@45 | 134 | 
| Chris@45 | 135     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 136 | 
| Chris@45 | 137     addImportedModel(model); | 
| Chris@45 | 138     setModel(newLayer, model); | 
| Chris@45 | 139 | 
| Chris@45 | 140     //!!! and all channels | 
| Chris@45 | 141     setChannel(newLayer, -1); | 
| Chris@45 | 142 | 
| Chris@45 | 143     m_layers.insert(newLayer); | 
| Chris@45 | 144     emit layerAdded(newLayer); | 
| Chris@45 | 145     return newLayer; | 
| Chris@45 | 146 } | 
| Chris@45 | 147 | 
| Chris@45 | 148 Layer * | 
| Chris@45 | 149 Document::createEmptyLayer(LayerFactory::LayerType type) | 
| Chris@45 | 150 { | 
| Chris@45 | 151     Model *newModel = | 
| Chris@45 | 152 	LayerFactory::getInstance()->createEmptyModel(type, m_mainModel); | 
| Chris@45 | 153     if (!newModel) return 0; | 
| Chris@45 | 154 | 
| Chris@45 | 155     Layer *newLayer = createLayer(type); | 
| Chris@45 | 156     if (!newLayer) { | 
| Chris@45 | 157 	delete newModel; | 
| Chris@45 | 158 	return 0; | 
| Chris@45 | 159     } | 
| Chris@45 | 160 | 
| Chris@45 | 161     addImportedModel(newModel); | 
| Chris@45 | 162     setModel(newLayer, newModel); | 
| Chris@45 | 163 | 
| Chris@45 | 164     return newLayer; | 
| Chris@45 | 165 } | 
| Chris@45 | 166 | 
| Chris@45 | 167 Layer * | 
| Chris@45 | 168 Document::createDerivedLayer(LayerFactory::LayerType type, | 
| Chris@45 | 169 			     TransformId transform) | 
| Chris@45 | 170 { | 
| Chris@45 | 171     Layer *newLayer = createLayer(type); | 
| Chris@45 | 172     if (!newLayer) return 0; | 
| Chris@45 | 173 | 
| Chris@45 | 174     newLayer->setObjectName(getUniqueLayerName | 
| Chris@45 | 175                             (TransformFactory::getInstance()-> | 
| Chris@45 | 176                              getTransformFriendlyName(transform))); | 
| Chris@45 | 177 | 
| Chris@45 | 178     return newLayer; | 
| Chris@45 | 179 } | 
| Chris@45 | 180 | 
| Chris@45 | 181 Layer * | 
| Chris@45 | 182 Document::createDerivedLayer(TransformId transform, | 
| Chris@45 | 183                              Model *inputModel, | 
| Chris@45 | 184                              const PluginTransform::ExecutionContext &context, | 
| Chris@45 | 185                              QString configurationXml) | 
| Chris@45 | 186 { | 
| Chris@45 | 187     Model *newModel = addDerivedModel(transform, inputModel, | 
| Chris@45 | 188                                       context, configurationXml); | 
| Chris@45 | 189     if (!newModel) { | 
| Chris@45 | 190         // error already printed to stderr by addDerivedModel | 
| Chris@45 | 191         emit modelGenerationFailed(transform); | 
| Chris@45 | 192         return 0; | 
| Chris@45 | 193     } | 
| Chris@45 | 194 | 
| Chris@45 | 195     LayerFactory::LayerTypeSet types = | 
| Chris@45 | 196 	LayerFactory::getInstance()->getValidLayerTypes(newModel); | 
| Chris@45 | 197 | 
| Chris@45 | 198     if (types.empty()) { | 
| Chris@45 | 199 	std::cerr << "WARNING: Document::createLayerForTransform: no valid display layer for output of transform " << transform.toStdString() << std::endl; | 
| Chris@45 | 200 	delete newModel; | 
| Chris@45 | 201 	return 0; | 
| Chris@45 | 202     } | 
| Chris@45 | 203 | 
| Chris@45 | 204     //!!! for now, just use the first suitable layer type | 
| Chris@45 | 205 | 
| Chris@45 | 206     Layer *newLayer = createLayer(*types.begin()); | 
| Chris@45 | 207     setModel(newLayer, newModel); | 
| Chris@45 | 208 | 
| Chris@45 | 209     //!!! We need to clone the model when adding the layer, so that it | 
| Chris@45 | 210     //can be edited without affecting other layers that are based on | 
| Chris@45 | 211     //the same model.  Unfortunately we can't just clone it now, | 
| Chris@45 | 212     //because it probably hasn't been completed yet -- the transform | 
| Chris@45 | 213     //runs in the background.  Maybe the transform has to handle | 
| Chris@45 | 214     //cloning and cacheing models itself. | 
| Chris@45 | 215     // | 
| Chris@45 | 216     // Once we do clone models here, of course, we'll have to avoid | 
| Chris@45 | 217     // leaking them too. | 
| Chris@45 | 218     // | 
| Chris@45 | 219     // We want the user to be able to add a model to a second layer | 
| Chris@45 | 220     // _while it's still being calculated in the first_ and have it | 
| Chris@45 | 221     // work quickly.  That means we need to put the same physical | 
| Chris@45 | 222     // model pointer in both layers, so they can't actually be cloned. | 
| Chris@45 | 223 | 
| Chris@45 | 224     if (newLayer) { | 
| Chris@45 | 225 	newLayer->setObjectName(getUniqueLayerName | 
| Chris@45 | 226                                 (TransformFactory::getInstance()-> | 
| Chris@45 | 227                                  getTransformFriendlyName(transform))); | 
| Chris@45 | 228     } | 
| Chris@45 | 229 | 
| Chris@45 | 230     emit layerAdded(newLayer); | 
| Chris@45 | 231     return newLayer; | 
| Chris@45 | 232 } | 
| Chris@45 | 233 | 
| Chris@45 | 234 void | 
| Chris@45 | 235 Document::setMainModel(WaveFileModel *model) | 
| Chris@45 | 236 { | 
| Chris@45 | 237     Model *oldMainModel = m_mainModel; | 
| Chris@45 | 238     m_mainModel = model; | 
| Chris@45 | 239 | 
| Chris@45 | 240     emit modelAdded(m_mainModel); | 
| Chris@45 | 241 | 
| Chris@45 | 242     std::vector<Layer *> obsoleteLayers; | 
| Chris@45 | 243     std::set<QString> failedTransforms; | 
| Chris@45 | 244 | 
| Chris@45 | 245     // We need to ensure that no layer is left using oldMainModel or | 
| Chris@45 | 246     // any of the old derived models as its model.  Either replace the | 
| Chris@45 | 247     // model, or delete the layer for each layer that is currently | 
| Chris@45 | 248     // using one of these.  Carry out this replacement before we | 
| Chris@45 | 249     // delete any of the models. | 
| Chris@45 | 250 | 
| Chris@45 | 251     for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 252 | 
| Chris@45 | 253 	Layer *layer = *i; | 
| Chris@45 | 254 	Model *model = layer->getModel(); | 
| Chris@45 | 255 | 
| Chris@45 | 256 //        std::cerr << "Document::setMainModel: inspecting model " | 
| Chris@45 | 257 //                  << (model ? model->objectName().toStdString() : "(null)") << " in layer " | 
| Chris@45 | 258 //                  << layer->objectName().toStdString() << std::endl; | 
| Chris@45 | 259 | 
| Chris@45 | 260 	if (model == oldMainModel) { | 
| Chris@45 | 261 //            std::cerr << "... it uses the old main model, replacing" << std::endl; | 
| Chris@45 | 262 	    LayerFactory::getInstance()->setModel(layer, m_mainModel); | 
| Chris@45 | 263 	    continue; | 
| Chris@45 | 264 	} | 
| Chris@45 | 265 | 
| Chris@45 | 266 	if (m_models.find(model) == m_models.end()) { | 
| Chris@45 | 267 	    std::cerr << "WARNING: Document::setMainModel: Unknown model " | 
| Chris@45 | 268 		      << model << " in layer " << layer << std::endl; | 
| Chris@45 | 269 	    // get rid of this hideous degenerate | 
| Chris@45 | 270 	    obsoleteLayers.push_back(layer); | 
| Chris@45 | 271 	    continue; | 
| Chris@45 | 272 	} | 
| Chris@45 | 273 | 
| Chris@45 | 274 	if (m_models[model].source == oldMainModel) { | 
| Chris@45 | 275 | 
| Chris@45 | 276 //            std::cerr << "... it uses a model derived from the old main model, regenerating" << std::endl; | 
| Chris@45 | 277 | 
| Chris@45 | 278 	    // This model was derived from the previous main | 
| Chris@45 | 279 	    // model: regenerate it. | 
| Chris@45 | 280 | 
| Chris@45 | 281 	    TransformId transform = m_models[model].transform; | 
| Chris@45 | 282             PluginTransform::ExecutionContext context = m_models[model].context; | 
| Chris@45 | 283 | 
| Chris@45 | 284 	    Model *replacementModel = | 
| Chris@45 | 285                 addDerivedModel(transform, | 
| Chris@45 | 286                                 m_mainModel, | 
| Chris@45 | 287                                 context, | 
| Chris@45 | 288                                 m_models[model].configurationXml); | 
| Chris@45 | 289 | 
| Chris@45 | 290 	    if (!replacementModel) { | 
| Chris@45 | 291 		std::cerr << "WARNING: Document::setMainModel: Failed to regenerate model for transform \"" | 
| Chris@45 | 292 			  << transform.toStdString() << "\"" << " in layer " << layer << std::endl; | 
| Chris@45 | 293                 if (failedTransforms.find(transform) == failedTransforms.end()) { | 
| Chris@45 | 294                     emit modelRegenerationFailed(layer->objectName(), | 
| Chris@45 | 295                                                  transform); | 
| Chris@45 | 296                     failedTransforms.insert(transform); | 
| Chris@45 | 297                 } | 
| Chris@45 | 298 		obsoleteLayers.push_back(layer); | 
| Chris@45 | 299 	    } else { | 
| Chris@45 | 300                 std::cerr << "Replacing model " << model << " (type " | 
| Chris@45 | 301                           << typeid(*model).name() << ") with model " | 
| Chris@45 | 302                           << replacementModel << " (type " | 
| Chris@45 | 303                           << typeid(*replacementModel).name() << ") in layer " | 
| Chris@45 | 304                           << layer << " (name " << layer->objectName().toStdString() << ")" | 
| Chris@45 | 305                           << std::endl; | 
| Chris@45 | 306                 RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 307                     dynamic_cast<RangeSummarisableTimeValueModel *>(replacementModel); | 
| Chris@45 | 308                 if (rm) { | 
| Chris@45 | 309                     std::cerr << "new model has " << rm->getChannelCount() << " channels " << std::endl; | 
| Chris@45 | 310                 } else { | 
| Chris@45 | 311                     std::cerr << "new model is not a RangeSummarisableTimeValueModel!" << std::endl; | 
| Chris@45 | 312                 } | 
| Chris@45 | 313 		setModel(layer, replacementModel); | 
| Chris@45 | 314 	    } | 
| Chris@45 | 315 	} | 
| Chris@45 | 316     } | 
| Chris@45 | 317 | 
| Chris@45 | 318     for (size_t k = 0; k < obsoleteLayers.size(); ++k) { | 
| Chris@45 | 319 	deleteLayer(obsoleteLayers[k], true); | 
| Chris@45 | 320     } | 
| Chris@45 | 321 | 
| Chris@48 | 322     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@48 | 323         if (i->first->getAlignmentReference() == oldMainModel) { | 
| Chris@48 | 324             alignModel(i->first); | 
| Chris@48 | 325         } | 
| Chris@48 | 326     } | 
| Chris@48 | 327 | 
| Chris@45 | 328     emit mainModelChanged(m_mainModel); | 
| Chris@45 | 329 | 
| Chris@45 | 330     // we already emitted modelAboutToBeDeleted for this | 
| Chris@45 | 331     delete oldMainModel; | 
| Chris@45 | 332 } | 
| Chris@45 | 333 | 
| Chris@45 | 334 void | 
| Chris@45 | 335 Document::addDerivedModel(TransformId transform, | 
| Chris@45 | 336                           Model *inputModel, | 
| Chris@45 | 337                           const PluginTransform::ExecutionContext &context, | 
| Chris@45 | 338                           Model *outputModelToAdd, | 
| Chris@45 | 339                           QString configurationXml) | 
| Chris@45 | 340 { | 
| Chris@45 | 341     if (m_models.find(outputModelToAdd) != m_models.end()) { | 
| Chris@45 | 342 	std::cerr << "WARNING: Document::addDerivedModel: Model already added" | 
| Chris@45 | 343 		  << std::endl; | 
| Chris@45 | 344 	return; | 
| Chris@45 | 345     } | 
| Chris@45 | 346 | 
| Chris@45 | 347 //    std::cerr << "Document::addDerivedModel: source is " << inputModel << " \"" << inputModel->objectName().toStdString() << "\"" << std::endl; | 
| Chris@45 | 348 | 
| Chris@45 | 349     ModelRecord rec; | 
| Chris@45 | 350     rec.source = inputModel; | 
| Chris@45 | 351     rec.transform = transform; | 
| Chris@45 | 352     rec.context = context; | 
| Chris@45 | 353     rec.configurationXml = configurationXml; | 
| Chris@45 | 354     rec.refcount = 0; | 
| Chris@45 | 355 | 
| Chris@45 | 356     outputModelToAdd->setSourceModel(inputModel); | 
| Chris@45 | 357 | 
| Chris@45 | 358     m_models[outputModelToAdd] = rec; | 
| Chris@45 | 359 | 
| Chris@45 | 360     emit modelAdded(outputModelToAdd); | 
| Chris@45 | 361 } | 
| Chris@45 | 362 | 
| Chris@45 | 363 | 
| Chris@45 | 364 void | 
| Chris@45 | 365 Document::addImportedModel(Model *model) | 
| Chris@45 | 366 { | 
| Chris@45 | 367     if (m_models.find(model) != m_models.end()) { | 
| Chris@45 | 368 	std::cerr << "WARNING: Document::addImportedModel: Model already added" | 
| Chris@45 | 369 		  << std::endl; | 
| Chris@45 | 370 	return; | 
| Chris@45 | 371     } | 
| Chris@45 | 372 | 
| Chris@45 | 373     ModelRecord rec; | 
| Chris@45 | 374     rec.source = 0; | 
| Chris@45 | 375     rec.transform = ""; | 
| Chris@45 | 376     rec.refcount = 0; | 
| Chris@45 | 377 | 
| Chris@45 | 378     m_models[model] = rec; | 
| Chris@45 | 379 | 
| Chris@47 | 380     if (m_autoAlignment) alignModel(model); | 
| Chris@47 | 381 | 
| Chris@45 | 382     emit modelAdded(model); | 
| Chris@45 | 383 } | 
| Chris@45 | 384 | 
| Chris@45 | 385 Model * | 
| Chris@45 | 386 Document::addDerivedModel(TransformId transform, | 
| Chris@45 | 387                           Model *inputModel, | 
| Chris@45 | 388                           const PluginTransform::ExecutionContext &context, | 
| Chris@45 | 389                           QString configurationXml) | 
| Chris@45 | 390 { | 
| Chris@45 | 391     Model *model = 0; | 
| Chris@45 | 392 | 
| Chris@45 | 393     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 394 	if (i->second.transform == transform && | 
| Chris@45 | 395 	    i->second.source == inputModel && | 
| Chris@45 | 396             i->second.context == context && | 
| Chris@45 | 397             i->second.configurationXml == configurationXml) { | 
| Chris@45 | 398 	    return i->first; | 
| Chris@45 | 399 	} | 
| Chris@45 | 400     } | 
| Chris@45 | 401 | 
| Chris@45 | 402     model = TransformFactory::getInstance()->transform | 
| Chris@45 | 403 	(transform, inputModel, context, configurationXml); | 
| Chris@45 | 404 | 
| Chris@45 | 405     if (!model) { | 
| Chris@45 | 406 	std::cerr << "WARNING: Document::addDerivedModel: no output model for transform " << transform.toStdString() << std::endl; | 
| Chris@45 | 407     } else { | 
| Chris@45 | 408 	addDerivedModel(transform, inputModel, context, model, configurationXml); | 
| Chris@45 | 409     } | 
| Chris@45 | 410 | 
| Chris@45 | 411     return model; | 
| Chris@45 | 412 } | 
| Chris@45 | 413 | 
| Chris@45 | 414 void | 
| Chris@45 | 415 Document::releaseModel(Model *model) // Will _not_ release main model! | 
| Chris@45 | 416 { | 
| Chris@45 | 417     if (model == 0) { | 
| Chris@45 | 418 	return; | 
| Chris@45 | 419     } | 
| Chris@45 | 420 | 
| Chris@45 | 421     if (model == m_mainModel) { | 
| Chris@45 | 422 	return; | 
| Chris@45 | 423     } | 
| Chris@45 | 424 | 
| Chris@45 | 425     bool toDelete = false; | 
| Chris@45 | 426 | 
| Chris@45 | 427     if (m_models.find(model) != m_models.end()) { | 
| Chris@45 | 428 | 
| Chris@45 | 429 	if (m_models[model].refcount == 0) { | 
| Chris@45 | 430 	    std::cerr << "WARNING: Document::releaseModel: model " << model | 
| Chris@45 | 431 		      << " reference count is zero already!" << std::endl; | 
| Chris@45 | 432 	} else { | 
| Chris@45 | 433 	    if (--m_models[model].refcount == 0) { | 
| Chris@45 | 434 		toDelete = true; | 
| Chris@45 | 435 	    } | 
| Chris@45 | 436 	} | 
| Chris@45 | 437     } else { | 
| Chris@45 | 438 	std::cerr << "WARNING: Document::releaseModel: Unfound model " | 
| Chris@45 | 439 		  << model << std::endl; | 
| Chris@45 | 440 	toDelete = true; | 
| Chris@45 | 441     } | 
| Chris@45 | 442 | 
| Chris@45 | 443     if (toDelete) { | 
| Chris@45 | 444 | 
| Chris@45 | 445 	int sourceCount = 0; | 
| Chris@45 | 446 | 
| Chris@45 | 447 	for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 448 	    if (i->second.source == model) { | 
| Chris@45 | 449 		++sourceCount; | 
| Chris@45 | 450 		i->second.source = 0; | 
| Chris@45 | 451 	    } | 
| Chris@45 | 452 	} | 
| Chris@45 | 453 | 
| Chris@45 | 454 	if (sourceCount > 0) { | 
| Chris@45 | 455 	    std::cerr << "Document::releaseModel: Deleting model " | 
| Chris@45 | 456 		      << model << " even though it is source for " | 
| Chris@45 | 457 		      << sourceCount << " other derived model(s) -- resetting " | 
| Chris@45 | 458 		      << "their source fields appropriately" << std::endl; | 
| Chris@45 | 459 	} | 
| Chris@45 | 460 | 
| Chris@45 | 461 	emit modelAboutToBeDeleted(model); | 
| Chris@45 | 462         model->aboutToDelete(); | 
| Chris@45 | 463 	m_models.erase(model); | 
| Chris@45 | 464 	delete model; | 
| Chris@45 | 465     } | 
| Chris@45 | 466 } | 
| Chris@45 | 467 | 
| Chris@45 | 468 void | 
| Chris@45 | 469 Document::deleteLayer(Layer *layer, bool force) | 
| Chris@45 | 470 { | 
| Chris@45 | 471     if (m_layerViewMap.find(layer) != m_layerViewMap.end() && | 
| Chris@45 | 472 	m_layerViewMap[layer].size() > 0) { | 
| Chris@45 | 473 | 
| Chris@45 | 474 	std::cerr << "WARNING: Document::deleteLayer: Layer " | 
| Chris@45 | 475 		  << layer << " [" << layer->objectName().toStdString() << "]" | 
| Chris@45 | 476 		  << " is still used in " << m_layerViewMap[layer].size() | 
| Chris@45 | 477 		  << " views!" << std::endl; | 
| Chris@45 | 478 | 
| Chris@45 | 479 	if (force) { | 
| Chris@45 | 480 | 
| Chris@45 | 481 	    std::cerr << "(force flag set -- deleting from all views)" << std::endl; | 
| Chris@45 | 482 | 
| Chris@45 | 483 	    for (std::set<View *>::iterator j = m_layerViewMap[layer].begin(); | 
| Chris@45 | 484 		 j != m_layerViewMap[layer].end(); ++j) { | 
| Chris@45 | 485 		// don't use removeLayerFromView, as it issues a command | 
| Chris@45 | 486 		layer->setLayerDormant(*j, true); | 
| Chris@45 | 487 		(*j)->removeLayer(layer); | 
| Chris@45 | 488 	    } | 
| Chris@45 | 489 | 
| Chris@45 | 490 	    m_layerViewMap.erase(layer); | 
| Chris@45 | 491 | 
| Chris@45 | 492 	} else { | 
| Chris@45 | 493 	    return; | 
| Chris@45 | 494 	} | 
| Chris@45 | 495     } | 
| Chris@45 | 496 | 
| Chris@45 | 497     if (m_layers.find(layer) == m_layers.end()) { | 
| Chris@45 | 498 	std::cerr << "Document::deleteLayer: Layer " | 
| Chris@45 | 499 		  << layer << " does not exist, or has already been deleted " | 
| Chris@45 | 500 		  << "(this may not be as serious as it sounds)" << std::endl; | 
| Chris@45 | 501 	return; | 
| Chris@45 | 502     } | 
| Chris@45 | 503 | 
| Chris@45 | 504     m_layers.erase(layer); | 
| Chris@45 | 505 | 
| Chris@45 | 506     releaseModel(layer->getModel()); | 
| Chris@45 | 507     emit layerRemoved(layer); | 
| Chris@45 | 508     emit layerAboutToBeDeleted(layer); | 
| Chris@45 | 509     delete layer; | 
| Chris@45 | 510 } | 
| Chris@45 | 511 | 
| Chris@45 | 512 void | 
| Chris@45 | 513 Document::setModel(Layer *layer, Model *model) | 
| Chris@45 | 514 { | 
| Chris@45 | 515     if (model && | 
| Chris@45 | 516 	model != m_mainModel && | 
| Chris@45 | 517 	m_models.find(model) == m_models.end()) { | 
| Chris@45 | 518 	std::cerr << "ERROR: Document::setModel: Layer " << layer | 
| Chris@45 | 519 		  << " (\"" << layer->objectName().toStdString() | 
| Chris@45 | 520                   << "\") wants to use unregistered model " << model | 
| Chris@45 | 521 		  << ": register the layer's model before setting it!" | 
| Chris@45 | 522 		  << std::endl; | 
| Chris@45 | 523 	return; | 
| Chris@45 | 524     } | 
| Chris@45 | 525 | 
| Chris@45 | 526     Model *previousModel = layer->getModel(); | 
| Chris@45 | 527 | 
| Chris@45 | 528     if (previousModel == model) { | 
| Chris@45 | 529         std::cerr << "WARNING: Document::setModel: Layer " << layer << " (\"" | 
| Chris@45 | 530                   << layer->objectName().toStdString() | 
| Chris@45 | 531                   << "\") is already set to model " | 
| Chris@45 | 532                   << model << " (\"" | 
| Chris@45 | 533                   << (model ? model->objectName().toStdString() : "(null)") | 
| Chris@45 | 534                   << "\")" << std::endl; | 
| Chris@45 | 535         return; | 
| Chris@45 | 536     } | 
| Chris@45 | 537 | 
| Chris@45 | 538     if (model && model != m_mainModel) { | 
| Chris@45 | 539 	m_models[model].refcount ++; | 
| Chris@45 | 540     } | 
| Chris@45 | 541 | 
| Chris@45 | 542     if (model && previousModel) { | 
| Chris@45 | 543         PlayParameterRepository::getInstance()->copyParameters | 
| Chris@45 | 544             (previousModel, model); | 
| Chris@45 | 545     } | 
| Chris@45 | 546 | 
| Chris@45 | 547     LayerFactory::getInstance()->setModel(layer, model); | 
| Chris@45 | 548 | 
| Chris@45 | 549     if (previousModel) { | 
| Chris@45 | 550         releaseModel(previousModel); | 
| Chris@45 | 551     } | 
| Chris@45 | 552 } | 
| Chris@45 | 553 | 
| Chris@45 | 554 void | 
| Chris@45 | 555 Document::setChannel(Layer *layer, int channel) | 
| Chris@45 | 556 { | 
| Chris@45 | 557     LayerFactory::getInstance()->setChannel(layer, channel); | 
| Chris@45 | 558 } | 
| Chris@45 | 559 | 
| Chris@45 | 560 void | 
| Chris@45 | 561 Document::addLayerToView(View *view, Layer *layer) | 
| Chris@45 | 562 { | 
| Chris@45 | 563     Model *model = layer->getModel(); | 
| Chris@45 | 564     if (!model) { | 
| Chris@45 | 565 //	std::cerr << "Document::addLayerToView: Layer (\"" | 
| Chris@45 | 566 //                  << layer->objectName().toStdString() | 
| Chris@45 | 567 //                  << "\") with no model being added to view: " | 
| Chris@45 | 568 //                  << "normally you want to set the model first" << std::endl; | 
| Chris@45 | 569     } else { | 
| Chris@45 | 570 	if (model != m_mainModel && | 
| Chris@45 | 571 	    m_models.find(model) == m_models.end()) { | 
| Chris@45 | 572 	    std::cerr << "ERROR: Document::addLayerToView: Layer " << layer | 
| Chris@45 | 573 		      << " has unregistered model " << model | 
| Chris@45 | 574 		      << " -- register the layer's model before adding the layer!" << std::endl; | 
| Chris@45 | 575 	    return; | 
| Chris@45 | 576 	} | 
| Chris@45 | 577     } | 
| Chris@45 | 578 | 
| Chris@45 | 579     CommandHistory::getInstance()->addCommand | 
| Chris@45 | 580 	(new Document::AddLayerCommand(this, view, layer)); | 
| Chris@45 | 581 } | 
| Chris@45 | 582 | 
| Chris@45 | 583 void | 
| Chris@45 | 584 Document::removeLayerFromView(View *view, Layer *layer) | 
| Chris@45 | 585 { | 
| Chris@45 | 586     CommandHistory::getInstance()->addCommand | 
| Chris@45 | 587 	(new Document::RemoveLayerCommand(this, view, layer)); | 
| Chris@45 | 588 } | 
| Chris@45 | 589 | 
| Chris@45 | 590 void | 
| Chris@45 | 591 Document::addToLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 592 { | 
| Chris@45 | 593     bool firstView = (m_layerViewMap.find(layer) == m_layerViewMap.end() || | 
| Chris@45 | 594                       m_layerViewMap[layer].empty()); | 
| Chris@45 | 595 | 
| Chris@45 | 596     if (m_layerViewMap[layer].find(view) != | 
| Chris@45 | 597 	m_layerViewMap[layer].end()) { | 
| Chris@45 | 598 	std::cerr << "WARNING: Document::addToLayerViewMap:" | 
| Chris@45 | 599 		  << " Layer " << layer << " -> view " << view << " already in" | 
| Chris@45 | 600 		  << " layer view map -- internal inconsistency" << std::endl; | 
| Chris@45 | 601     } | 
| Chris@45 | 602 | 
| Chris@45 | 603     m_layerViewMap[layer].insert(view); | 
| Chris@45 | 604 | 
| Chris@45 | 605     if (firstView) emit layerInAView(layer, true); | 
| Chris@45 | 606 } | 
| Chris@45 | 607 | 
| Chris@45 | 608 void | 
| Chris@45 | 609 Document::removeFromLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 610 { | 
| Chris@45 | 611     if (m_layerViewMap[layer].find(view) == | 
| Chris@45 | 612 	m_layerViewMap[layer].end()) { | 
| Chris@45 | 613 	std::cerr << "WARNING: Document::removeFromLayerViewMap:" | 
| Chris@45 | 614 		  << " Layer " << layer << " -> view " << view << " not in" | 
| Chris@45 | 615 		  << " layer view map -- internal inconsistency" << std::endl; | 
| Chris@45 | 616     } | 
| Chris@45 | 617 | 
| Chris@45 | 618     m_layerViewMap[layer].erase(view); | 
| Chris@45 | 619 | 
| Chris@45 | 620     if (m_layerViewMap[layer].empty()) { | 
| Chris@45 | 621         m_layerViewMap.erase(layer); | 
| Chris@45 | 622         emit layerInAView(layer, false); | 
| Chris@45 | 623     } | 
| Chris@45 | 624 } | 
| Chris@45 | 625 | 
| Chris@45 | 626 QString | 
| Chris@45 | 627 Document::getUniqueLayerName(QString candidate) | 
| Chris@45 | 628 { | 
| Chris@45 | 629     for (int count = 1; ; ++count) { | 
| Chris@45 | 630 | 
| Chris@45 | 631         QString adjusted = | 
| Chris@45 | 632             (count > 1 ? QString("%1 <%2>").arg(candidate).arg(count) : | 
| Chris@45 | 633              candidate); | 
| Chris@45 | 634 | 
| Chris@45 | 635         bool duplicate = false; | 
| Chris@45 | 636 | 
| Chris@45 | 637         for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 638             if ((*i)->objectName() == adjusted) { | 
| Chris@45 | 639                 duplicate = true; | 
| Chris@45 | 640                 break; | 
| Chris@45 | 641             } | 
| Chris@45 | 642         } | 
| Chris@45 | 643 | 
| Chris@45 | 644         if (!duplicate) return adjusted; | 
| Chris@45 | 645     } | 
| Chris@45 | 646 } | 
| Chris@45 | 647 | 
| Chris@45 | 648 std::vector<Model *> | 
| Chris@45 | 649 Document::getTransformInputModels() | 
| Chris@45 | 650 { | 
| Chris@45 | 651     std::vector<Model *> models; | 
| Chris@45 | 652 | 
| Chris@45 | 653     if (!m_mainModel) return models; | 
| Chris@45 | 654 | 
| Chris@45 | 655     models.push_back(m_mainModel); | 
| Chris@45 | 656 | 
| Chris@45 | 657     //!!! This will pick up all models, including those that aren't visible... | 
| Chris@45 | 658 | 
| Chris@45 | 659     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 660 | 
| Chris@45 | 661         Model *model = i->first; | 
| Chris@45 | 662         if (!model || model == m_mainModel) continue; | 
| Chris@45 | 663         DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); | 
| Chris@45 | 664 | 
| Chris@45 | 665         if (dtvm) { | 
| Chris@45 | 666             models.push_back(dtvm); | 
| Chris@45 | 667         } | 
| Chris@45 | 668     } | 
| Chris@45 | 669 | 
| Chris@45 | 670     return models; | 
| Chris@45 | 671 } | 
| Chris@45 | 672 | 
| Chris@45 | 673 void | 
| Chris@45 | 674 Document::alignModel(Model *model) | 
| Chris@45 | 675 { | 
| Chris@45 | 676     if (!m_mainModel || model == m_mainModel) return; | 
| Chris@45 | 677 | 
| Chris@45 | 678     RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 679         dynamic_cast<RangeSummarisableTimeValueModel *>(model); | 
| Chris@45 | 680     if (!rm) return; | 
| Chris@48 | 681 | 
| Chris@48 | 682     if (rm->getAlignmentReference() == m_mainModel) return; | 
| Chris@45 | 683 | 
| Chris@45 | 684     // This involves creating three new models: | 
| Chris@45 | 685 | 
| Chris@45 | 686     // 1. an AggregateWaveModel to provide the mixdowns of the main | 
| Chris@45 | 687     // model and the new model in its two channels, as input to the | 
| Chris@45 | 688     // MATCH plugin | 
| Chris@45 | 689 | 
| Chris@45 | 690     // 2. a SparseTimeValueModel, which is the model automatically | 
| Chris@45 | 691     // created by FeatureExtractionPluginTransform when running the | 
| Chris@45 | 692     // MATCH plugin (thus containing the alignment path) | 
| Chris@45 | 693 | 
| Chris@45 | 694     // 3. an AlignmentModel, which stores the path model and carries | 
| Chris@45 | 695     // out alignment lookups on it. | 
| Chris@45 | 696 | 
| Chris@45 | 697     // The first two of these are provided as arguments to the | 
| Chris@45 | 698     // constructor for the third, which takes responsibility for | 
| Chris@45 | 699     // deleting them.  The AlignmentModel, meanwhile, is passed to the | 
| Chris@45 | 700     // new model we are aligning, which also takes responsibility for | 
| Chris@45 | 701     // it.  We should not have to delete any of these new models here. | 
| Chris@45 | 702 | 
| Chris@45 | 703     AggregateWaveModel::ChannelSpecList components; | 
| Chris@45 | 704 | 
| Chris@45 | 705     components.push_back(AggregateWaveModel::ModelChannelSpec | 
| Chris@45 | 706                          (m_mainModel, -1)); | 
| Chris@45 | 707 | 
| Chris@45 | 708     components.push_back(AggregateWaveModel::ModelChannelSpec | 
| Chris@45 | 709                          (rm, -1)); | 
| Chris@45 | 710 | 
| Chris@45 | 711     Model *aggregate = new AggregateWaveModel(components); | 
| Chris@45 | 712 | 
| Chris@45 | 713     TransformId id = "vamp:match-vamp-plugin:match:path"; | 
| Chris@45 | 714 | 
| Chris@45 | 715     TransformFactory *factory = TransformFactory::getInstance(); | 
| Chris@45 | 716 | 
| Chris@45 | 717     Model *transformOutput = factory->transform | 
| Chris@45 | 718         (id, aggregate, | 
| Chris@45 | 719          factory->getDefaultContextForTransform(id, aggregate), | 
| Chris@45 | 720          "<plugin param-serialise=\"1\"/>"); | 
| Chris@45 | 721 | 
| Chris@45 | 722     SparseTimeValueModel *path = dynamic_cast<SparseTimeValueModel *> | 
| Chris@45 | 723         (transformOutput); | 
| Chris@45 | 724 | 
| Chris@45 | 725     if (!path) { | 
| Chris@45 | 726         std::cerr << "Document::alignModel: ERROR: Failed to create alignment path (no MATCH plugin?)" << std::endl; | 
| Chris@45 | 727         delete transformOutput; | 
| Chris@45 | 728         delete aggregate; | 
| Chris@45 | 729         return; | 
| Chris@45 | 730     } | 
| Chris@45 | 731 | 
| Chris@45 | 732     AlignmentModel *alignmentModel = new AlignmentModel | 
| Chris@45 | 733         (m_mainModel, model, aggregate, path); | 
| Chris@45 | 734 | 
| Chris@45 | 735     rm->setAlignment(alignmentModel); | 
| Chris@45 | 736 } | 
| Chris@45 | 737 | 
| Chris@45 | 738 void | 
| Chris@45 | 739 Document::alignModels() | 
| Chris@45 | 740 { | 
| Chris@45 | 741     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 742         alignModel(i->first); | 
| Chris@45 | 743     } | 
| Chris@45 | 744 } | 
| Chris@45 | 745 | 
| Chris@45 | 746 Document::AddLayerCommand::AddLayerCommand(Document *d, | 
| Chris@45 | 747 					   View *view, | 
| Chris@45 | 748 					   Layer *layer) : | 
| Chris@45 | 749     m_d(d), | 
| Chris@45 | 750     m_view(view), | 
| Chris@45 | 751     m_layer(layer), | 
| Chris@45 | 752     m_name(qApp->translate("AddLayerCommand", "Add %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 753     m_added(false) | 
| Chris@45 | 754 { | 
| Chris@45 | 755 } | 
| Chris@45 | 756 | 
| Chris@45 | 757 Document::AddLayerCommand::~AddLayerCommand() | 
| Chris@45 | 758 { | 
| Chris@45 | 759 //    std::cerr << "Document::AddLayerCommand::~AddLayerCommand" << std::endl; | 
| Chris@45 | 760     if (!m_added) { | 
| Chris@45 | 761 	m_d->deleteLayer(m_layer); | 
| Chris@45 | 762     } | 
| Chris@45 | 763 } | 
| Chris@45 | 764 | 
| Chris@45 | 765 void | 
| Chris@45 | 766 Document::AddLayerCommand::execute() | 
| Chris@45 | 767 { | 
| Chris@45 | 768     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@45 | 769 	if (m_view->getLayer(i) == m_layer) { | 
| Chris@45 | 770 	    // already there | 
| Chris@45 | 771 	    m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 772 	    m_added = true; | 
| Chris@45 | 773 	    return; | 
| Chris@45 | 774 	} | 
| Chris@45 | 775     } | 
| Chris@45 | 776 | 
| Chris@45 | 777     m_view->addLayer(m_layer); | 
| Chris@45 | 778     m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 779 | 
| Chris@45 | 780     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 781     m_added = true; | 
| Chris@45 | 782 } | 
| Chris@45 | 783 | 
| Chris@45 | 784 void | 
| Chris@45 | 785 Document::AddLayerCommand::unexecute() | 
| Chris@45 | 786 { | 
| Chris@45 | 787     m_view->removeLayer(m_layer); | 
| Chris@45 | 788     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 789 | 
| Chris@45 | 790     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 791     m_added = false; | 
| Chris@45 | 792 } | 
| Chris@45 | 793 | 
| Chris@45 | 794 Document::RemoveLayerCommand::RemoveLayerCommand(Document *d, | 
| Chris@45 | 795 						 View *view, | 
| Chris@45 | 796 						 Layer *layer) : | 
| Chris@45 | 797     m_d(d), | 
| Chris@45 | 798     m_view(view), | 
| Chris@45 | 799     m_layer(layer), | 
| Chris@45 | 800     m_name(qApp->translate("RemoveLayerCommand", "Delete %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 801     m_added(true) | 
| Chris@45 | 802 { | 
| Chris@45 | 803 } | 
| Chris@45 | 804 | 
| Chris@45 | 805 Document::RemoveLayerCommand::~RemoveLayerCommand() | 
| Chris@45 | 806 { | 
| Chris@45 | 807 //    std::cerr << "Document::RemoveLayerCommand::~RemoveLayerCommand" << std::endl; | 
| Chris@45 | 808     if (!m_added) { | 
| Chris@45 | 809 	m_d->deleteLayer(m_layer); | 
| Chris@45 | 810     } | 
| Chris@45 | 811 } | 
| Chris@45 | 812 | 
| Chris@45 | 813 void | 
| Chris@45 | 814 Document::RemoveLayerCommand::execute() | 
| Chris@45 | 815 { | 
| Chris@45 | 816     bool have = false; | 
| Chris@45 | 817     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@45 | 818 	if (m_view->getLayer(i) == m_layer) { | 
| Chris@45 | 819 	    have = true; | 
| Chris@45 | 820 	    break; | 
| Chris@45 | 821 	} | 
| Chris@45 | 822     } | 
| Chris@45 | 823 | 
| Chris@45 | 824     if (!have) { // not there! | 
| Chris@45 | 825 	m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 826 	m_added = false; | 
| Chris@45 | 827 	return; | 
| Chris@45 | 828     } | 
| Chris@45 | 829 | 
| Chris@45 | 830     m_view->removeLayer(m_layer); | 
| Chris@45 | 831     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 832 | 
| Chris@45 | 833     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 834     m_added = false; | 
| Chris@45 | 835 } | 
| Chris@45 | 836 | 
| Chris@45 | 837 void | 
| Chris@45 | 838 Document::RemoveLayerCommand::unexecute() | 
| Chris@45 | 839 { | 
| Chris@45 | 840     m_view->addLayer(m_layer); | 
| Chris@45 | 841     m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 842 | 
| Chris@45 | 843     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 844     m_added = true; | 
| Chris@45 | 845 } | 
| Chris@45 | 846 | 
| Chris@45 | 847 void | 
| Chris@45 | 848 Document::toXml(QTextStream &out, QString indent, QString extraAttributes) const | 
| Chris@45 | 849 { | 
| Chris@45 | 850     out << indent + QString("<data%1%2>\n") | 
| Chris@45 | 851         .arg(extraAttributes == "" ? "" : " ").arg(extraAttributes); | 
| Chris@45 | 852 | 
| Chris@45 | 853     if (m_mainModel) { | 
| Chris@45 | 854 	m_mainModel->toXml(out, indent + "  ", "mainModel=\"true\""); | 
| Chris@45 | 855     } | 
| Chris@45 | 856 | 
| Chris@45 | 857     // Models that are not used in a layer that is in a view should | 
| Chris@45 | 858     // not be written.  Get our list of required models first. | 
| Chris@45 | 859 | 
| Chris@45 | 860     std::set<const Model *> used; | 
| Chris@45 | 861 | 
| Chris@45 | 862     for (LayerViewMap::const_iterator i = m_layerViewMap.begin(); | 
| Chris@45 | 863          i != m_layerViewMap.end(); ++i) { | 
| Chris@45 | 864 | 
| Chris@45 | 865         if (i->first && !i->second.empty() && i->first->getModel()) { | 
| Chris@45 | 866             used.insert(i->first->getModel()); | 
| Chris@45 | 867         } | 
| Chris@45 | 868     } | 
| Chris@45 | 869 | 
| Chris@45 | 870     for (ModelMap::const_iterator i = m_models.begin(); | 
| Chris@45 | 871 	 i != m_models.end(); ++i) { | 
| Chris@45 | 872 | 
| Chris@45 | 873         const Model *model = i->first; | 
| Chris@45 | 874 	const ModelRecord &rec = i->second; | 
| Chris@45 | 875 | 
| Chris@45 | 876         if (used.find(model) == used.end()) continue; | 
| Chris@45 | 877 | 
| Chris@45 | 878         // We need an intelligent way to determine which models need | 
| Chris@45 | 879         // to be streamed (i.e. have been edited, or are small) and | 
| Chris@45 | 880         // which should not be (i.e. remain as generated by a | 
| Chris@45 | 881         // transform, and are large). | 
| Chris@45 | 882         // | 
| Chris@45 | 883         // At the moment we can get away with deciding not to stream | 
| Chris@45 | 884         // dense 3d models or writable wave file models, provided they | 
| Chris@45 | 885         // were generated from a transform, because at the moment there | 
| Chris@45 | 886         // is no way to edit those model types so it should be safe to | 
| Chris@45 | 887         // regenerate them.  That won't always work in future though. | 
| Chris@45 | 888         // It would be particularly nice to be able to ask the user, | 
| Chris@45 | 889         // as well as making an intelligent guess. | 
| Chris@45 | 890 | 
| Chris@45 | 891         bool writeModel = true; | 
| Chris@45 | 892         bool haveDerivation = false; | 
| Chris@45 | 893 | 
| Chris@45 | 894         if (rec.source && rec.transform != "") { | 
| Chris@45 | 895             haveDerivation = true; | 
| Chris@45 | 896         } | 
| Chris@45 | 897 | 
| Chris@45 | 898         if (haveDerivation) { | 
| Chris@45 | 899             if (dynamic_cast<const WritableWaveFileModel *>(model)) { | 
| Chris@45 | 900                 writeModel = false; | 
| Chris@45 | 901             } else if (dynamic_cast<const DenseThreeDimensionalModel *>(model)) { | 
| Chris@45 | 902                 writeModel = false; | 
| Chris@45 | 903             } | 
| Chris@45 | 904         } | 
| Chris@45 | 905 | 
| Chris@45 | 906         if (writeModel) { | 
| Chris@45 | 907             i->first->toXml(out, indent + "  "); | 
| Chris@45 | 908         } | 
| Chris@45 | 909 | 
| Chris@45 | 910 	if (haveDerivation) { | 
| Chris@45 | 911 | 
| Chris@45 | 912             QString extentsAttributes; | 
| Chris@45 | 913             if (rec.context.startFrame != 0 || | 
| Chris@45 | 914                 rec.context.duration != 0) { | 
| Chris@45 | 915                 extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") | 
| Chris@45 | 916                     .arg(rec.context.startFrame) | 
| Chris@45 | 917                     .arg(rec.context.duration); | 
| Chris@45 | 918             } | 
| Chris@45 | 919 | 
| Chris@45 | 920 	    out << indent; | 
| Chris@45 | 921 	    out << QString("  <derivation source=\"%1\" model=\"%2\" channel=\"%3\" domain=\"%4\" stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" transform=\"%9\"") | 
| Chris@45 | 922 		.arg(XmlExportable::getObjectExportId(rec.source)) | 
| Chris@45 | 923 		.arg(XmlExportable::getObjectExportId(i->first)) | 
| Chris@45 | 924                 .arg(rec.context.channel) | 
| Chris@45 | 925                 .arg(rec.context.domain) | 
| Chris@45 | 926                 .arg(rec.context.stepSize) | 
| Chris@45 | 927                 .arg(rec.context.blockSize) | 
| Chris@45 | 928                 .arg(extentsAttributes) | 
| Chris@45 | 929                 .arg(int(rec.context.windowType)) | 
| Chris@45 | 930 		.arg(XmlExportable::encodeEntities(rec.transform)); | 
| Chris@45 | 931 | 
| Chris@45 | 932             if (rec.configurationXml != "") { | 
| Chris@45 | 933                 out << ">\n    " + indent + rec.configurationXml | 
| Chris@45 | 934                     + "\n" + indent + "  </derivation>\n"; | 
| Chris@45 | 935             } else { | 
| Chris@45 | 936                 out << "/>\n"; | 
| Chris@45 | 937             } | 
| Chris@45 | 938 	} | 
| Chris@45 | 939 | 
| Chris@45 | 940         //!!! We should probably own the PlayParameterRepository | 
| Chris@45 | 941         PlayParameters *playParameters = | 
| Chris@45 | 942             PlayParameterRepository::getInstance()->getPlayParameters(i->first); | 
| Chris@45 | 943         if (playParameters) { | 
| Chris@45 | 944             playParameters->toXml | 
| Chris@45 | 945                 (out, indent + "  ", | 
| Chris@45 | 946                  QString("model=\"%1\"") | 
| Chris@45 | 947                  .arg(XmlExportable::getObjectExportId(i->first))); | 
| Chris@45 | 948         } | 
| Chris@45 | 949     } | 
| Chris@45 | 950 | 
| Chris@45 | 951     for (LayerSet::const_iterator i = m_layers.begin(); | 
| Chris@45 | 952 	 i != m_layers.end(); ++i) { | 
| Chris@45 | 953 | 
| Chris@45 | 954 	(*i)->toXml(out, indent + "  "); | 
| Chris@45 | 955     } | 
| Chris@45 | 956 | 
| Chris@45 | 957     out << indent + "</data>\n"; | 
| Chris@45 | 958 } | 
| Chris@45 | 959 | 
| Chris@45 | 960 |