| 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@420 | 18 #include "Align.h" | 
| Chris@420 | 19 | 
| Chris@45 | 20 #include "data/model/WaveFileModel.h" | 
| Chris@45 | 21 #include "data/model/WritableWaveFileModel.h" | 
| Chris@45 | 22 #include "data/model/DenseThreeDimensionalModel.h" | 
| Chris@45 | 23 #include "data/model/DenseTimeValueModel.h" | 
| gyorgyf@270 | 24 #include "data/model/FlexiNoteModel.h" | 
| Chris@588 | 25 #include "data/model/AggregateWaveModel.h" | 
| gyorgyf@270 | 26 | 
| Chris@45 | 27 #include "layer/Layer.h" | 
| Chris@105 | 28 #include "widgets/CommandHistory.h" | 
| Chris@45 | 29 #include "base/Command.h" | 
| Chris@45 | 30 #include "view/View.h" | 
| Chris@45 | 31 #include "base/PlayParameterRepository.h" | 
| Chris@45 | 32 #include "base/PlayParameters.h" | 
| Chris@106 | 33 #include "transform/TransformFactory.h" | 
| Chris@106 | 34 #include "transform/ModelTransformerFactory.h" | 
| gyorgyf@270 | 35 #include "transform/FeatureExtractionModelTransformer.h" | 
| Chris@45 | 36 #include <QApplication> | 
| Chris@45 | 37 #include <QTextStream> | 
| Chris@90 | 38 #include <QSettings> | 
| Chris@45 | 39 #include <iostream> | 
| Chris@212 | 40 #include <typeinfo> | 
| Chris@45 | 41 | 
| Chris@45 | 42 #include "data/model/AlignmentModel.h" | 
| Chris@423 | 43 #include "Align.h" | 
| Chris@45 | 44 | 
| Chris@297 | 45 using std::vector; | 
| Chris@297 | 46 | 
| Chris@138 | 47 //#define DEBUG_DOCUMENT 1 | 
| Chris@77 | 48 | 
| Chris@45 | 49 //!!! still need to handle command history, documentRestored/documentModified | 
| Chris@45 | 50 | 
| Chris@45 | 51 Document::Document() : | 
| Chris@47 | 52     m_mainModel(0), | 
| Chris@423 | 53     m_autoAlignment(false), | 
| Chris@601 | 54     m_align(new Align()), | 
| Chris@601 | 55     m_isIncomplete(false) | 
| Chris@45 | 56 { | 
| Chris@456 | 57     connect(this, | 
| Chris@456 | 58             SIGNAL(modelAboutToBeDeleted(Model *)), | 
| Chris@54 | 59             ModelTransformerFactory::getInstance(), | 
| Chris@45 | 60             SLOT(modelAboutToBeDeleted(Model *))); | 
| Chris@456 | 61 | 
| Chris@456 | 62     connect(ModelTransformerFactory::getInstance(), | 
| Chris@456 | 63             SIGNAL(transformFailed(QString, QString)), | 
| Chris@456 | 64             this, | 
| Chris@456 | 65             SIGNAL(modelGenerationFailed(QString, QString))); | 
| Chris@459 | 66 | 
| Chris@428 | 67     connect(m_align, SIGNAL(alignmentComplete(AlignmentModel *)), | 
| Chris@428 | 68             this, SIGNAL(alignmentComplete(AlignmentModel *))); | 
| Chris@45 | 69 } | 
| Chris@45 | 70 | 
| Chris@45 | 71 Document::~Document() | 
| Chris@45 | 72 { | 
| Chris@45 | 73     //!!! Document should really own the command history.  atm we | 
| Chris@45 | 74     //still refer to it in various places that don't have access to | 
| Chris@45 | 75     //the document, be nice to fix that | 
| Chris@45 | 76 | 
| Chris@77 | 77 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 78     cerr << "\n\nDocument::~Document: about to clear command history" << endl; | 
| Chris@77 | 79 #endif | 
| Chris@45 | 80     CommandHistory::getInstance()->clear(); | 
| Chris@45 | 81 | 
| Chris@77 | 82 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 83     SVDEBUG << "Document::~Document: about to delete layers" << endl; | 
| Chris@77 | 84 #endif | 
| Chris@45 | 85     while (!m_layers.empty()) { | 
| Chris@595 | 86         deleteLayer(*m_layers.begin(), true); | 
| Chris@45 | 87     } | 
| Chris@45 | 88 | 
| Chris@45 | 89     if (!m_models.empty()) { | 
| Chris@595 | 90         SVDEBUG << "Document::~Document: WARNING: " | 
| Chris@595 | 91                   << m_models.size() << " model(s) still remain -- " | 
| Chris@595 | 92                   << "should have been garbage collected when deleting layers" | 
| Chris@595 | 93                   << endl; | 
| Chris@595 | 94         while (!m_models.empty()) { | 
| Chris@45 | 95             Model *model = m_models.begin()->first; | 
| Chris@595 | 96             if (model == m_mainModel) { | 
| Chris@595 | 97                 // just in case! | 
| Chris@595 | 98                 SVDEBUG << "Document::~Document: WARNING: Main model is also" | 
| Chris@595 | 99                           << " in models list!" << endl; | 
| Chris@595 | 100             } else if (model) { | 
| Chris@79 | 101                 model->aboutToDelete(); | 
| Chris@595 | 102                 emit modelAboutToBeDeleted(model); | 
| Chris@595 | 103                 delete model; | 
| Chris@595 | 104             } | 
| Chris@595 | 105             m_models.erase(m_models.begin()); | 
| Chris@595 | 106         } | 
| Chris@45 | 107     } | 
| Chris@45 | 108 | 
| Chris@77 | 109 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 110     SVDEBUG << "Document::~Document: About to get rid of main model" | 
| Chris@595 | 111               << endl; | 
| Chris@77 | 112 #endif | 
| Chris@45 | 113     if (m_mainModel) { | 
| Chris@79 | 114         m_mainModel->aboutToDelete(); | 
| Chris@45 | 115         emit modelAboutToBeDeleted(m_mainModel); | 
| Chris@45 | 116     } | 
| Chris@45 | 117 | 
| Chris@45 | 118     emit mainModelChanged(0); | 
| Chris@45 | 119     delete m_mainModel; | 
| Chris@45 | 120 } | 
| Chris@45 | 121 | 
| Chris@45 | 122 Layer * | 
| Chris@45 | 123 Document::createLayer(LayerFactory::LayerType type) | 
| Chris@45 | 124 { | 
| Chris@45 | 125     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 126     if (!newLayer) return 0; | 
| Chris@45 | 127 | 
| Chris@45 | 128     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 129 | 
| Chris@45 | 130     m_layers.insert(newLayer); | 
| Chris@52 | 131 | 
| Chris@77 | 132 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 133     SVDEBUG << "Document::createLayer: Added layer of type " << type | 
| Chris@229 | 134               << ", now have " << m_layers.size() << " layers" << endl; | 
| Chris@77 | 135 #endif | 
| Chris@52 | 136 | 
| Chris@45 | 137     emit layerAdded(newLayer); | 
| Chris@45 | 138 | 
| Chris@45 | 139     return newLayer; | 
| Chris@45 | 140 } | 
| Chris@45 | 141 | 
| Chris@45 | 142 Layer * | 
| Chris@45 | 143 Document::createMainModelLayer(LayerFactory::LayerType type) | 
| Chris@45 | 144 { | 
| Chris@45 | 145     Layer *newLayer = createLayer(type); | 
| Chris@45 | 146     if (!newLayer) return 0; | 
| Chris@45 | 147     setModel(newLayer, m_mainModel); | 
| Chris@45 | 148     return newLayer; | 
| Chris@45 | 149 } | 
| Chris@45 | 150 | 
| Chris@45 | 151 Layer * | 
| Chris@45 | 152 Document::createImportedLayer(Model *model) | 
| Chris@45 | 153 { | 
| Chris@45 | 154     LayerFactory::LayerTypeSet types = | 
| Chris@595 | 155         LayerFactory::getInstance()->getValidLayerTypes(model); | 
| Chris@45 | 156 | 
| Chris@45 | 157     if (types.empty()) { | 
| Chris@595 | 158         cerr << "WARNING: Document::importLayer: no valid display layer for model" << endl; | 
| Chris@595 | 159         return 0; | 
| Chris@45 | 160     } | 
| Chris@45 | 161 | 
| Chris@45 | 162     //!!! for now, just use the first suitable layer type | 
| Chris@45 | 163     LayerFactory::LayerType type = *types.begin(); | 
| Chris@45 | 164 | 
| Chris@45 | 165     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 166     if (!newLayer) return 0; | 
| Chris@45 | 167 | 
| Chris@45 | 168     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 169 | 
| Chris@45 | 170     addImportedModel(model); | 
| Chris@45 | 171     setModel(newLayer, model); | 
| Chris@45 | 172 | 
| Chris@45 | 173     //!!! and all channels | 
| Chris@45 | 174     setChannel(newLayer, -1); | 
| Chris@45 | 175 | 
| Chris@45 | 176     m_layers.insert(newLayer); | 
| Chris@52 | 177 | 
| Chris@77 | 178 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 179     SVDEBUG << "Document::createImportedLayer: Added layer of type " << type | 
| Chris@229 | 180               << ", now have " << m_layers.size() << " layers" << endl; | 
| Chris@77 | 181 #endif | 
| Chris@52 | 182 | 
| Chris@45 | 183     emit layerAdded(newLayer); | 
| Chris@45 | 184     return newLayer; | 
| Chris@45 | 185 } | 
| Chris@45 | 186 | 
| Chris@45 | 187 Layer * | 
| Chris@45 | 188 Document::createEmptyLayer(LayerFactory::LayerType type) | 
| Chris@45 | 189 { | 
| Chris@61 | 190     if (!m_mainModel) return 0; | 
| Chris@61 | 191 | 
| Chris@45 | 192     Model *newModel = | 
| Chris@595 | 193         LayerFactory::getInstance()->createEmptyModel(type, m_mainModel); | 
| Chris@45 | 194     if (!newModel) return 0; | 
| Chris@45 | 195 | 
| Chris@45 | 196     Layer *newLayer = createLayer(type); | 
| Chris@45 | 197     if (!newLayer) { | 
| Chris@595 | 198         delete newModel; | 
| Chris@595 | 199         return 0; | 
| Chris@45 | 200     } | 
| Chris@45 | 201 | 
| Chris@45 | 202     addImportedModel(newModel); | 
| Chris@45 | 203     setModel(newLayer, newModel); | 
| Chris@45 | 204 | 
| Chris@45 | 205     return newLayer; | 
| Chris@45 | 206 } | 
| Chris@45 | 207 | 
| Chris@45 | 208 Layer * | 
| Chris@45 | 209 Document::createDerivedLayer(LayerFactory::LayerType type, | 
| Chris@595 | 210                              TransformId transform) | 
| Chris@45 | 211 { | 
| Chris@45 | 212     Layer *newLayer = createLayer(type); | 
| Chris@45 | 213     if (!newLayer) return 0; | 
| Chris@45 | 214 | 
| Chris@45 | 215     newLayer->setObjectName(getUniqueLayerName | 
| Chris@54 | 216                             (TransformFactory::getInstance()-> | 
| Chris@54 | 217                              getTransformFriendlyName(transform))); | 
| Chris@45 | 218 | 
| Chris@45 | 219     return newLayer; | 
| Chris@45 | 220 } | 
| Chris@297 | 221 | 
| Chris@45 | 222 Layer * | 
| Chris@72 | 223 Document::createDerivedLayer(const Transform &transform, | 
| Chris@72 | 224                              const ModelTransformer::Input &input) | 
| Chris@45 | 225 { | 
| Chris@297 | 226     Transforms transforms; | 
| Chris@297 | 227     transforms.push_back(transform); | 
| Chris@297 | 228     vector<Layer *> layers = createDerivedLayers(transforms, input); | 
| Chris@297 | 229     if (layers.empty()) return 0; | 
| Chris@297 | 230     else return layers[0]; | 
| Chris@297 | 231 } | 
| Chris@297 | 232 | 
| Chris@297 | 233 vector<Layer *> | 
| Chris@297 | 234 Document::createDerivedLayers(const Transforms &transforms, | 
| Chris@297 | 235                               const ModelTransformer::Input &input) | 
| Chris@297 | 236 { | 
| Chris@78 | 237     QString message; | 
| Chris@329 | 238     vector<Model *> newModels = addDerivedModels(transforms, input, message, 0); | 
| Chris@297 | 239 | 
| Chris@297 | 240     if (newModels.empty()) { | 
| Chris@297 | 241         //!!! This identifier may be wrong! | 
| Chris@297 | 242         emit modelGenerationFailed(transforms[0].getIdentifier(), message); | 
| Chris@297 | 243         return vector<Layer *>(); | 
| Chris@78 | 244     } else if (message != "") { | 
| Chris@297 | 245         //!!! This identifier may be wrong! | 
| Chris@297 | 246         emit modelGenerationWarning(transforms[0].getIdentifier(), message); | 
| Chris@45 | 247     } | 
| Chris@45 | 248 | 
| Chris@329 | 249     QStringList names; | 
| Chris@366 | 250     for (int i = 0; i < (int)newModels.size(); ++i) { | 
| Chris@329 | 251         names.push_back(getUniqueLayerName | 
| Chris@329 | 252                         (TransformFactory::getInstance()-> | 
| Chris@329 | 253                          getTransformFriendlyName | 
| Chris@329 | 254                          (transforms[i].getIdentifier()))); | 
| Chris@329 | 255     } | 
| Chris@329 | 256 | 
| Chris@329 | 257     vector<Layer *> layers = createLayersForDerivedModels(newModels, names); | 
| Chris@329 | 258     return layers; | 
| Chris@329 | 259 } | 
| Chris@329 | 260 | 
| Chris@329 | 261 class AdditionalModelConverter : | 
| Chris@329 | 262     public ModelTransformerFactory::AdditionalModelHandler | 
| Chris@329 | 263 { | 
| Chris@329 | 264 public: | 
| Chris@329 | 265     AdditionalModelConverter(Document *doc, | 
| Chris@329 | 266                              Document::LayerCreationHandler *handler) : | 
| Chris@329 | 267         m_doc(doc), | 
| Chris@329 | 268         m_handler(handler) { | 
| Chris@329 | 269     } | 
| Chris@329 | 270 | 
| Chris@329 | 271     virtual ~AdditionalModelConverter() { } | 
| Chris@329 | 272 | 
| Chris@329 | 273     void | 
| Chris@329 | 274     setPrimaryLayers(vector<Layer *> layers) { | 
| Chris@329 | 275         m_primary = layers; | 
| Chris@329 | 276     } | 
| Chris@329 | 277 | 
| Chris@329 | 278     void | 
| Chris@329 | 279     moreModelsAvailable(vector<Model *> models) { | 
| Chris@329 | 280         std::cerr << "AdditionalModelConverter::moreModelsAvailable: " << models.size() << " model(s)" << std::endl; | 
| Chris@329 | 281         // We can't automatically regenerate the additional models on | 
| Chris@329 | 282         // reload -- we should delete them instead | 
| Chris@329 | 283         QStringList names; | 
| Chris@329 | 284         foreach (Model *model, models) { | 
| Chris@329 | 285             m_doc->addAdditionalModel(model); | 
| Chris@329 | 286             names.push_back(QString()); | 
| Chris@329 | 287         } | 
| Chris@329 | 288         vector<Layer *> layers = m_doc->createLayersForDerivedModels | 
| Chris@329 | 289             (models, names); | 
| Chris@363 | 290         m_handler->layersCreated(this, m_primary, layers); | 
| Chris@329 | 291         delete this; | 
| Chris@329 | 292     } | 
| Chris@329 | 293 | 
| Chris@329 | 294     void | 
| Chris@329 | 295     noMoreModelsAvailable() { | 
| Chris@329 | 296         std::cerr << "AdditionalModelConverter::noMoreModelsAvailable" << std::endl; | 
| Chris@363 | 297         m_handler->layersCreated(this, m_primary, vector<Layer *>()); | 
| Chris@329 | 298         delete this; | 
| Chris@329 | 299     } | 
| Chris@329 | 300 | 
| Chris@363 | 301     void cancel() { | 
| Chris@363 | 302         foreach (Layer *layer, m_primary) { | 
| Chris@363 | 303             Model *model = layer->getModel(); | 
| Chris@363 | 304             if (model) { | 
| Chris@363 | 305                 model->abandon(); | 
| Chris@363 | 306             } | 
| Chris@363 | 307         } | 
| Chris@363 | 308     } | 
| Chris@363 | 309 | 
| Chris@329 | 310 private: | 
| Chris@329 | 311     Document *m_doc; | 
| Chris@329 | 312     vector<Layer *> m_primary; | 
| Chris@329 | 313     Document::LayerCreationHandler *m_handler; //!!! how to handle destruction of this? | 
| Chris@329 | 314 }; | 
| Chris@329 | 315 | 
| Chris@363 | 316 Document::LayerCreationAsyncHandle | 
| Chris@329 | 317 Document::createDerivedLayersAsync(const Transforms &transforms, | 
| Chris@329 | 318                                    const ModelTransformer::Input &input, | 
| Chris@329 | 319                                    LayerCreationHandler *handler) | 
| Chris@329 | 320 { | 
| Chris@329 | 321     QString message; | 
| Chris@329 | 322 | 
| Chris@329 | 323     AdditionalModelConverter *amc = new AdditionalModelConverter(this, handler); | 
| Chris@329 | 324 | 
| Chris@329 | 325     vector<Model *> newModels = addDerivedModels | 
| Chris@329 | 326         (transforms, input, message, amc); | 
| Chris@329 | 327 | 
| Chris@329 | 328     QStringList names; | 
| Chris@366 | 329     for (int i = 0; i < (int)newModels.size(); ++i) { | 
| Chris@329 | 330         names.push_back(getUniqueLayerName | 
| Chris@329 | 331                         (TransformFactory::getInstance()-> | 
| Chris@329 | 332                          getTransformFriendlyName | 
| Chris@329 | 333                          (transforms[i].getIdentifier()))); | 
| Chris@329 | 334     } | 
| Chris@329 | 335 | 
| Chris@329 | 336     vector<Layer *> layers = createLayersForDerivedModels(newModels, names); | 
| Chris@329 | 337     amc->setPrimaryLayers(layers); | 
| Chris@329 | 338 | 
| Chris@329 | 339     if (newModels.empty()) { | 
| Chris@329 | 340         //!!! This identifier may be wrong! | 
| Chris@329 | 341         emit modelGenerationFailed(transforms[0].getIdentifier(), message); | 
| Chris@363 | 342         //!!! what to do with amc? | 
| Chris@329 | 343     } else if (message != "") { | 
| Chris@329 | 344         //!!! This identifier may be wrong! | 
| Chris@329 | 345         emit modelGenerationWarning(transforms[0].getIdentifier(), message); | 
| Chris@363 | 346         //!!! what to do with amc? | 
| Chris@329 | 347     } | 
| Chris@363 | 348 | 
| Chris@363 | 349     return amc; | 
| Chris@363 | 350 } | 
| Chris@363 | 351 | 
| Chris@363 | 352 void | 
| Chris@363 | 353 Document::cancelAsyncLayerCreation(Document::LayerCreationAsyncHandle h) | 
| Chris@363 | 354 { | 
| Chris@363 | 355     AdditionalModelConverter *conv = static_cast<AdditionalModelConverter *>(h); | 
| Chris@363 | 356     conv->cancel(); | 
| Chris@329 | 357 } | 
| Chris@329 | 358 | 
| Chris@329 | 359 vector<Layer *> | 
| Chris@329 | 360 Document::createLayersForDerivedModels(vector<Model *> newModels, | 
| Chris@329 | 361                                        QStringList names) | 
| Chris@329 | 362 { | 
| Chris@297 | 363     vector<Layer *> layers; | 
| Chris@329 | 364 | 
| Chris@297 | 365     for (int i = 0; i < (int)newModels.size(); ++i) { | 
| Chris@297 | 366 | 
| Chris@297 | 367         Model *newModel = newModels[i]; | 
| Chris@297 | 368 | 
| Chris@297 | 369         LayerFactory::LayerTypeSet types = | 
| Chris@297 | 370             LayerFactory::getInstance()->getValidLayerTypes(newModel); | 
| Chris@297 | 371 | 
| Chris@297 | 372         if (types.empty()) { | 
| Chris@329 | 373             cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << names[i] << endl; | 
| Chris@297 | 374             //!!! inadequate cleanup: | 
| Chris@297 | 375             newModel->aboutToDelete(); | 
| Chris@297 | 376             emit modelAboutToBeDeleted(newModel); | 
| Chris@297 | 377             m_models.erase(newModel); | 
| Chris@297 | 378             delete newModel; | 
| Chris@297 | 379             return vector<Layer *>(); | 
| Chris@297 | 380         } | 
| Chris@297 | 381 | 
| Chris@297 | 382         //!!! for now, just use the first suitable layer type | 
| Chris@297 | 383 | 
| Chris@297 | 384         Layer *newLayer = createLayer(*types.begin()); | 
| Chris@297 | 385         setModel(newLayer, newModel); | 
| Chris@297 | 386 | 
| Chris@297 | 387         //!!! We need to clone the model when adding the layer, so that it | 
| Chris@297 | 388         //can be edited without affecting other layers that are based on | 
| Chris@297 | 389         //the same model.  Unfortunately we can't just clone it now, | 
| Chris@297 | 390         //because it probably hasn't been completed yet -- the transform | 
| Chris@297 | 391         //runs in the background.  Maybe the transform has to handle | 
| Chris@297 | 392         //cloning and cacheing models itself. | 
| Chris@297 | 393         // | 
| Chris@297 | 394         // Once we do clone models here, of course, we'll have to avoid | 
| Chris@297 | 395         // leaking them too. | 
| Chris@297 | 396         // | 
| Chris@297 | 397         // We want the user to be able to add a model to a second layer | 
| Chris@297 | 398         // _while it's still being calculated in the first_ and have it | 
| Chris@297 | 399         // work quickly.  That means we need to put the same physical | 
| Chris@297 | 400         // model pointer in both layers, so they can't actually be cloned. | 
| Chris@297 | 401 | 
| Chris@297 | 402         if (newLayer) { | 
| Chris@329 | 403             newLayer->setObjectName(names[i]); | 
| Chris@297 | 404         } | 
| Chris@297 | 405 | 
| Chris@297 | 406         emit layerAdded(newLayer); | 
| Chris@297 | 407         layers.push_back(newLayer); | 
| Chris@45 | 408     } | 
| Chris@45 | 409 | 
| Chris@297 | 410     return layers; | 
| Chris@45 | 411 } | 
| Chris@45 | 412 | 
| Chris@45 | 413 void | 
| Chris@45 | 414 Document::setMainModel(WaveFileModel *model) | 
| Chris@45 | 415 { | 
| Chris@45 | 416     Model *oldMainModel = m_mainModel; | 
| Chris@45 | 417     m_mainModel = model; | 
| Chris@160 | 418 | 
| Chris@45 | 419     emit modelAdded(m_mainModel); | 
| Chris@160 | 420     if (model) { | 
| Chris@160 | 421         emit activity(tr("Set main model to %1").arg(model->objectName())); | 
| Chris@160 | 422     } else { | 
| Chris@160 | 423         emit activity(tr("Clear main model")); | 
| Chris@160 | 424     } | 
| Chris@45 | 425 | 
| Chris@45 | 426     std::vector<Layer *> obsoleteLayers; | 
| Chris@53 | 427     std::set<QString> failedTransformers; | 
| Chris@45 | 428 | 
| Chris@45 | 429     // We need to ensure that no layer is left using oldMainModel or | 
| Chris@45 | 430     // any of the old derived models as its model.  Either replace the | 
| Chris@45 | 431     // model, or delete the layer for each layer that is currently | 
| Chris@45 | 432     // using one of these.  Carry out this replacement before we | 
| Chris@45 | 433     // delete any of the models. | 
| Chris@45 | 434 | 
| Chris@77 | 435 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 436     cerr << "Document::setMainModel: Have " | 
| Chris@293 | 437               << m_layers.size() << " layers" << endl; | 
| Chris@293 | 438     cerr << "Models now: "; | 
| Chris@137 | 439     for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@293 | 440         cerr << i->first << " "; | 
| Chris@137 | 441     } | 
| Chris@293 | 442     cerr << endl; | 
| Chris@293 | 443     cerr << "Old main model: " << oldMainModel << endl; | 
| Chris@77 | 444 #endif | 
| Chris@52 | 445 | 
| Chris@45 | 446     for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 447 | 
| Chris@595 | 448         Layer *layer = *i; | 
| Chris@595 | 449         Model *model = layer->getModel(); | 
| Chris@45 | 450 | 
| Chris@77 | 451 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 452         cerr << "Document::setMainModel: inspecting model " | 
| Chris@229 | 453                   << (model ? model->objectName(): "(null)") << " in layer " | 
| Chris@293 | 454                   << layer->objectName() << endl; | 
| Chris@77 | 455 #endif | 
| Chris@45 | 456 | 
| Chris@595 | 457         if (model == oldMainModel) { | 
| Chris@77 | 458 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 459             cerr << "... it uses the old main model, replacing" << endl; | 
| Chris@77 | 460 #endif | 
| Chris@595 | 461             LayerFactory::getInstance()->setModel(layer, m_mainModel); | 
| Chris@595 | 462             continue; | 
| Chris@595 | 463         } | 
| Chris@45 | 464 | 
| Chris@137 | 465         if (!model) { | 
| Chris@293 | 466             cerr << "WARNING: Document::setMainModel: Null model in layer " | 
| Chris@293 | 467                       << layer << endl; | 
| Chris@595 | 468             // get rid of this hideous degenerate | 
| Chris@595 | 469             obsoleteLayers.push_back(layer); | 
| Chris@595 | 470             continue; | 
| Chris@595 | 471         } | 
| Chris@137 | 472 | 
| Chris@595 | 473         if (m_models.find(model) == m_models.end()) { | 
| Chris@595 | 474             cerr << "WARNING: Document::setMainModel: Unknown model " | 
| Chris@595 | 475                       << model << " in layer " << layer << endl; | 
| Chris@595 | 476             // and this one | 
| Chris@595 | 477             obsoleteLayers.push_back(layer); | 
| Chris@595 | 478             continue; | 
| Chris@595 | 479         } | 
| Chris@595 | 480 | 
| Chris@595 | 481         if (m_models[model].source && | 
| Chris@70 | 482             (m_models[model].source == oldMainModel)) { | 
| Chris@45 | 483 | 
| Chris@77 | 484 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 485             cerr << "... it uses a model derived from the old main model, regenerating" << endl; | 
| Chris@77 | 486 #endif | 
| Chris@45 | 487 | 
| Chris@595 | 488             // This model was derived from the previous main | 
| Chris@595 | 489             // model: regenerate it. | 
| Chris@595 | 490 | 
| Chris@595 | 491             const Transform &transform = m_models[model].transform; | 
| Chris@72 | 492             QString transformId = transform.getIdentifier(); | 
| Chris@595 | 493 | 
| Chris@72 | 494             //!!! We have a problem here if the number of channels in | 
| Chris@72 | 495             //the main model has changed. | 
| Chris@72 | 496 | 
| Chris@78 | 497             QString message; | 
| Chris@595 | 498             Model *replacementModel = | 
| Chris@45 | 499                 addDerivedModel(transform, | 
| Chris@72 | 500                                 ModelTransformer::Input | 
| Chris@78 | 501                                 (m_mainModel, m_models[model].channel), | 
| Chris@78 | 502                                 message); | 
| Chris@595 | 503 | 
| Chris@595 | 504             if (!replacementModel) { | 
| Chris@595 | 505                 cerr << "WARNING: Document::setMainModel: Failed to regenerate model for transform \"" | 
| Chris@595 | 506                           << transformId << "\"" << " in layer " << layer << endl; | 
| Chris@72 | 507                 if (failedTransformers.find(transformId) | 
| Chris@72 | 508                     == failedTransformers.end()) { | 
| Chris@45 | 509                     emit modelRegenerationFailed(layer->objectName(), | 
| Chris@78 | 510                                                  transformId, | 
| Chris@78 | 511                                                  message); | 
| Chris@72 | 512                     failedTransformers.insert(transformId); | 
| Chris@45 | 513                 } | 
| Chris@595 | 514                 obsoleteLayers.push_back(layer); | 
| Chris@595 | 515             } else { | 
| Chris@78 | 516                 if (message != "") { | 
| Chris@78 | 517                     emit modelRegenerationWarning(layer->objectName(), | 
| Chris@78 | 518                                                   transformId, | 
| Chris@78 | 519                                                   message); | 
| Chris@78 | 520                 } | 
| Chris@77 | 521 #ifdef DEBUG_DOCUMENT | 
| Chris@293 | 522                 cerr << "Replacing model " << model << " (type " | 
| Chris@77 | 523                           << typeid(*model).name() << ") with model " | 
| Chris@77 | 524                           << replacementModel << " (type " | 
| Chris@77 | 525                           << typeid(*replacementModel).name() << ") in layer " | 
| Chris@228 | 526                           << layer << " (name " << layer->objectName() << ")" | 
| Chris@293 | 527                           << endl; | 
| Chris@366 | 528 | 
| Chris@45 | 529                 RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 530                     dynamic_cast<RangeSummarisableTimeValueModel *>(replacementModel); | 
| Chris@45 | 531                 if (rm) { | 
| Chris@293 | 532                     cerr << "new model has " << rm->getChannelCount() << " channels " << endl; | 
| Chris@45 | 533                 } else { | 
| Chris@293 | 534                     cerr << "new model " << replacementModel << " is not a RangeSummarisableTimeValueModel!" << endl; | 
| Chris@45 | 535                 } | 
| Chris@77 | 536 #endif | 
| Chris@595 | 537                 setModel(layer, replacementModel); | 
| Chris@595 | 538             } | 
| Chris@595 | 539         } | 
| Chris@45 | 540     } | 
| Chris@45 | 541 | 
| Chris@45 | 542     for (size_t k = 0; k < obsoleteLayers.size(); ++k) { | 
| Chris@595 | 543         deleteLayer(obsoleteLayers[k], true); | 
| Chris@45 | 544     } | 
| Chris@45 | 545 | 
| Chris@48 | 546     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@329 | 547         if (i->second.additional) { | 
| Chris@329 | 548             Model *m = i->first; | 
| Chris@588 | 549             m->aboutToDelete(); | 
| Chris@329 | 550             emit modelAboutToBeDeleted(m); | 
| Chris@329 | 551             delete m; | 
| Chris@329 | 552         } | 
| Chris@329 | 553     } | 
| Chris@329 | 554 | 
| Chris@329 | 555     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@86 | 556 | 
| Chris@137 | 557         Model *m = i->first; | 
| Chris@137 | 558 | 
| Chris@137 | 559 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 560         SVDEBUG << "considering alignment for model " << m << " (name \"" | 
| Chris@229 | 561                   << m->objectName() << "\")" << endl; | 
| Chris@137 | 562 #endif | 
| Chris@137 | 563 | 
| Chris@86 | 564         if (m_autoAlignment) { | 
| Chris@86 | 565 | 
| Chris@137 | 566             alignModel(m); | 
| Chris@86 | 567 | 
| Chris@86 | 568         } else if (oldMainModel && | 
| Chris@137 | 569                    (m->getAlignmentReference() == oldMainModel)) { | 
| Chris@86 | 570 | 
| Chris@137 | 571             alignModel(m); | 
| Chris@48 | 572         } | 
| Chris@48 | 573     } | 
| Chris@48 | 574 | 
| Chris@77 | 575     if (oldMainModel) { | 
| Chris@79 | 576         oldMainModel->aboutToDelete(); | 
| Chris@77 | 577         emit modelAboutToBeDeleted(oldMainModel); | 
| Chris@77 | 578     } | 
| Chris@77 | 579 | 
| Chris@86 | 580     if (m_autoAlignment) { | 
| Chris@387 | 581         SVDEBUG << "Document::setMainModel: auto-alignment is on, aligning model if possible" << endl; | 
| Chris@86 | 582         alignModel(m_mainModel); | 
| Chris@86 | 583     } | 
| Chris@86 | 584 | 
| Chris@45 | 585     emit mainModelChanged(m_mainModel); | 
| Chris@45 | 586 | 
| Chris@45 | 587     delete oldMainModel; | 
| Chris@45 | 588 } | 
| Chris@45 | 589 | 
| Chris@45 | 590 void | 
| Chris@329 | 591 Document::addAlreadyDerivedModel(const Transform &transform, | 
| Chris@329 | 592                                  const ModelTransformer::Input &input, | 
| Chris@329 | 593                                  Model *outputModelToAdd) | 
| Chris@45 | 594 { | 
| Chris@45 | 595     if (m_models.find(outputModelToAdd) != m_models.end()) { | 
| Chris@595 | 596         cerr << "WARNING: Document::addAlreadyDerivedModel: Model already added" | 
| Chris@595 | 597                   << endl; | 
| Chris@595 | 598         return; | 
| Chris@45 | 599     } | 
| Chris@45 | 600 | 
| Chris@77 | 601 #ifdef DEBUG_DOCUMENT | 
| Chris@248 | 602     if (input.getModel()) { | 
| Chris@329 | 603         cerr << "Document::addAlreadyDerivedModel: source is " << input.getModel() << " \"" << input.getModel()->objectName() << "\"" << endl; | 
| Chris@248 | 604     } else { | 
| Chris@329 | 605         cerr << "Document::addAlreadyDerivedModel: source is " << input.getModel() << endl; | 
| Chris@248 | 606     } | 
| Chris@77 | 607 #endif | 
| Chris@45 | 608 | 
| Chris@45 | 609     ModelRecord rec; | 
| Chris@72 | 610     rec.source = input.getModel(); | 
| Chris@72 | 611     rec.channel = input.getChannel(); | 
| Chris@45 | 612     rec.transform = transform; | 
| Chris@329 | 613     rec.additional = false; | 
| Chris@45 | 614     rec.refcount = 0; | 
| Chris@45 | 615 | 
| Chris@72 | 616     outputModelToAdd->setSourceModel(input.getModel()); | 
| Chris@45 | 617 | 
| Chris@45 | 618     m_models[outputModelToAdd] = rec; | 
| Chris@45 | 619 | 
| Chris@137 | 620 #ifdef DEBUG_DOCUMENT | 
| Chris@329 | 621     cerr << "Document::addAlreadyDerivedModel: Added model " << outputModelToAdd << endl; | 
| Chris@293 | 622     cerr << "Models now: "; | 
| Chris@137 | 623     for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@293 | 624         cerr << i->first << " "; | 
| Chris@137 | 625     } | 
| Chris@293 | 626     cerr << endl; | 
| Chris@137 | 627 #endif | 
| Chris@137 | 628 | 
| Chris@45 | 629     emit modelAdded(outputModelToAdd); | 
| Chris@45 | 630 } | 
| Chris@45 | 631 | 
| Chris@45 | 632 | 
| Chris@45 | 633 void | 
| Chris@45 | 634 Document::addImportedModel(Model *model) | 
| Chris@45 | 635 { | 
| Chris@45 | 636     if (m_models.find(model) != m_models.end()) { | 
| Chris@595 | 637         cerr << "WARNING: Document::addImportedModel: Model already added" | 
| Chris@595 | 638                   << endl; | 
| Chris@595 | 639         return; | 
| Chris@45 | 640     } | 
| Chris@45 | 641 | 
| Chris@45 | 642     ModelRecord rec; | 
| Chris@45 | 643     rec.source = 0; | 
| Chris@408 | 644     rec.channel = 0; | 
| Chris@45 | 645     rec.refcount = 0; | 
| Chris@329 | 646     rec.additional = false; | 
| Chris@45 | 647 | 
| Chris@45 | 648     m_models[model] = rec; | 
| Chris@45 | 649 | 
| Chris@137 | 650 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 651     SVDEBUG << "Document::addImportedModel: Added model " << model << endl; | 
| Chris@293 | 652     cerr << "Models now: "; | 
| Chris@137 | 653     for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@293 | 654         cerr << i->first << " "; | 
| Chris@137 | 655     } | 
| Chris@293 | 656     cerr << endl; | 
| Chris@137 | 657 #endif | 
| Chris@137 | 658 | 
| Chris@387 | 659     if (m_autoAlignment) { | 
| Chris@387 | 660         SVDEBUG << "Document::addImportedModel: auto-alignment is on, aligning model if possible" << endl; | 
| Chris@387 | 661         alignModel(model); | 
| Chris@387 | 662     } else { | 
| Chris@387 | 663         SVDEBUG << "Document(" << this << "): addImportedModel: auto-alignment is off" << endl; | 
| Chris@387 | 664     } | 
| Chris@47 | 665 | 
| Chris@45 | 666     emit modelAdded(model); | 
| Chris@45 | 667 } | 
| Chris@45 | 668 | 
| Chris@329 | 669 void | 
| Chris@329 | 670 Document::addAdditionalModel(Model *model) | 
| Chris@329 | 671 { | 
| Chris@329 | 672     if (m_models.find(model) != m_models.end()) { | 
| Chris@595 | 673         cerr << "WARNING: Document::addAdditionalModel: Model already added" | 
| Chris@595 | 674                   << endl; | 
| Chris@595 | 675         return; | 
| Chris@329 | 676     } | 
| Chris@329 | 677 | 
| Chris@329 | 678     ModelRecord rec; | 
| Chris@329 | 679     rec.source = 0; | 
| Chris@408 | 680     rec.channel = 0; | 
| Chris@329 | 681     rec.refcount = 0; | 
| Chris@329 | 682     rec.additional = true; | 
| Chris@329 | 683 | 
| Chris@329 | 684     m_models[model] = rec; | 
| Chris@329 | 685 | 
| Chris@329 | 686 #ifdef DEBUG_DOCUMENT | 
| Chris@329 | 687     SVDEBUG << "Document::addAdditionalModel: Added model " << model << endl; | 
| Chris@329 | 688     cerr << "Models now: "; | 
| Chris@329 | 689     for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@329 | 690         cerr << i->first << " "; | 
| Chris@329 | 691     } | 
| Chris@329 | 692     cerr << endl; | 
| Chris@329 | 693 #endif | 
| Chris@329 | 694 | 
| Chris@387 | 695     if (m_autoAlignment) { | 
| Chris@387 | 696         SVDEBUG << "Document::addAdditionalModel: auto-alignment is on, aligning model if possible" << endl; | 
| Chris@387 | 697         alignModel(model); | 
| Chris@387 | 698     } | 
| Chris@329 | 699 | 
| Chris@329 | 700     emit modelAdded(model); | 
| Chris@329 | 701 } | 
| Chris@329 | 702 | 
| Chris@588 | 703 void | 
| Chris@588 | 704 Document::addAggregateModel(AggregateWaveModel *model) | 
| Chris@588 | 705 { | 
| Chris@588 | 706     connect(model, SIGNAL(modelInvalidated()), | 
| Chris@588 | 707             this, SLOT(aggregateModelInvalidated())); | 
| Chris@588 | 708     m_aggregateModels.insert(model); | 
| Chris@588 | 709 } | 
| Chris@588 | 710 | 
| Chris@588 | 711 void | 
| Chris@588 | 712 Document::aggregateModelInvalidated() | 
| Chris@588 | 713 { | 
| Chris@588 | 714     QObject *s = sender(); | 
| Chris@588 | 715     AggregateWaveModel *aggregate = qobject_cast<AggregateWaveModel *>(s); | 
| Chris@588 | 716     if (aggregate) releaseModel(aggregate); | 
| Chris@588 | 717 } | 
| Chris@588 | 718 | 
| Chris@45 | 719 Model * | 
| Chris@72 | 720 Document::addDerivedModel(const Transform &transform, | 
| Chris@78 | 721                           const ModelTransformer::Input &input, | 
| Chris@296 | 722                           QString &message) | 
| Chris@45 | 723 { | 
| Chris@45 | 724     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@297 | 725         if (i->second.transform == transform && | 
| Chris@297 | 726             i->second.source == input.getModel() && | 
| Chris@72 | 727             i->second.channel == input.getChannel()) { | 
| Chris@297 | 728             std::cerr << "derived model taken from map " << std::endl; | 
| Chris@297 | 729             return i->first; | 
| Chris@297 | 730         } | 
| Chris@45 | 731     } | 
| Chris@45 | 732 | 
| Chris@297 | 733     Transforms tt; | 
| Chris@297 | 734     tt.push_back(transform); | 
| Chris@329 | 735     vector<Model *> mm = addDerivedModels(tt, input, message, 0); | 
| Chris@297 | 736     if (mm.empty()) return 0; | 
| Chris@297 | 737     else return mm[0]; | 
| Chris@297 | 738 } | 
| Chris@45 | 739 | 
| Chris@297 | 740 vector<Model *> | 
| Chris@297 | 741 Document::addDerivedModels(const Transforms &transforms, | 
| Chris@297 | 742                            const ModelTransformer::Input &input, | 
| Chris@329 | 743                            QString &message, | 
| Chris@329 | 744                            AdditionalModelConverter *amc) | 
| Chris@297 | 745 { | 
| Chris@297 | 746     vector<Model *> mm = | 
| Chris@297 | 747         ModelTransformerFactory::getInstance()->transformMultiple | 
| Chris@329 | 748         (transforms, input, message, amc); | 
| Chris@83 | 749 | 
| Chris@297 | 750     for (int j = 0; j < (int)mm.size(); ++j) { | 
| Chris@83 | 751 | 
| Chris@297 | 752         Model *model = mm[j]; | 
| Chris@297 | 753 | 
| Chris@297 | 754         // The transform we actually used was presumably identical to | 
| Chris@297 | 755         // the one asked for, except that the version of the plugin | 
| Chris@297 | 756         // may differ.  It's possible that the returned message | 
| Chris@297 | 757         // contains a warning about this; that doesn't concern us | 
| Chris@297 | 758         // here, but we do need to ensure that the transform we | 
| Chris@297 | 759         // remember is correct for what was actually applied, with the | 
| Chris@297 | 760         // current plugin version. | 
| Chris@297 | 761 | 
| Chris@536 | 762         //!!! would be nice to short-circuit this -- the version is | 
| Chris@536 | 763         //!!! static data, shouldn't have to construct a plugin for it | 
| Chris@536 | 764         //!!! (which may be expensive in Piper-world) | 
| Chris@536 | 765 | 
| Chris@297 | 766         Transform applied = transforms[j]; | 
| Chris@297 | 767         applied.setPluginVersion | 
| Chris@297 | 768             (TransformFactory::getInstance()-> | 
| Chris@297 | 769              getDefaultTransformFor(applied.getIdentifier(), | 
| Chris@436 | 770                                     applied.getSampleRate()) | 
| Chris@297 | 771              .getPluginVersion()); | 
| Chris@297 | 772 | 
| Chris@297 | 773         if (!model) { | 
| Chris@297 | 774             cerr << "WARNING: Document::addDerivedModel: no output model for transform " << applied.getIdentifier() << endl; | 
| Chris@297 | 775         } else { | 
| Chris@329 | 776             addAlreadyDerivedModel(applied, input, model); | 
| Chris@297 | 777         } | 
| Chris@45 | 778     } | 
| Chris@595 | 779 | 
| Chris@297 | 780     return mm; | 
| Chris@45 | 781 } | 
| Chris@45 | 782 | 
| Chris@45 | 783 void | 
| Chris@45 | 784 Document::releaseModel(Model *model) // Will _not_ release main model! | 
| Chris@45 | 785 { | 
| Chris@45 | 786     if (model == 0) { | 
| Chris@595 | 787         return; | 
| Chris@45 | 788     } | 
| Chris@45 | 789 | 
| Chris@45 | 790     if (model == m_mainModel) { | 
| Chris@595 | 791         return; | 
| Chris@45 | 792     } | 
| Chris@45 | 793 | 
| Chris@45 | 794     bool toDelete = false; | 
| Chris@45 | 795 | 
| Chris@45 | 796     if (m_models.find(model) != m_models.end()) { | 
| Chris@595 | 797         if (m_models[model].refcount == 0) { | 
| Chris@595 | 798             SVCERR << "WARNING: Document::releaseModel: model " << model | 
| Chris@588 | 799                    << " reference count is zero already!" << endl; | 
| Chris@595 | 800         } else { | 
| Chris@595 | 801             if (--m_models[model].refcount == 0) { | 
| Chris@595 | 802                 toDelete = true; | 
| Chris@595 | 803             } | 
| Chris@595 | 804         } | 
| Chris@588 | 805     } else if (m_aggregateModels.find(model) != m_aggregateModels.end()) { | 
| Chris@588 | 806         SVDEBUG << "Document::releaseModel: is an aggregate model" << endl; | 
| Chris@588 | 807         toDelete = true; | 
| Chris@45 | 808     } else { | 
| Chris@595 | 809         SVCERR << "WARNING: Document::releaseModel: Unfound model " | 
| Chris@588 | 810                << model << endl; | 
| Chris@595 | 811         toDelete = true; | 
| Chris@45 | 812     } | 
| Chris@45 | 813 | 
| Chris@45 | 814     if (toDelete) { | 
| Chris@45 | 815 | 
| Chris@595 | 816         int sourceCount = 0; | 
| Chris@45 | 817 | 
| Chris@595 | 818         for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@595 | 819             if (i->second.source == model) { | 
| Chris@595 | 820                 ++sourceCount; | 
| Chris@595 | 821                 i->second.source = 0; | 
| Chris@595 | 822             } | 
| Chris@595 | 823         } | 
| Chris@45 | 824 | 
| Chris@595 | 825         if (sourceCount > 0) { | 
| Chris@595 | 826             SVDEBUG << "Document::releaseModel: Deleting model " | 
| Chris@588 | 827                     << model << " even though it is source for " | 
| Chris@588 | 828                     << sourceCount << " other derived model(s) -- resetting " | 
| Chris@588 | 829                     << "their source fields appropriately" << endl; | 
| Chris@595 | 830         } | 
| Chris@45 | 831 | 
| Chris@79 | 832         model->aboutToDelete(); | 
| Chris@595 | 833         emit modelAboutToBeDeleted(model); | 
| Chris@595 | 834         m_models.erase(model); | 
| Chris@137 | 835 | 
| Chris@137 | 836 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 837         SVDEBUG << "Document::releaseModel: Deleted model " << model << endl; | 
| Chris@293 | 838         cerr << "Models now: "; | 
| Chris@137 | 839         for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@293 | 840             cerr << i->first << " "; | 
| Chris@137 | 841         } | 
| Chris@293 | 842         cerr << endl; | 
| Chris@137 | 843 #endif | 
| Chris@137 | 844 | 
| Chris@595 | 845         delete model; | 
| Chris@45 | 846     } | 
| Chris@45 | 847 } | 
| Chris@45 | 848 | 
| Chris@45 | 849 void | 
| Chris@45 | 850 Document::deleteLayer(Layer *layer, bool force) | 
| Chris@45 | 851 { | 
| Chris@45 | 852     if (m_layerViewMap.find(layer) != m_layerViewMap.end() && | 
| Chris@595 | 853         m_layerViewMap[layer].size() > 0) { | 
| Chris@45 | 854 | 
| Chris@595 | 855         cerr << "WARNING: Document::deleteLayer: Layer " | 
| Chris@595 | 856                   << layer << " [" << layer->objectName() << "]" | 
| Chris@595 | 857                   << " is still used in " << m_layerViewMap[layer].size() | 
| Chris@595 | 858                   << " views!" << endl; | 
| Chris@45 | 859 | 
| Chris@595 | 860         if (force) { | 
| Chris@45 | 861 | 
| Chris@77 | 862 #ifdef DEBUG_DOCUMENT | 
| Chris@595 | 863             cerr << "(force flag set -- deleting from all views)" << endl; | 
| Chris@77 | 864 #endif | 
| Chris@45 | 865 | 
| Chris@595 | 866             for (std::set<View *>::iterator j = m_layerViewMap[layer].begin(); | 
| Chris@595 | 867                  j != m_layerViewMap[layer].end(); ++j) { | 
| Chris@595 | 868                 // don't use removeLayerFromView, as it issues a command | 
| Chris@595 | 869                 layer->setLayerDormant(*j, true); | 
| Chris@595 | 870                 (*j)->removeLayer(layer); | 
| Chris@595 | 871             } | 
| Chris@595 | 872 | 
| Chris@595 | 873             m_layerViewMap.erase(layer); | 
| Chris@45 | 874 | 
| Chris@595 | 875         } else { | 
| Chris@595 | 876             return; | 
| Chris@595 | 877         } | 
| Chris@45 | 878     } | 
| Chris@45 | 879 | 
| Chris@45 | 880     if (m_layers.find(layer) == m_layers.end()) { | 
| Chris@595 | 881         SVDEBUG << "Document::deleteLayer: Layer " | 
| Chris@212 | 882                   << layer << " (" << typeid(layer).name() << | 
| Chris@212 | 883                   ") does not exist, or has already been deleted " | 
| Chris@595 | 884                   << "(this may not be as serious as it sounds)" << endl; | 
| Chris@595 | 885         return; | 
| Chris@45 | 886     } | 
| Chris@45 | 887 | 
| Chris@45 | 888     m_layers.erase(layer); | 
| Chris@45 | 889 | 
| Chris@132 | 890 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 891     SVDEBUG << "Document::deleteLayer: Removing, now have " | 
| Chris@229 | 892               << m_layers.size() << " layers" << endl; | 
| Chris@132 | 893 #endif | 
| Chris@52 | 894 | 
| Chris@45 | 895     releaseModel(layer->getModel()); | 
| Chris@45 | 896     emit layerRemoved(layer); | 
| Chris@45 | 897     emit layerAboutToBeDeleted(layer); | 
| Chris@45 | 898     delete layer; | 
| Chris@45 | 899 } | 
| Chris@45 | 900 | 
| Chris@45 | 901 void | 
| Chris@45 | 902 Document::setModel(Layer *layer, Model *model) | 
| Chris@45 | 903 { | 
| Chris@45 | 904     if (model && | 
| Chris@595 | 905         model != m_mainModel && | 
| Chris@595 | 906         m_models.find(model) == m_models.end()) { | 
| Chris@595 | 907         cerr << "ERROR: Document::setModel: Layer " << layer | 
| Chris@595 | 908                   << " (\"" << layer->objectName() | 
| Chris@45 | 909                   << "\") wants to use unregistered model " << model | 
| Chris@595 | 910                   << ": register the layer's model before setting it!" | 
| Chris@595 | 911                   << endl; | 
| Chris@595 | 912         return; | 
| Chris@45 | 913     } | 
| Chris@45 | 914 | 
| Chris@45 | 915     Model *previousModel = layer->getModel(); | 
| Chris@45 | 916 | 
| Chris@45 | 917     if (previousModel == model) { | 
| Chris@233 | 918         SVDEBUG << "NOTE: Document::setModel: Layer " << layer << " (\"" | 
| Chris@229 | 919                   << layer->objectName()                  << "\") is already set to model " | 
| Chris@45 | 920                   << model << " (\"" | 
| Chris@229 | 921                   << (model ? model->objectName(): "(null)") | 
| Chris@229 | 922                   << "\")" << endl; | 
| Chris@45 | 923         return; | 
| Chris@45 | 924     } | 
| Chris@45 | 925 | 
| Chris@45 | 926     if (model && model != m_mainModel) { | 
| Chris@595 | 927         m_models[model].refcount ++; | 
| Chris@45 | 928     } | 
| Chris@45 | 929 | 
| Chris@45 | 930     if (model && previousModel) { | 
| Chris@45 | 931         PlayParameterRepository::getInstance()->copyParameters | 
| Chris@45 | 932             (previousModel, model); | 
| Chris@45 | 933     } | 
| Chris@45 | 934 | 
| Chris@45 | 935     LayerFactory::getInstance()->setModel(layer, model); | 
| Chris@595 | 936         // std::cerr << "layer type: " << LayerFactory::getInstance()->getLayerTypeName(LayerFactory::getInstance()->getLayerType(layer)) << std::endl; | 
| Chris@45 | 937 | 
| Chris@45 | 938     if (previousModel) { | 
| Chris@45 | 939         releaseModel(previousModel); | 
| Chris@45 | 940     } | 
| Chris@45 | 941 } | 
| Chris@45 | 942 | 
| Chris@45 | 943 void | 
| Chris@45 | 944 Document::setChannel(Layer *layer, int channel) | 
| Chris@45 | 945 { | 
| Chris@45 | 946     LayerFactory::getInstance()->setChannel(layer, channel); | 
| Chris@45 | 947 } | 
| Chris@45 | 948 | 
| Chris@45 | 949 void | 
| Chris@45 | 950 Document::addLayerToView(View *view, Layer *layer) | 
| Chris@45 | 951 { | 
| Chris@45 | 952     Model *model = layer->getModel(); | 
| Chris@45 | 953     if (!model) { | 
| Chris@77 | 954 #ifdef DEBUG_DOCUMENT | 
| Chris@595 | 955         SVDEBUG << "Document::addLayerToView: Layer (\"" | 
| Chris@229 | 956                   << layer->objectName()                  << "\") with no model being added to view: " | 
| Chris@229 | 957                   << "normally you want to set the model first" << endl; | 
| Chris@77 | 958 #endif | 
| Chris@45 | 959     } else { | 
| Chris@595 | 960         if (model != m_mainModel && | 
| Chris@595 | 961             m_models.find(model) == m_models.end()) { | 
| Chris@595 | 962             cerr << "ERROR: Document::addLayerToView: Layer " << layer | 
| Chris@595 | 963                       << " has unregistered model " << model | 
| Chris@595 | 964                       << " -- register the layer's model before adding the layer!" << endl; | 
| Chris@595 | 965             return; | 
| Chris@595 | 966         } | 
| Chris@45 | 967     } | 
| Chris@45 | 968 | 
| Chris@45 | 969     CommandHistory::getInstance()->addCommand | 
| Chris@595 | 970         (new Document::AddLayerCommand(this, view, layer)); | 
| Chris@45 | 971 } | 
| Chris@45 | 972 | 
| Chris@45 | 973 void | 
| Chris@45 | 974 Document::removeLayerFromView(View *view, Layer *layer) | 
| Chris@45 | 975 { | 
| Chris@45 | 976     CommandHistory::getInstance()->addCommand | 
| Chris@595 | 977         (new Document::RemoveLayerCommand(this, view, layer)); | 
| Chris@45 | 978 } | 
| Chris@45 | 979 | 
| Chris@45 | 980 void | 
| Chris@45 | 981 Document::addToLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 982 { | 
| Chris@45 | 983     bool firstView = (m_layerViewMap.find(layer) == m_layerViewMap.end() || | 
| Chris@45 | 984                       m_layerViewMap[layer].empty()); | 
| Chris@45 | 985 | 
| Chris@45 | 986     if (m_layerViewMap[layer].find(view) != | 
| Chris@595 | 987         m_layerViewMap[layer].end()) { | 
| Chris@595 | 988         cerr << "WARNING: Document::addToLayerViewMap:" | 
| Chris@595 | 989                   << " Layer " << layer << " -> view " << view << " already in" | 
| Chris@595 | 990                   << " layer view map -- internal inconsistency" << endl; | 
| Chris@45 | 991     } | 
| Chris@45 | 992 | 
| Chris@45 | 993     m_layerViewMap[layer].insert(view); | 
| Chris@45 | 994 | 
| Chris@45 | 995     if (firstView) emit layerInAView(layer, true); | 
| Chris@45 | 996 } | 
| Chris@45 | 997 | 
| Chris@45 | 998 void | 
| Chris@45 | 999 Document::removeFromLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 1000 { | 
| Chris@45 | 1001     if (m_layerViewMap[layer].find(view) == | 
| Chris@595 | 1002         m_layerViewMap[layer].end()) { | 
| Chris@595 | 1003         cerr << "WARNING: Document::removeFromLayerViewMap:" | 
| Chris@595 | 1004                   << " Layer " << layer << " -> view " << view << " not in" | 
| Chris@595 | 1005                   << " layer view map -- internal inconsistency" << endl; | 
| Chris@45 | 1006     } | 
| Chris@45 | 1007 | 
| Chris@45 | 1008     m_layerViewMap[layer].erase(view); | 
| Chris@45 | 1009 | 
| Chris@45 | 1010     if (m_layerViewMap[layer].empty()) { | 
| Chris@45 | 1011         m_layerViewMap.erase(layer); | 
| Chris@45 | 1012         emit layerInAView(layer, false); | 
| Chris@45 | 1013     } | 
| Chris@45 | 1014 } | 
| Chris@45 | 1015 | 
| Chris@45 | 1016 QString | 
| Chris@45 | 1017 Document::getUniqueLayerName(QString candidate) | 
| Chris@45 | 1018 { | 
| Chris@45 | 1019     for (int count = 1; ; ++count) { | 
| Chris@45 | 1020 | 
| Chris@45 | 1021         QString adjusted = | 
| Chris@45 | 1022             (count > 1 ? QString("%1 <%2>").arg(candidate).arg(count) : | 
| Chris@45 | 1023              candidate); | 
| Chris@45 | 1024 | 
| Chris@45 | 1025         bool duplicate = false; | 
| Chris@45 | 1026 | 
| Chris@45 | 1027         for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 1028             if ((*i)->objectName() == adjusted) { | 
| Chris@45 | 1029                 duplicate = true; | 
| Chris@45 | 1030                 break; | 
| Chris@45 | 1031             } | 
| Chris@45 | 1032         } | 
| Chris@45 | 1033 | 
| Chris@45 | 1034         if (!duplicate) return adjusted; | 
| Chris@45 | 1035     } | 
| Chris@45 | 1036 } | 
| Chris@45 | 1037 | 
| Chris@45 | 1038 std::vector<Model *> | 
| Chris@72 | 1039 Document::getTransformInputModels() | 
| Chris@45 | 1040 { | 
| Chris@45 | 1041     std::vector<Model *> models; | 
| Chris@45 | 1042 | 
| Chris@45 | 1043     if (!m_mainModel) return models; | 
| Chris@45 | 1044 | 
| Chris@45 | 1045     models.push_back(m_mainModel); | 
| Chris@45 | 1046 | 
| Chris@45 | 1047     //!!! This will pick up all models, including those that aren't visible... | 
| Chris@45 | 1048 | 
| Chris@45 | 1049     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 1050 | 
| Chris@45 | 1051         Model *model = i->first; | 
| Chris@45 | 1052         if (!model || model == m_mainModel) continue; | 
| Chris@45 | 1053         DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); | 
| Chris@45 | 1054 | 
| Chris@45 | 1055         if (dtvm) { | 
| Chris@45 | 1056             models.push_back(dtvm); | 
| Chris@45 | 1057         } | 
| Chris@45 | 1058     } | 
| Chris@45 | 1059 | 
| Chris@45 | 1060     return models; | 
| Chris@45 | 1061 } | 
| Chris@45 | 1062 | 
| Chris@50 | 1063 bool | 
| Chris@77 | 1064 Document::isKnownModel(const Model *model) const | 
| Chris@77 | 1065 { | 
| Chris@77 | 1066     if (model == m_mainModel) return true; | 
| Chris@77 | 1067     return (m_models.find(const_cast<Model *>(model)) != m_models.end()); | 
| Chris@77 | 1068 } | 
| Chris@77 | 1069 | 
| Chris@428 | 1070 bool | 
| Chris@428 | 1071 Document::canAlign() | 
| Chris@90 | 1072 { | 
| Chris@428 | 1073     return Align::canAlign(); | 
| Chris@50 | 1074 } | 
| Chris@50 | 1075 | 
| Chris@45 | 1076 void | 
| Chris@45 | 1077 Document::alignModel(Model *model) | 
| Chris@45 | 1078 { | 
| Chris@387 | 1079     SVDEBUG << "Document::alignModel(" << model << ")" << endl; | 
| Chris@387 | 1080 | 
| Chris@387 | 1081     if (!m_mainModel) { | 
| Chris@387 | 1082         SVDEBUG << "(no main model to align to)" << endl; | 
| Chris@387 | 1083         return; | 
| Chris@387 | 1084     } | 
| Chris@45 | 1085 | 
| Chris@45 | 1086     RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 1087         dynamic_cast<RangeSummarisableTimeValueModel *>(model); | 
| Chris@387 | 1088     if (!rm) { | 
| Chris@387 | 1089         SVDEBUG << "(main model is not alignable-to)" << endl; | 
| Chris@387 | 1090         return; | 
| Chris@387 | 1091     } | 
| Chris@48 | 1092 | 
| Chris@86 | 1093     if (rm->getAlignmentReference() == m_mainModel) { | 
| Chris@387 | 1094         SVDEBUG << "(model " << rm << " is already aligned to main model " << m_mainModel << ")" << endl; | 
| Chris@86 | 1095         return; | 
| Chris@86 | 1096     } | 
| Chris@45 | 1097 | 
| Chris@86 | 1098     if (model == m_mainModel) { | 
| Chris@86 | 1099         // The reference has an empty alignment to itself.  This makes | 
| Chris@86 | 1100         // it possible to distinguish between the reference and any | 
| Chris@86 | 1101         // unaligned model just by looking at the model itself, | 
| Chris@86 | 1102         // without also knowing what the main model is | 
| Chris@233 | 1103         SVDEBUG << "Document::alignModel(" << model << "): is main model, setting appropriately" << endl; | 
| Chris@86 | 1104         rm->setAlignment(new AlignmentModel(model, model, 0, 0)); | 
| Chris@86 | 1105         return; | 
| Chris@86 | 1106     } | 
| Chris@86 | 1107 | 
| Chris@423 | 1108     if (!m_align->alignModel(m_mainModel, rm)) { | 
| Chris@423 | 1109         cerr << "Alignment failed: " << m_align->getError() << endl; | 
| Chris@423 | 1110         emit alignmentFailed(m_align->getError()); | 
| Chris@64 | 1111     } | 
| Chris@45 | 1112 } | 
| Chris@45 | 1113 | 
| Chris@45 | 1114 void | 
| Chris@45 | 1115 Document::alignModels() | 
| Chris@45 | 1116 { | 
| Chris@45 | 1117     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 1118         alignModel(i->first); | 
| Chris@45 | 1119     } | 
| Chris@86 | 1120     alignModel(m_mainModel); | 
| Chris@45 | 1121 } | 
| Chris@45 | 1122 | 
| Chris@45 | 1123 Document::AddLayerCommand::AddLayerCommand(Document *d, | 
| Chris@595 | 1124                                            View *view, | 
| Chris@595 | 1125                                            Layer *layer) : | 
| Chris@45 | 1126     m_d(d), | 
| Chris@45 | 1127     m_view(view), | 
| Chris@45 | 1128     m_layer(layer), | 
| Chris@45 | 1129     m_name(qApp->translate("AddLayerCommand", "Add %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 1130     m_added(false) | 
| Chris@45 | 1131 { | 
| Chris@45 | 1132 } | 
| Chris@45 | 1133 | 
| Chris@45 | 1134 Document::AddLayerCommand::~AddLayerCommand() | 
| Chris@45 | 1135 { | 
| Chris@77 | 1136 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 1137     SVDEBUG << "Document::AddLayerCommand::~AddLayerCommand" << endl; | 
| Chris@77 | 1138 #endif | 
| Chris@45 | 1139     if (!m_added) { | 
| Chris@595 | 1140         m_d->deleteLayer(m_layer); | 
| Chris@45 | 1141     } | 
| Chris@45 | 1142 } | 
| Chris@45 | 1143 | 
| Chris@159 | 1144 QString | 
| Chris@159 | 1145 Document::AddLayerCommand::getName() const | 
| Chris@159 | 1146 { | 
| Chris@165 | 1147 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 1148     SVDEBUG << "Document::AddLayerCommand::getName(): Name is " | 
| Chris@229 | 1149               << m_name << endl; | 
| Chris@165 | 1150 #endif | 
| Chris@159 | 1151     return m_name; | 
| Chris@159 | 1152 } | 
| Chris@159 | 1153 | 
| Chris@45 | 1154 void | 
| Chris@45 | 1155 Document::AddLayerCommand::execute() | 
| Chris@45 | 1156 { | 
| Chris@45 | 1157     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@595 | 1158         if (m_view->getLayer(i) == m_layer) { | 
| Chris@595 | 1159             // already there | 
| Chris@595 | 1160             m_layer->setLayerDormant(m_view, false); | 
| Chris@595 | 1161             m_added = true; | 
| Chris@595 | 1162             return; | 
| Chris@595 | 1163         } | 
| Chris@45 | 1164     } | 
| Chris@45 | 1165 | 
| Chris@45 | 1166     m_view->addLayer(m_layer); | 
| Chris@45 | 1167     m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 1168 | 
| Chris@45 | 1169     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 1170     m_added = true; | 
| Chris@45 | 1171 } | 
| Chris@45 | 1172 | 
| Chris@45 | 1173 void | 
| Chris@45 | 1174 Document::AddLayerCommand::unexecute() | 
| Chris@45 | 1175 { | 
| Chris@45 | 1176     m_view->removeLayer(m_layer); | 
| Chris@45 | 1177     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 1178 | 
| Chris@45 | 1179     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 1180     m_added = false; | 
| Chris@45 | 1181 } | 
| Chris@45 | 1182 | 
| Chris@45 | 1183 Document::RemoveLayerCommand::RemoveLayerCommand(Document *d, | 
| Chris@595 | 1184                                                  View *view, | 
| Chris@595 | 1185                                                  Layer *layer) : | 
| Chris@45 | 1186     m_d(d), | 
| Chris@45 | 1187     m_view(view), | 
| Chris@45 | 1188     m_layer(layer), | 
| Chris@339 | 1189     m_wasDormant(layer->isLayerDormant(view)), | 
| Chris@45 | 1190     m_name(qApp->translate("RemoveLayerCommand", "Delete %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 1191     m_added(true) | 
| Chris@45 | 1192 { | 
| Chris@45 | 1193 } | 
| Chris@45 | 1194 | 
| Chris@45 | 1195 Document::RemoveLayerCommand::~RemoveLayerCommand() | 
| Chris@45 | 1196 { | 
| Chris@77 | 1197 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 1198     SVDEBUG << "Document::RemoveLayerCommand::~RemoveLayerCommand" << endl; | 
| Chris@77 | 1199 #endif | 
| Chris@45 | 1200     if (!m_added) { | 
| Chris@595 | 1201         m_d->deleteLayer(m_layer); | 
| Chris@45 | 1202     } | 
| Chris@45 | 1203 } | 
| Chris@45 | 1204 | 
| Chris@159 | 1205 QString | 
| Chris@159 | 1206 Document::RemoveLayerCommand::getName() const | 
| Chris@159 | 1207 { | 
| Chris@171 | 1208 #ifdef DEBUG_DOCUMENT | 
| Chris@233 | 1209     SVDEBUG << "Document::RemoveLayerCommand::getName(): Name is " | 
| Chris@229 | 1210               << m_name << endl; | 
| Chris@171 | 1211 #endif | 
| Chris@159 | 1212     return m_name; | 
| Chris@159 | 1213 } | 
| Chris@159 | 1214 | 
| Chris@45 | 1215 void | 
| Chris@45 | 1216 Document::RemoveLayerCommand::execute() | 
| Chris@45 | 1217 { | 
| Chris@45 | 1218     bool have = false; | 
| Chris@45 | 1219     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@595 | 1220         if (m_view->getLayer(i) == m_layer) { | 
| Chris@595 | 1221             have = true; | 
| Chris@595 | 1222             break; | 
| Chris@595 | 1223         } | 
| Chris@45 | 1224     } | 
| Chris@45 | 1225 | 
| Chris@45 | 1226     if (!have) { // not there! | 
| Chris@595 | 1227         m_layer->setLayerDormant(m_view, true); | 
| Chris@595 | 1228         m_added = false; | 
| Chris@595 | 1229         return; | 
| Chris@45 | 1230     } | 
| Chris@45 | 1231 | 
| Chris@45 | 1232     m_view->removeLayer(m_layer); | 
| Chris@45 | 1233     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 1234 | 
| Chris@45 | 1235     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 1236     m_added = false; | 
| Chris@45 | 1237 } | 
| Chris@45 | 1238 | 
| Chris@45 | 1239 void | 
| Chris@45 | 1240 Document::RemoveLayerCommand::unexecute() | 
| Chris@45 | 1241 { | 
| Chris@45 | 1242     m_view->addLayer(m_layer); | 
| Chris@339 | 1243     m_layer->setLayerDormant(m_view, m_wasDormant); | 
| Chris@45 | 1244 | 
| Chris@45 | 1245     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 1246     m_added = true; | 
| Chris@45 | 1247 } | 
| Chris@45 | 1248 | 
| Chris@45 | 1249 void | 
| Chris@45 | 1250 Document::toXml(QTextStream &out, QString indent, QString extraAttributes) const | 
| Chris@45 | 1251 { | 
| Chris@226 | 1252     toXml(out, indent, extraAttributes, false); | 
| Chris@226 | 1253 } | 
| Chris@226 | 1254 | 
| Chris@226 | 1255 void | 
| Chris@226 | 1256 Document::toXmlAsTemplate(QTextStream &out, QString indent, QString extraAttributes) const | 
| Chris@226 | 1257 { | 
| Chris@226 | 1258     toXml(out, indent, extraAttributes, true); | 
| Chris@226 | 1259 } | 
| Chris@226 | 1260 | 
| Chris@226 | 1261 void | 
| Chris@226 | 1262 Document::toXml(QTextStream &out, QString indent, QString extraAttributes, | 
| Chris@226 | 1263                 bool asTemplate) const | 
| Chris@226 | 1264 { | 
| Chris@45 | 1265     out << indent + QString("<data%1%2>\n") | 
| Chris@45 | 1266         .arg(extraAttributes == "" ? "" : " ").arg(extraAttributes); | 
| Chris@45 | 1267 | 
| Chris@45 | 1268     if (m_mainModel) { | 
| Chris@108 | 1269 | 
| Chris@226 | 1270         if (asTemplate) { | 
| Chris@226 | 1271             writePlaceholderMainModel(out, indent + "  "); | 
| Chris@226 | 1272         } else { | 
| Chris@226 | 1273             m_mainModel->toXml(out, indent + "  ", "mainModel=\"true\""); | 
| Chris@226 | 1274         } | 
| Chris@108 | 1275 | 
| Chris@108 | 1276         PlayParameters *playParameters = | 
| Chris@108 | 1277             PlayParameterRepository::getInstance()->getPlayParameters(m_mainModel); | 
| Chris@108 | 1278         if (playParameters) { | 
| Chris@108 | 1279             playParameters->toXml | 
| Chris@108 | 1280                 (out, indent + "  ", | 
| Chris@108 | 1281                  QString("model=\"%1\"") | 
| Chris@108 | 1282                  .arg(XmlExportable::getObjectExportId(m_mainModel))); | 
| Chris@108 | 1283         } | 
| Chris@45 | 1284     } | 
| Chris@45 | 1285 | 
| Chris@45 | 1286     // Models that are not used in a layer that is in a view should | 
| Chris@45 | 1287     // not be written.  Get our list of required models first. | 
| Chris@45 | 1288 | 
| Chris@45 | 1289     std::set<const Model *> used; | 
| Chris@45 | 1290 | 
| Chris@45 | 1291     for (LayerViewMap::const_iterator i = m_layerViewMap.begin(); | 
| Chris@45 | 1292          i != m_layerViewMap.end(); ++i) { | 
| Chris@45 | 1293 | 
| Chris@589 | 1294         if (i->first && !i->second.empty()) { // Layer exists, is in views | 
| Chris@589 | 1295             Model *m = i->first->getModel(); | 
| Chris@589 | 1296             if (m) { | 
| Chris@589 | 1297                 used.insert(m); | 
| Chris@589 | 1298                 if (m->getSourceModel()) { | 
| Chris@589 | 1299                     used.insert(m->getSourceModel()); | 
| Chris@589 | 1300                 } | 
| Chris@589 | 1301             } | 
| Chris@45 | 1302         } | 
| Chris@45 | 1303     } | 
| Chris@45 | 1304 | 
| Chris@589 | 1305     // Write aggregate models first, so that when re-reading | 
| Chris@589 | 1306     // derivations we already know about their existence. But only | 
| Chris@589 | 1307     // those that are actually used | 
| Chris@589 | 1308 | 
| Chris@589 | 1309     for (std::set<Model *>::iterator i = m_aggregateModels.begin(); | 
| Chris@589 | 1310          i != m_aggregateModels.end(); ++i) { | 
| Chris@589 | 1311 | 
| Chris@589 | 1312         SVDEBUG << "checking aggregate model " << *i << endl; | 
| Chris@589 | 1313 | 
| Chris@589 | 1314         AggregateWaveModel *aggregate = qobject_cast<AggregateWaveModel *>(*i); | 
| Chris@589 | 1315         if (!aggregate) continue; | 
| Chris@589 | 1316         if (used.find(aggregate) == used.end()) { | 
| Chris@589 | 1317             SVDEBUG << "(unused, skipping)" << endl; | 
| Chris@589 | 1318             continue; | 
| Chris@589 | 1319         } | 
| Chris@589 | 1320 | 
| Chris@589 | 1321         SVDEBUG << "(used, writing)" << endl; | 
| Chris@589 | 1322 | 
| Chris@589 | 1323         aggregate->toXml(out, indent + "  "); | 
| Chris@589 | 1324     } | 
| Chris@589 | 1325 | 
| Chris@111 | 1326     std::set<Model *> written; | 
| Chris@111 | 1327 | 
| Chris@45 | 1328     for (ModelMap::const_iterator i = m_models.begin(); | 
| Chris@595 | 1329          i != m_models.end(); ++i) { | 
| Chris@45 | 1330 | 
| Chris@111 | 1331         Model *model = i->first; | 
| Chris@595 | 1332         const ModelRecord &rec = i->second; | 
| Chris@45 | 1333 | 
| Chris@45 | 1334         if (used.find(model) == used.end()) continue; | 
| Chris@45 | 1335 | 
| Chris@45 | 1336         // We need an intelligent way to determine which models need | 
| Chris@45 | 1337         // to be streamed (i.e. have been edited, or are small) and | 
| Chris@45 | 1338         // which should not be (i.e. remain as generated by a | 
| Chris@45 | 1339         // transform, and are large). | 
| Chris@45 | 1340         // | 
| Chris@45 | 1341         // At the moment we can get away with deciding not to stream | 
| Chris@45 | 1342         // dense 3d models or writable wave file models, provided they | 
| Chris@45 | 1343         // were generated from a transform, because at the moment there | 
| Chris@45 | 1344         // is no way to edit those model types so it should be safe to | 
| Chris@45 | 1345         // regenerate them.  That won't always work in future though. | 
| Chris@45 | 1346         // It would be particularly nice to be able to ask the user, | 
| Chris@45 | 1347         // as well as making an intelligent guess. | 
| Chris@45 | 1348 | 
| Chris@45 | 1349         bool writeModel = true; | 
| Chris@45 | 1350         bool haveDerivation = false; | 
| Chris@45 | 1351 | 
| Chris@72 | 1352         if (rec.source && rec.transform.getIdentifier() != "") { | 
| Chris@45 | 1353             haveDerivation = true; | 
| Chris@45 | 1354         } | 
| Chris@45 | 1355 | 
| Chris@45 | 1356         if (haveDerivation) { | 
| Chris@45 | 1357             if (dynamic_cast<const WritableWaveFileModel *>(model)) { | 
| Chris@45 | 1358                 writeModel = false; | 
| Chris@45 | 1359             } else if (dynamic_cast<const DenseThreeDimensionalModel *>(model)) { | 
| Chris@45 | 1360                 writeModel = false; | 
| Chris@45 | 1361             } | 
| Chris@45 | 1362         } | 
| Chris@45 | 1363 | 
| Chris@45 | 1364         if (writeModel) { | 
| Chris@111 | 1365             model->toXml(out, indent + "  "); | 
| Chris@111 | 1366             written.insert(model); | 
| Chris@45 | 1367         } | 
| Chris@45 | 1368 | 
| Chris@595 | 1369         if (haveDerivation) { | 
| Chris@72 | 1370             writeBackwardCompatibleDerivation(out, indent + "  ", | 
| Chris@111 | 1371                                               model, rec); | 
| Chris@595 | 1372         } | 
| Chris@45 | 1373 | 
| Chris@45 | 1374         //!!! We should probably own the PlayParameterRepository | 
| Chris@45 | 1375         PlayParameters *playParameters = | 
| Chris@111 | 1376             PlayParameterRepository::getInstance()->getPlayParameters(model); | 
| Chris@45 | 1377         if (playParameters) { | 
| Chris@45 | 1378             playParameters->toXml | 
| Chris@45 | 1379                 (out, indent + "  ", | 
| Chris@45 | 1380                  QString("model=\"%1\"") | 
| Chris@111 | 1381                  .arg(XmlExportable::getObjectExportId(model))); | 
| Chris@45 | 1382         } | 
| Chris@45 | 1383     } | 
| Chris@589 | 1384 | 
| Chris@111 | 1385     //!!! | 
| Chris@111 | 1386 | 
| Chris@111 | 1387     // We should write out the alignment models here.  AlignmentModel | 
| Chris@111 | 1388     // needs a toXml that writes out the export IDs of its reference | 
| Chris@111 | 1389     // and aligned models, and then streams its path model.  Note that | 
| Chris@111 | 1390     // this will only work when the alignment is complete, so we | 
| Chris@111 | 1391     // should probably wait for it if it isn't already by this point. | 
| Chris@111 | 1392 | 
| Chris@111 | 1393     for (std::set<Model *>::const_iterator i = written.begin(); | 
| Chris@595 | 1394          i != written.end(); ++i) { | 
| Chris@111 | 1395 | 
| Chris@111 | 1396         const Model *model = *i; | 
| Chris@111 | 1397         const AlignmentModel *alignment = model->getAlignment(); | 
| Chris@111 | 1398         if (!alignment) continue; | 
| Chris@111 | 1399 | 
| Chris@111 | 1400         alignment->toXml(out, indent + "  "); | 
| Chris@111 | 1401     } | 
| Chris@111 | 1402 | 
| Chris@45 | 1403     for (LayerSet::const_iterator i = m_layers.begin(); | 
| Chris@595 | 1404          i != m_layers.end(); ++i) { | 
| Chris@45 | 1405 | 
| Chris@595 | 1406         (*i)->toXml(out, indent + "  "); | 
| Chris@45 | 1407     } | 
| Chris@45 | 1408 | 
| Chris@45 | 1409     out << indent + "</data>\n"; | 
| Chris@45 | 1410 } | 
| Chris@45 | 1411 | 
| Chris@72 | 1412 void | 
| Chris@226 | 1413 Document::writePlaceholderMainModel(QTextStream &out, QString indent) const | 
| Chris@226 | 1414 { | 
| Chris@226 | 1415     out << indent; | 
| Chris@226 | 1416     out << QString("<model id=\"%1\" name=\"placeholder\" sampleRate=\"%2\" type=\"wavefile\" file=\":samples/silent.wav\" mainModel=\"true\"/>\n") | 
| Chris@226 | 1417         .arg(getObjectExportId(m_mainModel)) | 
| Chris@226 | 1418         .arg(m_mainModel->getSampleRate()); | 
| Chris@226 | 1419 } | 
| Chris@226 | 1420 | 
| Chris@226 | 1421 void | 
| Chris@72 | 1422 Document::writeBackwardCompatibleDerivation(QTextStream &out, QString indent, | 
| Chris@72 | 1423                                             Model *targetModel, | 
| Chris@72 | 1424                                             const ModelRecord &rec) const | 
| Chris@72 | 1425 { | 
| Chris@72 | 1426     // There is a lot of redundancy in the XML we output here, because | 
| Chris@72 | 1427     // we want it to work with older SV session file reading code as | 
| Chris@72 | 1428     // well. | 
| Chris@72 | 1429     // | 
| Chris@72 | 1430     // Formerly, a transform was described using a derivation element | 
| Chris@72 | 1431     // which set out the source and target models, execution context | 
| Chris@72 | 1432     // (step size, input channel etc) and transform id, containing a | 
| Chris@72 | 1433     // plugin element which set out the transform parameters and so | 
| Chris@72 | 1434     // on.  (The plugin element came from a "configurationXml" string | 
| Chris@72 | 1435     // obtained from PluginXml.) | 
| Chris@72 | 1436     // | 
| Chris@72 | 1437     // This has been replaced by a derivation element setting out the | 
| Chris@72 | 1438     // source and target models and input channel, containing a | 
| Chris@72 | 1439     // transform element which sets out everything in the Transform. | 
| Chris@72 | 1440     // | 
| Chris@72 | 1441     // In order to retain compatibility with older SV code, however, | 
| Chris@72 | 1442     // we have to write out the same stuff into the derivation as | 
| Chris@72 | 1443     // before, and manufacture an appropriate plugin element as well | 
| Chris@72 | 1444     // as the transform element.  In order that newer code knows it's | 
| Chris@72 | 1445     // dealing with a newer format, we will also write an attribute | 
| Chris@72 | 1446     // 'type="transform"' in the derivation element. | 
| Chris@45 | 1447 | 
| Chris@72 | 1448     const Transform &transform = rec.transform; | 
| Chris@72 | 1449 | 
| Chris@72 | 1450     // Just for reference, this is what we would write if we didn't | 
| Chris@72 | 1451     // have to be backward compatible: | 
| Chris@72 | 1452     // | 
| Chris@72 | 1453     //    out << indent | 
| Chris@72 | 1454     //        << QString("<derivation type=\"transform\" source=\"%1\" " | 
| Chris@72 | 1455     //                   "model=\"%2\" channel=\"%3\">\n") | 
| Chris@72 | 1456     //        .arg(XmlExportable::getObjectExportId(rec.source)) | 
| Chris@72 | 1457     //        .arg(XmlExportable::getObjectExportId(targetModel)) | 
| Chris@72 | 1458     //        .arg(rec.channel); | 
| Chris@72 | 1459     // | 
| Chris@72 | 1460     //    transform.toXml(out, indent + "  "); | 
| Chris@72 | 1461     // | 
| Chris@72 | 1462     //    out << indent << "</derivation>\n"; | 
| Chris@72 | 1463     // | 
| Chris@72 | 1464     // Unfortunately, we can't just do that.  So we do this... | 
| Chris@72 | 1465 | 
| Chris@72 | 1466     QString extentsAttributes; | 
| Chris@72 | 1467     if (transform.getStartTime() != RealTime::zeroTime || | 
| Chris@72 | 1468         transform.getDuration() != RealTime::zeroTime) { | 
| Chris@72 | 1469         extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") | 
| Chris@72 | 1470             .arg(RealTime::realTime2Frame(transform.getStartTime(), | 
| Chris@72 | 1471                                           targetModel->getSampleRate())) | 
| Chris@72 | 1472             .arg(RealTime::realTime2Frame(transform.getDuration(), | 
| Chris@72 | 1473                                           targetModel->getSampleRate())); | 
| Chris@72 | 1474     } | 
| Chris@595 | 1475 | 
| Chris@72 | 1476     out << indent; | 
| Chris@72 | 1477     out << QString("<derivation type=\"transform\" source=\"%1\" " | 
| Chris@72 | 1478                    "model=\"%2\" channel=\"%3\" domain=\"%4\" " | 
| Chris@72 | 1479                    "stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" " | 
| Chris@72 | 1480                    "transform=\"%9\">\n") | 
| Chris@72 | 1481         .arg(XmlExportable::getObjectExportId(rec.source)) | 
| Chris@72 | 1482         .arg(XmlExportable::getObjectExportId(targetModel)) | 
| Chris@72 | 1483         .arg(rec.channel) | 
| Chris@72 | 1484         .arg(TransformFactory::getInstance()->getTransformInputDomain | 
| Chris@72 | 1485              (transform.getIdentifier())) | 
| Chris@72 | 1486         .arg(transform.getStepSize()) | 
| Chris@72 | 1487         .arg(transform.getBlockSize()) | 
| Chris@72 | 1488         .arg(extentsAttributes) | 
| Chris@72 | 1489         .arg(int(transform.getWindowType())) | 
| Chris@72 | 1490         .arg(XmlExportable::encodeEntities(transform.getIdentifier())); | 
| Chris@72 | 1491 | 
| Chris@72 | 1492     transform.toXml(out, indent + "  "); | 
| Chris@72 | 1493 | 
| Chris@72 | 1494     out << indent << "  " | 
| Chris@72 | 1495         << TransformFactory::getInstance()->getPluginConfigurationXml(transform); | 
| Chris@72 | 1496 | 
| Chris@72 | 1497     out << indent << "</derivation>\n"; | 
| Chris@72 | 1498 } | 
| Chris@72 | 1499 |