| 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 "SVFileReader.h" | 
| Chris@45 | 17 | 
| Chris@45 | 18 #include "layer/Layer.h" | 
| Chris@45 | 19 #include "view/View.h" | 
| Chris@45 | 20 #include "base/PlayParameters.h" | 
| Chris@45 | 21 #include "base/PlayParameterRepository.h" | 
| Chris@116 | 22 #include "base/Preferences.h" | 
| Chris@45 | 23 | 
| Chris@45 | 24 #include "data/fileio/AudioFileReaderFactory.h" | 
| Chris@45 | 25 #include "data/fileio/FileSource.h" | 
| Chris@45 | 26 | 
| Chris@170 | 27 #include "data/fileio/FileFinder.h" | 
| Chris@109 | 28 | 
| Chris@479 | 29 #include "data/model/ReadOnlyWaveFileModel.h" | 
| Chris@45 | 30 #include "data/model/EditableDenseThreeDimensionalModel.h" | 
| Chris@45 | 31 #include "data/model/SparseOneDimensionalModel.h" | 
| Chris@45 | 32 #include "data/model/SparseTimeValueModel.h" | 
| Chris@45 | 33 #include "data/model/NoteModel.h" | 
| Chris@343 | 34 #include "data/model/FlexiNoteModel.h" | 
| Chris@137 | 35 #include "data/model/RegionModel.h" | 
| Chris@45 | 36 #include "data/model/TextModel.h" | 
| Chris@45 | 37 #include "data/model/ImageModel.h" | 
| Chris@111 | 38 #include "data/model/AlignmentModel.h" | 
| Chris@45 | 39 | 
| Chris@106 | 40 #include "transform/TransformFactory.h" | 
| Chris@72 | 41 | 
| Chris@45 | 42 #include "view/Pane.h" | 
| Chris@45 | 43 | 
| Chris@109 | 44 #include "widgets/ProgressDialog.h" | 
| Chris@109 | 45 | 
| Chris@45 | 46 #include "Document.h" | 
| Chris@45 | 47 | 
| Chris@45 | 48 #include <QString> | 
| Chris@45 | 49 #include <QMessageBox> | 
| Chris@45 | 50 #include <QFileDialog> | 
| Chris@45 | 51 | 
| Chris@45 | 52 #include <iostream> | 
| Chris@45 | 53 | 
| Chris@45 | 54 SVFileReader::SVFileReader(Document *document, | 
| Chris@595 | 55                            SVFileReaderPaneCallback &callback, | 
| Chris@45 | 56                            QString location) : | 
| Chris@45 | 57     m_document(document), | 
| Chris@45 | 58     m_paneCallback(callback), | 
| Chris@45 | 59     m_location(location), | 
| Chris@45 | 60     m_currentPane(0), | 
| Chris@410 | 61     m_currentLayer(0), | 
| Chris@45 | 62     m_currentDataset(0), | 
| Chris@45 | 63     m_currentDerivedModel(0), | 
| Chris@45 | 64     m_currentDerivedModelId(-1), | 
| Chris@45 | 65     m_currentPlayParameters(0), | 
| Chris@72 | 66     m_currentTransformSource(0), | 
| Chris@410 | 67     m_currentTransformChannel(0), | 
| Chris@410 | 68     m_currentTransformIsNewStyle(true), | 
| Chris@45 | 69     m_datasetSeparator(" "), | 
| Chris@45 | 70     m_inRow(false), | 
| Chris@45 | 71     m_inLayer(false), | 
| Chris@45 | 72     m_inView(false), | 
| Chris@410 | 73     m_inData(false), | 
| Chris@410 | 74     m_inSelections(false), | 
| Chris@45 | 75     m_rowNumber(0), | 
| Chris@45 | 76     m_ok(false) | 
| Chris@45 | 77 { | 
| Chris@45 | 78 } | 
| Chris@45 | 79 | 
| Chris@45 | 80 void | 
| Chris@45 | 81 SVFileReader::parse(const QString &xmlData) | 
| Chris@45 | 82 { | 
| Chris@45 | 83     QXmlInputSource inputSource; | 
| Chris@45 | 84     inputSource.setData(xmlData); | 
| Chris@45 | 85     parse(inputSource); | 
| Chris@45 | 86 } | 
| Chris@45 | 87 | 
| Chris@45 | 88 void | 
| Chris@45 | 89 SVFileReader::parse(QXmlInputSource &inputSource) | 
| Chris@45 | 90 { | 
| Chris@45 | 91     QXmlSimpleReader reader; | 
| Chris@45 | 92     reader.setContentHandler(this); | 
| Chris@45 | 93     reader.setErrorHandler(this); | 
| Chris@45 | 94     m_ok = reader.parse(inputSource); | 
| Chris@45 | 95 } | 
| Chris@45 | 96 | 
| Chris@45 | 97 bool | 
| Chris@45 | 98 SVFileReader::isOK() | 
| Chris@45 | 99 { | 
| Chris@45 | 100     return m_ok; | 
| Chris@45 | 101 } | 
| Chris@595 | 102 | 
| Chris@45 | 103 SVFileReader::~SVFileReader() | 
| Chris@45 | 104 { | 
| Chris@45 | 105     if (!m_awaitingDatasets.empty()) { | 
| Chris@601 | 106         SVCERR << "WARNING: SV-XML: File ended with " | 
| Chris@595 | 107                   << m_awaitingDatasets.size() << " unfilled model dataset(s)" | 
| Chris@595 | 108                   << endl; | 
| Chris@45 | 109     } | 
| Chris@45 | 110 | 
| Chris@45 | 111     std::set<Model *> unaddedModels; | 
| Chris@45 | 112 | 
| Chris@45 | 113     for (std::map<int, Model *>::iterator i = m_models.begin(); | 
| Chris@595 | 114          i != m_models.end(); ++i) { | 
| Chris@595 | 115         if (m_addedModels.find(i->second) == m_addedModels.end()) { | 
| Chris@595 | 116             unaddedModels.insert(i->second); | 
| Chris@595 | 117         } | 
| Chris@45 | 118     } | 
| Chris@45 | 119 | 
| Chris@45 | 120     if (!unaddedModels.empty()) { | 
| Chris@601 | 121         SVCERR << "WARNING: SV-XML: File contained " | 
| Chris@595 | 122                   << unaddedModels.size() << " unused models" | 
| Chris@595 | 123                   << endl; | 
| Chris@595 | 124         while (!unaddedModels.empty()) { | 
| Chris@595 | 125             delete *unaddedModels.begin(); | 
| Chris@595 | 126             unaddedModels.erase(unaddedModels.begin()); | 
| Chris@595 | 127         } | 
| Chris@595 | 128     } | 
| Chris@45 | 129 } | 
| Chris@45 | 130 | 
| Chris@45 | 131 bool | 
| Chris@45 | 132 SVFileReader::startElement(const QString &, const QString &, | 
| Chris@595 | 133                            const QString &qName, | 
| Chris@595 | 134                            const QXmlAttributes &attributes) | 
| Chris@45 | 135 { | 
| Chris@45 | 136     QString name = qName.toLower(); | 
| Chris@45 | 137 | 
| Chris@45 | 138     bool ok = false; | 
| Chris@45 | 139 | 
| Chris@45 | 140     // Valid element names: | 
| Chris@45 | 141     // | 
| Chris@45 | 142     // sv | 
| Chris@45 | 143     // data | 
| Chris@45 | 144     // dataset | 
| Chris@45 | 145     // display | 
| Chris@45 | 146     // derivation | 
| Chris@45 | 147     // playparameters | 
| Chris@45 | 148     // layer | 
| Chris@45 | 149     // model | 
| Chris@45 | 150     // point | 
| Chris@45 | 151     // row | 
| Chris@45 | 152     // view | 
| Chris@45 | 153     // window | 
| Chris@72 | 154     // plugin | 
| Chris@72 | 155     // transform | 
| Chris@72 | 156     // selections | 
| Chris@72 | 157     // selection | 
| Chris@72 | 158     // measurement | 
| Chris@45 | 159 | 
| Chris@45 | 160     if (name == "sv") { | 
| Chris@45 | 161 | 
| Chris@595 | 162         // nothing needed | 
| Chris@595 | 163         ok = true; | 
| Chris@45 | 164 | 
| Chris@45 | 165     } else if (name == "data") { | 
| Chris@45 | 166 | 
| Chris@595 | 167         // nothing needed | 
| Chris@595 | 168         m_inData = true; | 
| Chris@595 | 169         ok = true; | 
| Chris@45 | 170 | 
| Chris@45 | 171     } else if (name == "display") { | 
| Chris@45 | 172 | 
| Chris@595 | 173         // nothing needed | 
| Chris@595 | 174         ok = true; | 
| Chris@45 | 175 | 
| Chris@45 | 176     } else if (name == "window") { | 
| Chris@45 | 177 | 
| Chris@595 | 178         ok = readWindow(attributes); | 
| Chris@45 | 179 | 
| Chris@45 | 180     } else if (name == "model") { | 
| Chris@45 | 181 | 
| Chris@595 | 182         ok = readModel(attributes); | 
| Chris@45 | 183 | 
| Chris@45 | 184     } else if (name == "dataset") { | 
| Chris@595 | 185 | 
| Chris@595 | 186         ok = readDatasetStart(attributes); | 
| Chris@45 | 187 | 
| Chris@45 | 188     } else if (name == "bin") { | 
| Chris@595 | 189 | 
| Chris@595 | 190         ok = addBinToDataset(attributes); | 
| Chris@45 | 191 | 
| Chris@45 | 192     } else if (name == "point") { | 
| Chris@595 | 193 | 
| Chris@595 | 194         ok = addPointToDataset(attributes); | 
| Chris@45 | 195 | 
| Chris@45 | 196     } else if (name == "row") { | 
| Chris@45 | 197 | 
| Chris@595 | 198         ok = addRowToDataset(attributes); | 
| Chris@45 | 199 | 
| Chris@45 | 200     } else if (name == "layer") { | 
| Chris@45 | 201 | 
| Chris@45 | 202         addUnaddedModels(); // all models must be specified before first layer | 
| Chris@595 | 203         ok = readLayer(attributes); | 
| Chris@45 | 204 | 
| Chris@45 | 205     } else if (name == "view") { | 
| Chris@45 | 206 | 
| Chris@595 | 207         m_inView = true; | 
| Chris@595 | 208         ok = readView(attributes); | 
| Chris@45 | 209 | 
| Chris@45 | 210     } else if (name == "derivation") { | 
| Chris@45 | 211 | 
| Chris@595 | 212         ok = readDerivation(attributes); | 
| Chris@45 | 213 | 
| Chris@45 | 214     } else if (name == "playparameters") { | 
| Chris@45 | 215 | 
| Chris@45 | 216         ok = readPlayParameters(attributes); | 
| Chris@45 | 217 | 
| Chris@45 | 218     } else if (name == "plugin") { | 
| Chris@45 | 219 | 
| Chris@595 | 220         ok = readPlugin(attributes); | 
| Chris@45 | 221 | 
| Chris@45 | 222     } else if (name == "selections") { | 
| Chris@45 | 223 | 
| Chris@595 | 224         m_inSelections = true; | 
| Chris@595 | 225         ok = true; | 
| Chris@45 | 226 | 
| Chris@45 | 227     } else if (name == "selection") { | 
| Chris@45 | 228 | 
| Chris@595 | 229         ok = readSelection(attributes); | 
| Chris@45 | 230 | 
| Chris@45 | 231     } else if (name == "measurement") { | 
| Chris@45 | 232 | 
| Chris@45 | 233         ok = readMeasurement(attributes); | 
| Chris@45 | 234 | 
| Chris@72 | 235     } else if (name == "transform") { | 
| Chris@72 | 236 | 
| Chris@72 | 237         ok = readTransform(attributes); | 
| Chris@72 | 238 | 
| Chris@72 | 239     } else if (name == "parameter") { | 
| Chris@72 | 240 | 
| Chris@72 | 241         ok = readParameter(attributes); | 
| Chris@72 | 242 | 
| Chris@45 | 243     } else { | 
| Chris@601 | 244         SVCERR << "WARNING: SV-XML: Unexpected element \"" | 
| Chris@294 | 245                   << name << "\"" << endl; | 
| Chris@45 | 246     } | 
| Chris@45 | 247 | 
| Chris@45 | 248     if (!ok) { | 
| Chris@601 | 249         SVCERR << "WARNING: SV-XML: Failed to completely process element \"" | 
| Chris@595 | 250                   << name << "\"" << endl; | 
| Chris@45 | 251     } | 
| Chris@45 | 252 | 
| Chris@45 | 253     return true; | 
| Chris@45 | 254 } | 
| Chris@45 | 255 | 
| Chris@45 | 256 bool | 
| Chris@45 | 257 SVFileReader::characters(const QString &text) | 
| Chris@45 | 258 { | 
| Chris@45 | 259     bool ok = false; | 
| Chris@45 | 260 | 
| Chris@45 | 261     if (m_inRow) { | 
| Chris@595 | 262         ok = readRowData(text); | 
| Chris@595 | 263         if (!ok) { | 
| Chris@601 | 264             SVCERR << "WARNING: SV-XML: Failed to read row data content for row " << m_rowNumber << endl; | 
| Chris@595 | 265         } | 
| Chris@45 | 266     } | 
| Chris@45 | 267 | 
| Chris@45 | 268     return true; | 
| Chris@45 | 269 } | 
| Chris@45 | 270 | 
| Chris@45 | 271 bool | 
| Chris@45 | 272 SVFileReader::endElement(const QString &, const QString &, | 
| Chris@595 | 273                          const QString &qName) | 
| Chris@45 | 274 { | 
| Chris@45 | 275     QString name = qName.toLower(); | 
| Chris@45 | 276 | 
| Chris@45 | 277     if (name == "dataset") { | 
| Chris@45 | 278 | 
| Chris@595 | 279         if (m_currentDataset) { | 
| Chris@595 | 280 | 
| Chris@595 | 281             bool foundInAwaiting = false; | 
| Chris@45 | 282 | 
| Chris@595 | 283             for (std::map<int, int>::iterator i = m_awaitingDatasets.begin(); | 
| Chris@595 | 284                  i != m_awaitingDatasets.end(); ++i) { | 
| Chris@595 | 285                 if (haveModel(i->second) && | 
| Chris@45 | 286                     m_models[i->second] == m_currentDataset) { | 
| Chris@595 | 287                     m_awaitingDatasets.erase(i); | 
| Chris@595 | 288                     foundInAwaiting = true; | 
| Chris@595 | 289                     break; | 
| Chris@595 | 290                 } | 
| Chris@595 | 291             } | 
| Chris@45 | 292 | 
| Chris@595 | 293             if (!foundInAwaiting) { | 
| Chris@601 | 294                 SVCERR << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl; | 
| Chris@595 | 295             } | 
| Chris@595 | 296         } | 
| Chris@45 | 297 | 
| Chris@595 | 298         m_currentDataset = 0; | 
| Chris@45 | 299 | 
| Chris@45 | 300     } else if (name == "data") { | 
| Chris@45 | 301 | 
| Chris@45 | 302         addUnaddedModels(); | 
| Chris@595 | 303         m_inData = false; | 
| Chris@45 | 304 | 
| Chris@45 | 305     } else if (name == "derivation") { | 
| Chris@45 | 306 | 
| Chris@45 | 307         if (!m_currentDerivedModel) { | 
| Chris@358 | 308             if (m_currentDerivedModelId < 0) { | 
| Chris@601 | 309                 SVCERR << "WARNING: SV-XML: Bad derivation output model id " | 
| Chris@293 | 310                           << m_currentDerivedModelId << endl; | 
| Chris@45 | 311             } else if (haveModel(m_currentDerivedModelId)) { | 
| Chris@601 | 312                 SVCERR << "WARNING: SV-XML: Derivation has existing model " | 
| Chris@45 | 313                           << m_currentDerivedModelId | 
| Chris@293 | 314                           << " as target, not regenerating" << endl; | 
| Chris@45 | 315             } else { | 
| Chris@78 | 316                 QString message; | 
| Chris@45 | 317                 m_currentDerivedModel = m_models[m_currentDerivedModelId] = | 
| Chris@72 | 318                     m_document->addDerivedModel | 
| Chris@72 | 319                     (m_currentTransform, | 
| Chris@72 | 320                      ModelTransformer::Input(m_currentTransformSource, | 
| Chris@78 | 321                                              m_currentTransformChannel), | 
| Chris@78 | 322                      message); | 
| Chris@79 | 323                 if (!m_currentDerivedModel) { | 
| Chris@79 | 324                     emit modelRegenerationFailed(tr("(derived model in SV-XML)"), | 
| Chris@79 | 325                                                  m_currentTransform.getIdentifier(), | 
| Chris@79 | 326                                                  message); | 
| Chris@79 | 327                 } else if (message != "") { | 
| Chris@79 | 328                     emit modelRegenerationWarning(tr("(derived model in SV-XML)"), | 
| Chris@79 | 329                                                   m_currentTransform.getIdentifier(), | 
| Chris@79 | 330                                                   message); | 
| Chris@79 | 331                 } | 
| Chris@45 | 332             } | 
| Chris@45 | 333         } else { | 
| Chris@329 | 334             m_document->addAlreadyDerivedModel | 
| Chris@72 | 335                 (m_currentTransform, | 
| Chris@72 | 336                  ModelTransformer::Input(m_currentTransformSource, | 
| Chris@72 | 337                                          m_currentTransformChannel), | 
| Chris@72 | 338                  m_currentDerivedModel); | 
| Chris@45 | 339         } | 
| Chris@45 | 340 | 
| Chris@45 | 341         m_addedModels.insert(m_currentDerivedModel); | 
| Chris@45 | 342         m_currentDerivedModel = 0; | 
| Chris@45 | 343         m_currentDerivedModelId = -1; | 
| Chris@72 | 344         m_currentTransformSource = 0; | 
| Chris@72 | 345         m_currentTransform = Transform(); | 
| Chris@72 | 346         m_currentTransformChannel = -1; | 
| Chris@45 | 347 | 
| Chris@45 | 348     } else if (name == "row") { | 
| Chris@595 | 349         m_inRow = false; | 
| Chris@45 | 350     } else if (name == "layer") { | 
| Chris@45 | 351         m_inLayer = false; | 
| Chris@45 | 352     } else if (name == "view") { | 
| Chris@595 | 353         m_inView = false; | 
| Chris@45 | 354     } else if (name == "selections") { | 
| Chris@595 | 355         m_inSelections = false; | 
| Chris@45 | 356     } else if (name == "playparameters") { | 
| Chris@45 | 357         m_currentPlayParameters = 0; | 
| Chris@45 | 358     } | 
| Chris@45 | 359 | 
| Chris@45 | 360     return true; | 
| Chris@45 | 361 } | 
| Chris@45 | 362 | 
| Chris@45 | 363 bool | 
| Chris@45 | 364 SVFileReader::error(const QXmlParseException &exception) | 
| Chris@45 | 365 { | 
| Chris@45 | 366     m_errorString = | 
| Chris@595 | 367         QString("ERROR: SV-XML: %1 at line %2, column %3") | 
| Chris@595 | 368         .arg(exception.message()) | 
| Chris@595 | 369         .arg(exception.lineNumber()) | 
| Chris@595 | 370         .arg(exception.columnNumber()); | 
| Chris@601 | 371     SVCERR << m_errorString << endl; | 
| Chris@45 | 372     return QXmlDefaultHandler::error(exception); | 
| Chris@45 | 373 } | 
| Chris@45 | 374 | 
| Chris@45 | 375 bool | 
| Chris@45 | 376 SVFileReader::fatalError(const QXmlParseException &exception) | 
| Chris@45 | 377 { | 
| Chris@45 | 378     m_errorString = | 
| Chris@595 | 379         QString("FATAL ERROR: SV-XML: %1 at line %2, column %3") | 
| Chris@595 | 380         .arg(exception.message()) | 
| Chris@595 | 381         .arg(exception.lineNumber()) | 
| Chris@595 | 382         .arg(exception.columnNumber()); | 
| Chris@601 | 383     SVCERR << m_errorString << endl; | 
| Chris@45 | 384     return QXmlDefaultHandler::fatalError(exception); | 
| Chris@45 | 385 } | 
| Chris@45 | 386 | 
| Chris@45 | 387 | 
| Chris@595 | 388 #define READ_MANDATORY(TYPE, NAME, CONVERSION)                      \ | 
| Chris@45 | 389     TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \ | 
| Chris@45 | 390     if (!ok) { \ | 
| Chris@601 | 391         SVCERR << "WARNING: SV-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << endl; \ | 
| Chris@595 | 392         return false; \ | 
| Chris@45 | 393     } | 
| Chris@45 | 394 | 
| Chris@45 | 395 bool | 
| Chris@576 | 396 SVFileReader::readWindow(const QXmlAttributes &) | 
| Chris@45 | 397 { | 
| Chris@576 | 398     // The window element contains window dimensions, which we used to | 
| Chris@576 | 399     // read and size the window accordingly. This was a Bad Idea [tm] | 
| Chris@576 | 400     // and we now do nothing instead. See #1769 Loading window | 
| Chris@576 | 401     // dimensions from session file is a really bad idea | 
| Chris@45 | 402     return true; | 
| Chris@45 | 403 } | 
| Chris@45 | 404 | 
| Chris@45 | 405 void | 
| Chris@45 | 406 SVFileReader::addUnaddedModels() | 
| Chris@45 | 407 { | 
| Chris@45 | 408     std::set<Model *> unaddedModels; | 
| Chris@45 | 409 | 
| Chris@45 | 410     for (std::map<int, Model *>::iterator i = m_models.begin(); | 
| Chris@45 | 411          i != m_models.end(); ++i) { | 
| Chris@45 | 412         if (m_addedModels.find(i->second) == m_addedModels.end()) { | 
| Chris@45 | 413             unaddedModels.insert(i->second); | 
| Chris@45 | 414         } | 
| Chris@45 | 415     } | 
| Chris@45 | 416 | 
| Chris@45 | 417     for (std::set<Model *>::iterator i = unaddedModels.begin(); | 
| Chris@45 | 418          i != unaddedModels.end(); ++i) { | 
| Chris@212 | 419         Model *model = *i; | 
| Chris@212 | 420         // don't want to add these models, because their lifespans | 
| Chris@212 | 421         // are entirely dictated by the models that "own" them even | 
| Chris@212 | 422         // though they were read independently from the .sv file. | 
| Chris@212 | 423         // (pity we don't have a nicer way) | 
| Chris@212 | 424         if (!dynamic_cast<PathModel *>(model) && | 
| Chris@212 | 425             !dynamic_cast<AlignmentModel *>(model)) { | 
| Chris@212 | 426             m_document->addImportedModel(model); | 
| Chris@212 | 427         } | 
| Chris@212 | 428         // but we add all models here, so they don't get deleted | 
| Chris@212 | 429         // when the file loader is destroyed | 
| Chris@212 | 430         m_addedModels.insert(model); | 
| Chris@45 | 431     } | 
| Chris@45 | 432 } | 
| Chris@45 | 433 | 
| Chris@45 | 434 bool | 
| Chris@45 | 435 SVFileReader::readModel(const QXmlAttributes &attributes) | 
| Chris@45 | 436 { | 
| Chris@45 | 437     bool ok = false; | 
| Chris@45 | 438 | 
| Chris@45 | 439     READ_MANDATORY(int, id, toInt); | 
| Chris@45 | 440 | 
| Chris@45 | 441     if (haveModel(id)) { | 
| Chris@601 | 442         SVCERR << "WARNING: SV-XML: Ignoring duplicate model id " << id | 
| Chris@595 | 443                   << endl; | 
| Chris@595 | 444         return false; | 
| Chris@45 | 445     } | 
| Chris@45 | 446 | 
| Chris@45 | 447     QString name = attributes.value("name"); | 
| Chris@45 | 448 | 
| Chris@233 | 449     SVDEBUG << "SVFileReader::readModel: model name \"" << name << "\"" << endl; | 
| Chris@45 | 450 | 
| Chris@436 | 451     READ_MANDATORY(double, sampleRate, toDouble); | 
| Chris@45 | 452 | 
| Chris@45 | 453     QString type = attributes.value("type").trimmed(); | 
| Chris@362 | 454     bool isMainModel = (attributes.value("mainModel").trimmed() == "true"); | 
| Chris@45 | 455 | 
| Chris@45 | 456     if (type == "wavefile") { | 
| Chris@595 | 457 | 
| Chris@45 | 458         WaveFileModel *model = 0; | 
| Chris@45 | 459         FileFinder *ff = FileFinder::getInstance(); | 
| Chris@45 | 460         QString originalPath = attributes.value("file"); | 
| Chris@45 | 461         QString path = ff->find(FileFinder::AudioFile, | 
| Chris@45 | 462                                 originalPath, m_location); | 
| Chris@45 | 463 | 
| Chris@248 | 464         SVDEBUG << "Wave file originalPath = " << originalPath << ", path = " | 
| Chris@248 | 465                   << path << endl; | 
| Chris@248 | 466 | 
| Chris@109 | 467         ProgressDialog dialog(tr("Opening file or URL..."), true, 2000); | 
| Chris@109 | 468         FileSource file(path, &dialog); | 
| Chris@45 | 469         file.waitForStatus(); | 
| Chris@45 | 470 | 
| Chris@45 | 471         if (!file.isOK()) { | 
| Chris@601 | 472             SVCERR << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: " << file.getErrorString() << endl; | 
| Chris@45 | 473         } else if (!file.isAvailable()) { | 
| Chris@601 | 474             SVCERR << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: Source unavailable" << endl; | 
| Chris@45 | 475         } else { | 
| Chris@45 | 476 | 
| Chris@45 | 477             file.waitForData(); | 
| Chris@116 | 478 | 
| Chris@436 | 479             sv_samplerate_t rate = sampleRate; | 
| Chris@116 | 480 | 
| Chris@360 | 481             if (Preferences::getInstance()->getFixedSampleRate() != 0) { | 
| Chris@360 | 482                 rate = Preferences::getInstance()->getFixedSampleRate(); | 
| Chris@362 | 483             } else if (rate == 0 && | 
| Chris@362 | 484                        !isMainModel && | 
| Chris@360 | 485                        Preferences::getInstance()->getResampleOnLoad()) { | 
| Chris@116 | 486                 WaveFileModel *mm = m_document->getMainModel(); | 
| Chris@116 | 487                 if (mm) rate = mm->getSampleRate(); | 
| Chris@116 | 488             } | 
| Chris@116 | 489 | 
| Chris@479 | 490             model = new ReadOnlyWaveFileModel(file, rate); | 
| Chris@45 | 491             if (!model->isOK()) { | 
| Chris@45 | 492                 delete model; | 
| Chris@45 | 493                 model = 0; | 
| Chris@45 | 494             } | 
| Chris@45 | 495         } | 
| Chris@45 | 496 | 
| Chris@601 | 497         if (!model) { | 
| Chris@601 | 498             m_document->setIncomplete(true); | 
| Chris@601 | 499             return false; | 
| Chris@601 | 500         } | 
| Chris@45 | 501 | 
| Chris@45 | 502         model->setObjectName(name); | 
| Chris@595 | 503         m_models[id] = model; | 
| Chris@595 | 504         if (isMainModel) { | 
| Chris@595 | 505             m_document->setMainModel(model); | 
| Chris@595 | 506             m_addedModels.insert(model); | 
| Chris@595 | 507         } | 
| Chris@595 | 508         // Derived models will be added when their derivation | 
| Chris@595 | 509         // is found. | 
| Chris@45 | 510 | 
| Chris@595 | 511         return true; | 
| Chris@45 | 512 | 
| Chris@45 | 513     } else if (type == "dense") { | 
| Chris@595 | 514 | 
| Chris@595 | 515         READ_MANDATORY(int, dimensions, toInt); | 
| Chris@595 | 516 | 
| Chris@595 | 517         // Currently the only dense model we support here is the dense | 
| Chris@595 | 518         // 3d model.  Dense time-value models are always file-backed | 
| Chris@595 | 519         // waveform data, at this point, and they come in as wavefile | 
| Chris@595 | 520         // models. | 
| Chris@595 | 521 | 
| Chris@595 | 522         if (dimensions == 3) { | 
| Chris@595 | 523 | 
| Chris@595 | 524             READ_MANDATORY(int, windowSize, toInt); | 
| Chris@595 | 525             READ_MANDATORY(int, yBinCount, toInt); | 
| Chris@595 | 526 | 
| Chris@45 | 527             EditableDenseThreeDimensionalModel *model = | 
| Chris@595 | 528                 new EditableDenseThreeDimensionalModel | 
| Chris@153 | 529                 (sampleRate, windowSize, yBinCount, | 
| Chris@153 | 530                  EditableDenseThreeDimensionalModel::NoCompression); | 
| Chris@595 | 531 | 
| Chris@595 | 532             float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 
| Chris@595 | 533             if (ok) model->setMinimumLevel(minimum); | 
| Chris@595 | 534 | 
| Chris@595 | 535             float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 
| Chris@595 | 536             if (ok) model->setMaximumLevel(maximum); | 
| Chris@45 | 537 | 
| Chris@595 | 538             int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@595 | 539             if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 540 | 
| Chris@181 | 541             int startFrame = attributes.value("startFrame").trimmed().toInt(&ok); | 
| Chris@181 | 542             if (ok) model->setStartFrame(startFrame); | 
| Chris@181 | 543 | 
| Chris@45 | 544             model->setObjectName(name); | 
| Chris@595 | 545             m_models[id] = model; | 
| Chris@595 | 546             return true; | 
| Chris@45 | 547 | 
| Chris@595 | 548         } else { | 
| Chris@45 | 549 | 
| Chris@601 | 550             SVCERR << "WARNING: SV-XML: Unexpected dense model dimension (" | 
| Chris@595 | 551                       << dimensions << ")" << endl; | 
| Chris@595 | 552         } | 
| Chris@45 | 553     } else if (type == "sparse") { | 
| Chris@45 | 554 | 
| Chris@595 | 555         READ_MANDATORY(int, dimensions, toInt); | 
| Chris@595 | 556 | 
| Chris@595 | 557         if (dimensions == 1) { | 
| Chris@595 | 558 | 
| Chris@595 | 559             READ_MANDATORY(int, resolution, toInt); | 
| Chris@45 | 560 | 
| Chris@45 | 561             if (attributes.value("subtype") == "image") { | 
| Chris@45 | 562 | 
| Chris@45 | 563                 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 
| Chris@45 | 564                 ImageModel *model = new ImageModel(sampleRate, resolution, | 
| Chris@45 | 565                                                    notifyOnAdd); | 
| Chris@45 | 566                 model->setObjectName(name); | 
| Chris@45 | 567                 m_models[id] = model; | 
| Chris@45 | 568 | 
| Chris@45 | 569             } else { | 
| Chris@45 | 570 | 
| Chris@45 | 571                 SparseOneDimensionalModel *model = new SparseOneDimensionalModel | 
| Chris@45 | 572                     (sampleRate, resolution); | 
| Chris@45 | 573                 model->setObjectName(name); | 
| Chris@45 | 574                 m_models[id] = model; | 
| Chris@45 | 575             } | 
| Chris@45 | 576 | 
| Chris@595 | 577             int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@595 | 578             if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 579 | 
| Chris@595 | 580             return true; | 
| Chris@45 | 581 | 
| Chris@595 | 582         } else if (dimensions == 2 || dimensions == 3) { | 
| Chris@595 | 583 | 
| Chris@595 | 584             READ_MANDATORY(int, resolution, toInt); | 
| Chris@45 | 585 | 
| Chris@45 | 586             bool haveMinMax = true; | 
| Chris@595 | 587             float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 
| Chris@45 | 588             if (!ok) haveMinMax = false; | 
| Chris@595 | 589             float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 
| Chris@45 | 590             if (!ok) haveMinMax = false; | 
| Chris@45 | 591 | 
| Chris@595 | 592             float valueQuantization = | 
| Chris@595 | 593                 attributes.value("valueQuantization").trimmed().toFloat(&ok); | 
| Chris@45 | 594 | 
| Chris@595 | 595             bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 
| Chris@45 | 596 | 
| Chris@45 | 597             QString units = attributes.value("units"); | 
| Chris@45 | 598 | 
| Chris@595 | 599             if (dimensions == 2) { | 
| Chris@595 | 600                 if (attributes.value("subtype") == "text") { | 
| Chris@595 | 601                     TextModel *model = new TextModel | 
| Chris@595 | 602                         (sampleRate, resolution, notifyOnAdd); | 
| Chris@45 | 603                     model->setObjectName(name); | 
| Chris@595 | 604                     m_models[id] = model; | 
| Chris@111 | 605                 } else if (attributes.value("subtype") == "path") { | 
| Chris@111 | 606                     PathModel *model = new PathModel | 
| Chris@111 | 607                         (sampleRate, resolution, notifyOnAdd); | 
| Chris@111 | 608                     model->setObjectName(name); | 
| Chris@111 | 609                     m_models[id] = model; | 
| Chris@595 | 610                 } else { | 
| Chris@595 | 611                     SparseTimeValueModel *model; | 
| Chris@45 | 612                     if (haveMinMax) { | 
| Chris@45 | 613                         model = new SparseTimeValueModel | 
| Chris@45 | 614                             (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@45 | 615                     } else { | 
| Chris@45 | 616                         model = new SparseTimeValueModel | 
| Chris@45 | 617                             (sampleRate, resolution, notifyOnAdd); | 
| Chris@45 | 618                     } | 
| Chris@45 | 619                     model->setScaleUnits(units); | 
| Chris@45 | 620                     model->setObjectName(name); | 
| Chris@595 | 621                     m_models[id] = model; | 
| Chris@595 | 622                 } | 
| Chris@595 | 623             } else { | 
| Chris@137 | 624                 if (attributes.value("subtype") == "region") { | 
| Chris@137 | 625                     RegionModel *model; | 
| Chris@137 | 626                     if (haveMinMax) { | 
| Chris@137 | 627                         model = new RegionModel | 
| Chris@137 | 628                             (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@137 | 629                     } else { | 
| Chris@137 | 630                         model = new RegionModel | 
| Chris@137 | 631                             (sampleRate, resolution, notifyOnAdd); | 
| Chris@137 | 632                     } | 
| Chris@137 | 633                     model->setValueQuantization(valueQuantization); | 
| Chris@137 | 634                     model->setScaleUnits(units); | 
| Chris@137 | 635                     model->setObjectName(name); | 
| Chris@137 | 636                     m_models[id] = model; | 
| Chris@343 | 637                 } else if (attributes.value("subtype") == "flexinote") { | 
| Chris@343 | 638                     FlexiNoteModel *model; | 
| Chris@343 | 639                     if (haveMinMax) { | 
| Chris@343 | 640                         model = new FlexiNoteModel | 
| Chris@343 | 641                             (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@343 | 642                     } else { | 
| Chris@343 | 643                         model = new FlexiNoteModel | 
| Chris@343 | 644                             (sampleRate, resolution, notifyOnAdd); | 
| Chris@343 | 645                     } | 
| Chris@343 | 646                     model->setValueQuantization(valueQuantization); | 
| Chris@343 | 647                     model->setScaleUnits(units); | 
| Chris@343 | 648                     model->setObjectName(name); | 
| Chris@343 | 649                     m_models[id] = model; | 
| Chris@45 | 650                 } else { | 
| Chris@137 | 651                     // note models written out by SV 1.3 and earlier | 
| Chris@137 | 652                     // have no subtype, so we can't test that | 
| Chris@137 | 653                     NoteModel *model; | 
| Chris@137 | 654                     if (haveMinMax) { | 
| Chris@137 | 655                         model = new NoteModel | 
| Chris@137 | 656                             (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@137 | 657                     } else { | 
| Chris@137 | 658                         model = new NoteModel | 
| Chris@137 | 659                             (sampleRate, resolution, notifyOnAdd); | 
| Chris@137 | 660                     } | 
| Chris@137 | 661                     model->setValueQuantization(valueQuantization); | 
| Chris@137 | 662                     model->setScaleUnits(units); | 
| Chris@137 | 663                     model->setObjectName(name); | 
| Chris@137 | 664                     m_models[id] = model; | 
| Chris@45 | 665                 } | 
| Chris@137 | 666             } | 
| Chris@45 | 667 | 
| Chris@595 | 668             int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@595 | 669             if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 670 | 
| Chris@595 | 671             return true; | 
| Chris@45 | 672 | 
| Chris@595 | 673         } else { | 
| Chris@45 | 674 | 
| Chris@601 | 675             SVCERR << "WARNING: SV-XML: Unexpected sparse model dimension (" | 
| Chris@595 | 676                       << dimensions << ")" << endl; | 
| Chris@595 | 677         } | 
| Chris@111 | 678 | 
| Chris@111 | 679     } else if (type == "alignment") { | 
| Chris@111 | 680 | 
| Chris@111 | 681         READ_MANDATORY(int, reference, toInt); | 
| Chris@111 | 682         READ_MANDATORY(int, aligned, toInt); | 
| Chris@111 | 683         READ_MANDATORY(int, path, toInt); | 
| Chris@111 | 684 | 
| Chris@111 | 685         Model *refModel = 0, *alignedModel = 0, *pathModel = 0; | 
| Chris@111 | 686 | 
| Chris@111 | 687         if (m_models.find(reference) != m_models.end()) { | 
| Chris@111 | 688             refModel = m_models[reference]; | 
| Chris@111 | 689         } else { | 
| Chris@601 | 690             SVCERR << "WARNING: SV-XML: Unknown reference model id " | 
| Chris@111 | 691                       << reference << " in alignment model id " << id | 
| Chris@293 | 692                       << endl; | 
| Chris@111 | 693         } | 
| Chris@111 | 694 | 
| Chris@111 | 695         if (m_models.find(aligned) != m_models.end()) { | 
| Chris@111 | 696             alignedModel = m_models[aligned]; | 
| Chris@111 | 697         } else { | 
| Chris@601 | 698             SVCERR << "WARNING: SV-XML: Unknown aligned model id " | 
| Chris@111 | 699                       << aligned << " in alignment model id " << id | 
| Chris@293 | 700                       << endl; | 
| Chris@111 | 701         } | 
| Chris@111 | 702 | 
| Chris@111 | 703         if (m_models.find(path) != m_models.end()) { | 
| Chris@111 | 704             pathModel = m_models[path]; | 
| Chris@111 | 705         } else { | 
| Chris@601 | 706             SVCERR << "WARNING: SV-XML: Unknown path model id " | 
| Chris@111 | 707                       << path << " in alignment model id " << id | 
| Chris@293 | 708                       << endl; | 
| Chris@111 | 709         } | 
| Chris@111 | 710 | 
| Chris@111 | 711         if (refModel && alignedModel && pathModel) { | 
| Chris@111 | 712             AlignmentModel *model = new AlignmentModel | 
| Chris@111 | 713                 (refModel, alignedModel, 0, 0); | 
| Chris@111 | 714             PathModel *pm = dynamic_cast<PathModel *>(pathModel); | 
| Chris@111 | 715             if (!pm) { | 
| Chris@601 | 716                 SVCERR << "WARNING: SV-XML: Model id " << path | 
| Chris@111 | 717                           << " referenced as path for alignment " << id | 
| Chris@293 | 718                           << " is not a path model" << endl; | 
| Chris@111 | 719             } else { | 
| Chris@111 | 720                 model->setPath(pm); | 
| Chris@111 | 721                 pm->setCompletion(100); | 
| Chris@111 | 722             } | 
| Chris@111 | 723             model->setObjectName(name); | 
| Chris@111 | 724             m_models[id] = model; | 
| Chris@111 | 725             alignedModel->setAlignment(model); | 
| Chris@111 | 726             return true; | 
| Chris@111 | 727         } | 
| Chris@111 | 728 | 
| Chris@45 | 729     } else { | 
| Chris@45 | 730 | 
| Chris@590 | 731         SVCERR << "WARNING: SV-XML: Unexpected model type \"" | 
| Chris@590 | 732                << type << "\" for model id " << id << endl; | 
| Chris@45 | 733     } | 
| Chris@45 | 734 | 
| Chris@45 | 735     return false; | 
| Chris@45 | 736 } | 
| Chris@45 | 737 | 
| Chris@45 | 738 bool | 
| Chris@45 | 739 SVFileReader::readView(const QXmlAttributes &attributes) | 
| Chris@45 | 740 { | 
| Chris@45 | 741     QString type = attributes.value("type"); | 
| Chris@45 | 742     m_currentPane = 0; | 
| Chris@45 | 743 | 
| Chris@45 | 744     if (type != "pane") { | 
| Chris@601 | 745         SVCERR << "WARNING: SV-XML: Unexpected view type \"" | 
| Chris@595 | 746                   << type << "\"" << endl; | 
| Chris@595 | 747         return false; | 
| Chris@45 | 748     } | 
| Chris@45 | 749 | 
| Chris@45 | 750     m_currentPane = m_paneCallback.addPane(); | 
| Chris@45 | 751 | 
| Chris@601 | 752     SVCERR << "SVFileReader::addPane: pane is " << m_currentPane << endl; | 
| Chris@342 | 753 | 
| Chris@45 | 754     if (!m_currentPane) { | 
| Chris@601 | 755         SVCERR << "WARNING: SV-XML: Internal error: Failed to add pane!" | 
| Chris@595 | 756                   << endl; | 
| Chris@595 | 757         return false; | 
| Chris@45 | 758     } | 
| Chris@45 | 759 | 
| Chris@45 | 760     bool ok = false; | 
| Chris@45 | 761 | 
| Chris@45 | 762     View *view = m_currentPane; | 
| Chris@45 | 763 | 
| Chris@45 | 764     // The view properties first | 
| Chris@45 | 765 | 
| Chris@366 | 766     READ_MANDATORY(int, centre, toInt); | 
| Chris@366 | 767     READ_MANDATORY(int, zoom, toInt); | 
| Chris@45 | 768     READ_MANDATORY(int, followPan, toInt); | 
| Chris@45 | 769     READ_MANDATORY(int, followZoom, toInt); | 
| Chris@45 | 770     QString tracking = attributes.value("tracking"); | 
| Chris@45 | 771 | 
| Chris@624 | 772     ZoomLevel zoomLevel; | 
| Chris@624 | 773     int deepZoom = attributes.value("deepZoom").trimmed().toInt(&ok); | 
| Chris@624 | 774     if (ok && zoom == 1 && deepZoom > 1) { | 
| Chris@624 | 775         zoomLevel = { ZoomLevel::PixelsPerFrame, deepZoom }; | 
| Chris@624 | 776     } else { | 
| Chris@624 | 777         zoomLevel = { ZoomLevel::FramesPerPixel, zoom }; | 
| Chris@624 | 778     } | 
| Chris@624 | 779 | 
| Chris@45 | 780     // Specify the follow modes before we set the actual values | 
| Chris@45 | 781     view->setFollowGlobalPan(followPan); | 
| Chris@45 | 782     view->setFollowGlobalZoom(followZoom); | 
| Chris@45 | 783     view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous : | 
| Chris@595 | 784                             tracking == "page" ? PlaybackScrollPageWithCentre : | 
| Chris@595 | 785                             tracking == "daw" ? PlaybackScrollPage | 
| Chris@595 | 786                             : PlaybackIgnore); | 
| Chris@45 | 787 | 
| Chris@45 | 788     // Then set these values | 
| Chris@45 | 789     view->setCentreFrame(centre); | 
| Chris@624 | 790     view->setZoomLevel(zoomLevel); | 
| Chris@45 | 791 | 
| Chris@45 | 792     // And pane properties | 
| Chris@45 | 793     READ_MANDATORY(int, centreLineVisible, toInt); | 
| Chris@45 | 794     m_currentPane->setCentreLineVisible(centreLineVisible); | 
| Chris@45 | 795 | 
| Chris@45 | 796     int height = attributes.value("height").toInt(&ok); | 
| Chris@45 | 797     if (ok) { | 
| Chris@595 | 798         m_currentPane->resize(m_currentPane->width(), height); | 
| Chris@45 | 799     } | 
| Chris@45 | 800 | 
| Chris@45 | 801     return true; | 
| Chris@45 | 802 } | 
| Chris@45 | 803 | 
| Chris@45 | 804 bool | 
| Chris@45 | 805 SVFileReader::readLayer(const QXmlAttributes &attributes) | 
| Chris@45 | 806 { | 
| Chris@45 | 807     QString type = attributes.value("type"); | 
| Chris@45 | 808 | 
| Chris@45 | 809     int id; | 
| Chris@45 | 810     bool ok = false; | 
| Chris@45 | 811     id = attributes.value("id").trimmed().toInt(&ok); | 
| Chris@45 | 812 | 
| Chris@45 | 813     if (!ok) { | 
| Chris@601 | 814         SVCERR << "WARNING: SV-XML: No layer id for layer of type \"" | 
| Chris@595 | 815                   << type | 
| Chris@595 | 816                   << "\"" << endl; | 
| Chris@595 | 817         return false; | 
| Chris@45 | 818     } | 
| Chris@45 | 819 | 
| Chris@45 | 820     Layer *layer = 0; | 
| Chris@45 | 821     bool isNewLayer = false; | 
| Chris@45 | 822 | 
| Chris@45 | 823     // Layers are expected to be defined in layer elements in the data | 
| Chris@45 | 824     // section, and referred to in layer elements in the view | 
| Chris@45 | 825     // sections.  So if we're in the data section, we expect this | 
| Chris@45 | 826     // layer not to exist already; if we're in the view section, we | 
| Chris@45 | 827     // expect it to exist. | 
| Chris@45 | 828 | 
| Chris@45 | 829     if (m_inData) { | 
| Chris@45 | 830 | 
| Chris@595 | 831         if (m_layers.find(id) != m_layers.end()) { | 
| Chris@601 | 832             SVCERR << "WARNING: SV-XML: Ignoring duplicate layer id " << id | 
| Chris@595 | 833                       << " in data section" << endl; | 
| Chris@595 | 834             return false; | 
| Chris@595 | 835         } | 
| Chris@45 | 836 | 
| Chris@595 | 837         layer = m_layers[id] = m_document->createLayer | 
| Chris@595 | 838             (LayerFactory::getInstance()->getLayerTypeForName(type)); | 
| Chris@45 | 839 | 
| Chris@595 | 840         if (layer) { | 
| Chris@595 | 841             m_layers[id] = layer; | 
| Chris@595 | 842             isNewLayer = true; | 
| Chris@595 | 843         } | 
| Chris@45 | 844 | 
| Chris@45 | 845     } else { | 
| Chris@45 | 846 | 
| Chris@595 | 847         if (!m_currentPane) { | 
| Chris@601 | 848             SVCERR << "WARNING: SV-XML: No current pane for layer " << id | 
| Chris@595 | 849                       << " in view section" << endl; | 
| Chris@595 | 850             return false; | 
| Chris@595 | 851         } | 
| Chris@45 | 852 | 
| Chris@595 | 853         if (m_layers.find(id) != m_layers.end()) { | 
| Chris@595 | 854 | 
| Chris@595 | 855             layer = m_layers[id]; | 
| Chris@595 | 856 | 
| Chris@595 | 857         } else { | 
| Chris@601 | 858             SVCERR << "WARNING: SV-XML: Layer id " << id | 
| Chris@595 | 859                       << " in view section has not been defined -- defining it here" | 
| Chris@595 | 860                       << endl; | 
| Chris@45 | 861 | 
| Chris@595 | 862             layer = m_document->createLayer | 
| Chris@595 | 863                 (LayerFactory::getInstance()->getLayerTypeForName(type)); | 
| Chris@45 | 864 | 
| Chris@595 | 865             if (layer) { | 
| Chris@595 | 866                 m_layers[id] = layer; | 
| Chris@595 | 867                 isNewLayer = true; | 
| Chris@595 | 868             } | 
| Chris@595 | 869         } | 
| Chris@45 | 870     } | 
| Chris@595 | 871 | 
| Chris@45 | 872     if (!layer) { | 
| Chris@601 | 873         SVCERR << "WARNING: SV-XML: Failed to add layer of type \"" | 
| Chris@595 | 874                   << type | 
| Chris@595 | 875                   << "\"" << endl; | 
| Chris@595 | 876         return false; | 
| Chris@45 | 877     } | 
| Chris@45 | 878 | 
| Chris@45 | 879     if (isNewLayer) { | 
| Chris@45 | 880 | 
| Chris@595 | 881         QString name = attributes.value("name"); | 
| Chris@595 | 882         layer->setObjectName(name); | 
| Chris@45 | 883 | 
| Chris@89 | 884         QString presentationName = attributes.value("presentationName"); | 
| Chris@89 | 885         layer->setPresentationName(presentationName); | 
| Chris@89 | 886 | 
| Chris@595 | 887         int modelId; | 
| Chris@595 | 888         bool modelOk = false; | 
| Chris@595 | 889         modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 890 | 
| Chris@595 | 891         if (modelOk) { | 
| Chris@595 | 892             if (haveModel(modelId)) { | 
| Chris@595 | 893                 Model *model = m_models[modelId]; | 
| Chris@595 | 894                 m_document->setModel(layer, model); | 
| Chris@595 | 895             } else { | 
| Chris@601 | 896                 SVCERR << "WARNING: SV-XML: Unknown model id " << modelId | 
| Chris@595 | 897                           << " in layer definition" << endl; | 
| Chris@451 | 898                 if (!layer->canExistWithoutModel()) { | 
| Chris@451 | 899                     // Don't add a layer with an unknown model id | 
| Chris@451 | 900                     // unless it explicitly supports this state | 
| Chris@451 | 901                     m_document->deleteLayer(layer); | 
| Chris@451 | 902                     m_layers[id] = layer = 0; | 
| Chris@451 | 903                     return false; | 
| Chris@451 | 904                 } | 
| Chris@451 | 905             } | 
| Chris@595 | 906         } | 
| Chris@45 | 907 | 
| Chris@447 | 908         if (layer) layer->setProperties(attributes); | 
| Chris@45 | 909     } | 
| Chris@45 | 910 | 
| Chris@447 | 911     if (!m_inData && m_currentPane && layer) { | 
| Chris@45 | 912 | 
| Chris@45 | 913         QString visible = attributes.value("visible"); | 
| Chris@45 | 914         bool dormant = (visible == "false"); | 
| Chris@45 | 915 | 
| Chris@45 | 916         // We need to do this both before and after adding the layer | 
| Chris@45 | 917         // to the view -- we need it to be dormant if appropriate | 
| Chris@45 | 918         // before it's actually added to the view so that any property | 
| Chris@45 | 919         // box gets the right state when it's added, but the add layer | 
| Chris@45 | 920         // command sets dormant to false because it assumes it may be | 
| Chris@45 | 921         // restoring a previously dormant layer, so we need to set it | 
| Chris@45 | 922         // again afterwards too.  Hm | 
| Chris@45 | 923         layer->setLayerDormant(m_currentPane, dormant); | 
| Chris@45 | 924 | 
| Chris@595 | 925         m_document->addLayerToView(m_currentPane, layer); | 
| Chris@45 | 926 | 
| Chris@45 | 927         layer->setLayerDormant(m_currentPane, dormant); | 
| Chris@45 | 928     } | 
| Chris@45 | 929 | 
| Chris@45 | 930     m_currentLayer = layer; | 
| Chris@447 | 931     m_inLayer = (layer != 0); | 
| Chris@45 | 932 | 
| Chris@45 | 933     return true; | 
| Chris@45 | 934 } | 
| Chris@45 | 935 | 
| Chris@45 | 936 bool | 
| Chris@45 | 937 SVFileReader::readDatasetStart(const QXmlAttributes &attributes) | 
| Chris@45 | 938 { | 
| Chris@45 | 939     bool ok = false; | 
| Chris@45 | 940 | 
| Chris@45 | 941     READ_MANDATORY(int, id, toInt); | 
| Chris@45 | 942     READ_MANDATORY(int, dimensions, toInt); | 
| Chris@45 | 943 | 
| Chris@45 | 944     if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) { | 
| Chris@601 | 945         SVCERR << "WARNING: SV-XML: Unwanted dataset " << id << endl; | 
| Chris@595 | 946         return false; | 
| Chris@45 | 947     } | 
| Chris@45 | 948 | 
| Chris@45 | 949     int modelId = m_awaitingDatasets[id]; | 
| Chris@45 | 950 | 
| Chris@45 | 951     Model *model = 0; | 
| Chris@45 | 952     if (haveModel(modelId)) { | 
| Chris@595 | 953         model = m_models[modelId]; | 
| Chris@45 | 954     } else { | 
| Chris@601 | 955         SVCERR << "WARNING: SV-XML: Internal error: Unknown model " << modelId | 
| Chris@595 | 956                   << " expecting dataset " << id << endl; | 
| Chris@595 | 957         return false; | 
| Chris@45 | 958     } | 
| Chris@45 | 959 | 
| Chris@45 | 960     bool good = false; | 
| Chris@45 | 961 | 
| Chris@45 | 962     switch (dimensions) { | 
| Chris@45 | 963     case 1: | 
| Chris@595 | 964         if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true; | 
| Chris@45 | 965         else if (dynamic_cast<ImageModel *>(model)) good = true; | 
| Chris@595 | 966         break; | 
| Chris@45 | 967 | 
| Chris@45 | 968     case 2: | 
| Chris@595 | 969         if (dynamic_cast<SparseTimeValueModel *>(model)) good = true; | 
| Chris@595 | 970         else if (dynamic_cast<TextModel *>(model)) good = true; | 
| Chris@595 | 971         else if (dynamic_cast<PathModel *>(model)) good = true; | 
| Chris@595 | 972         break; | 
| Chris@45 | 973 | 
| Chris@45 | 974     case 3: | 
| Chris@595 | 975         if (dynamic_cast<NoteModel *>(model)) good = true; | 
| Chris@595 | 976         else if (dynamic_cast<FlexiNoteModel *>(model)) good = true; | 
| Chris@595 | 977         else if (dynamic_cast<RegionModel *>(model)) good = true; | 
| Chris@595 | 978         else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) { | 
| Chris@595 | 979             m_datasetSeparator = attributes.value("separator"); | 
| Chris@595 | 980             good = true; | 
| Chris@595 | 981         } | 
| Chris@595 | 982         break; | 
| Chris@45 | 983     } | 
| Chris@45 | 984 | 
| Chris@45 | 985     if (!good) { | 
| Chris@601 | 986         SVCERR << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl; | 
| Chris@595 | 987         m_currentDataset = 0; | 
| Chris@595 | 988         return false; | 
| Chris@45 | 989     } | 
| Chris@45 | 990 | 
| Chris@45 | 991     m_currentDataset = model; | 
| Chris@45 | 992     return true; | 
| Chris@45 | 993 } | 
| Chris@45 | 994 | 
| Chris@45 | 995 bool | 
| Chris@45 | 996 SVFileReader::addPointToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 997 { | 
| Chris@45 | 998     bool ok = false; | 
| Chris@45 | 999 | 
| Chris@45 | 1000     READ_MANDATORY(int, frame, toInt); | 
| Chris@45 | 1001 | 
| Chris@233 | 1002 //    SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl; | 
| Chris@45 | 1003 | 
| Chris@45 | 1004     SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 
| Chris@595 | 1005         (m_currentDataset); | 
| Chris@45 | 1006 | 
| Chris@45 | 1007     if (sodm) { | 
| Chris@601 | 1008 //        SVCERR << "Current dataset is a sparse one dimensional model" << endl; | 
| Chris@595 | 1009         QString label = attributes.value("label"); | 
| Chris@595 | 1010         sodm->addPoint(SparseOneDimensionalModel::Point(frame, label)); | 
| Chris@595 | 1011         return true; | 
| Chris@45 | 1012     } | 
| Chris@45 | 1013 | 
| Chris@45 | 1014     SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *> | 
| Chris@595 | 1015         (m_currentDataset); | 
| Chris@45 | 1016 | 
| Chris@45 | 1017     if (stvm) { | 
| Chris@601 | 1018 //        SVCERR << "Current dataset is a sparse time-value model" << endl; | 
| Chris@595 | 1019         float value = 0.0; | 
| Chris@595 | 1020         value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@595 | 1021         QString label = attributes.value("label"); | 
| Chris@595 | 1022         stvm->addPoint(SparseTimeValueModel::Point(frame, value, label)); | 
| Chris@595 | 1023         return ok; | 
| Chris@45 | 1024     } | 
| Chris@595 | 1025 | 
| Chris@45 | 1026     NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset); | 
| Chris@45 | 1027 | 
| Chris@45 | 1028     if (nm) { | 
| Chris@601 | 1029 //        SVCERR << "Current dataset is a note model" << endl; | 
| Chris@595 | 1030         float value = 0.0; | 
| Chris@595 | 1031         value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@595 | 1032         int duration = 0; | 
| Chris@595 | 1033         duration = attributes.value("duration").trimmed().toInt(&ok); | 
| Chris@595 | 1034         QString label = attributes.value("label"); | 
| Chris@61 | 1035         float level = attributes.value("level").trimmed().toFloat(&ok); | 
| Chris@61 | 1036         if (!ok) { // level is optional | 
| Chris@61 | 1037             level = 1.f; | 
| Chris@61 | 1038             ok = true; | 
| Chris@61 | 1039         } | 
| Chris@595 | 1040         nm->addPoint(NoteModel::Point(frame, value, duration, level, label)); | 
| Chris@595 | 1041         return ok; | 
| Chris@45 | 1042     } | 
| Chris@45 | 1043 | 
| Chris@343 | 1044     FlexiNoteModel *fnm = dynamic_cast<FlexiNoteModel *>(m_currentDataset); | 
| Chris@343 | 1045 | 
| Chris@343 | 1046     if (fnm) { | 
| Chris@601 | 1047 //        SVCERR << "Current dataset is a flexinote model" << endl; | 
| Chris@595 | 1048         float value = 0.0; | 
| Chris@595 | 1049         value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@595 | 1050         int duration = 0; | 
| Chris@595 | 1051         duration = attributes.value("duration").trimmed().toInt(&ok); | 
| Chris@595 | 1052         QString label = attributes.value("label"); | 
| Chris@343 | 1053         float level = attributes.value("level").trimmed().toFloat(&ok); | 
| Chris@343 | 1054         if (!ok) { // level is optional | 
| Chris@343 | 1055             level = 1.f; | 
| Chris@343 | 1056             ok = true; | 
| Chris@343 | 1057         } | 
| Chris@595 | 1058         fnm->addPoint(FlexiNoteModel::Point(frame, value, duration, level, label)); | 
| Chris@595 | 1059         return ok; | 
| Chris@343 | 1060     } | 
| Chris@343 | 1061 | 
| Chris@137 | 1062     RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset); | 
| Chris@137 | 1063 | 
| Chris@137 | 1064     if (rm) { | 
| Chris@601 | 1065 //        SVCERR << "Current dataset is a region model" << endl; | 
| Chris@595 | 1066         float value = 0.0; | 
| Chris@595 | 1067         value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@595 | 1068         int duration = 0; | 
| Chris@595 | 1069         duration = attributes.value("duration").trimmed().toInt(&ok); | 
| Chris@595 | 1070         QString label = attributes.value("label"); | 
| Chris@595 | 1071         rm->addPoint(RegionModel::Point(frame, value, duration, label)); | 
| Chris@595 | 1072         return ok; | 
| Chris@137 | 1073     } | 
| Chris@137 | 1074 | 
| Chris@45 | 1075     TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset); | 
| Chris@45 | 1076 | 
| Chris@45 | 1077     if (tm) { | 
| Chris@601 | 1078 //        SVCERR << "Current dataset is a text model" << endl; | 
| Chris@595 | 1079         float height = 0.0; | 
| Chris@595 | 1080         height = attributes.value("height").trimmed().toFloat(&ok); | 
| Chris@595 | 1081         QString label = attributes.value("label"); | 
| Chris@233 | 1082 //        SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl; | 
| Chris@595 | 1083         tm->addPoint(TextModel::Point(frame, height, label)); | 
| Chris@595 | 1084         return ok; | 
| Chris@45 | 1085     } | 
| Chris@45 | 1086 | 
| Chris@111 | 1087     PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset); | 
| Chris@111 | 1088 | 
| Chris@111 | 1089     if (pm) { | 
| Chris@601 | 1090 //        SVCERR << "Current dataset is a path model" << endl; | 
| Chris@111 | 1091         int mapframe = attributes.value("mapframe").trimmed().toInt(&ok); | 
| Chris@233 | 1092 //        SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl; | 
| Chris@595 | 1093         pm->addPoint(PathModel::Point(frame, mapframe)); | 
| Chris@595 | 1094         return ok; | 
| Chris@111 | 1095     } | 
| Chris@111 | 1096 | 
| Chris@45 | 1097     ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset); | 
| Chris@45 | 1098 | 
| Chris@45 | 1099     if (im) { | 
| Chris@601 | 1100 //        SVCERR << "Current dataset is an image model" << endl; | 
| Chris@595 | 1101         QString image = attributes.value("image"); | 
| Chris@595 | 1102         QString label = attributes.value("label"); | 
| Chris@233 | 1103 //        SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl; | 
| Chris@595 | 1104         im->addPoint(ImageModel::Point(frame, image, label)); | 
| Chris@595 | 1105         return ok; | 
| Chris@45 | 1106     } | 
| Chris@45 | 1107 | 
| Chris@601 | 1108     SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" << endl; | 
| Chris@45 | 1109 | 
| Chris@45 | 1110     return false; | 
| Chris@45 | 1111 } | 
| Chris@45 | 1112 | 
| Chris@45 | 1113 bool | 
| Chris@45 | 1114 SVFileReader::addBinToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 1115 { | 
| Chris@45 | 1116     EditableDenseThreeDimensionalModel *dtdm = | 
| Chris@45 | 1117         dynamic_cast<EditableDenseThreeDimensionalModel *> | 
| Chris@595 | 1118         (m_currentDataset); | 
| Chris@45 | 1119 | 
| Chris@45 | 1120     if (dtdm) { | 
| Chris@45 | 1121 | 
| Chris@595 | 1122         bool ok = false; | 
| Chris@595 | 1123         int n = attributes.value("number").trimmed().toInt(&ok); | 
| Chris@595 | 1124         if (!ok) { | 
| Chris@601 | 1125             SVCERR << "WARNING: SV-XML: Missing or invalid bin number" | 
| Chris@595 | 1126                       << endl; | 
| Chris@595 | 1127             return false; | 
| Chris@595 | 1128         } | 
| Chris@45 | 1129 | 
| Chris@595 | 1130         QString name = attributes.value("name"); | 
| Chris@45 | 1131 | 
| Chris@595 | 1132         dtdm->setBinName(n, name); | 
| Chris@595 | 1133         return true; | 
| Chris@45 | 1134     } | 
| Chris@45 | 1135 | 
| Chris@601 | 1136     SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl; | 
| Chris@45 | 1137 | 
| Chris@45 | 1138     return false; | 
| Chris@45 | 1139 } | 
| Chris@45 | 1140 | 
| Chris@45 | 1141 | 
| Chris@45 | 1142 bool | 
| Chris@45 | 1143 SVFileReader::addRowToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 1144 { | 
| Chris@45 | 1145     m_inRow = false; | 
| Chris@45 | 1146 | 
| Chris@45 | 1147     bool ok = false; | 
| Chris@45 | 1148     m_rowNumber = attributes.value("n").trimmed().toInt(&ok); | 
| Chris@45 | 1149     if (!ok) { | 
| Chris@601 | 1150         SVCERR << "WARNING: SV-XML: Missing or invalid row number" | 
| Chris@595 | 1151                   << endl; | 
| Chris@595 | 1152         return false; | 
| Chris@45 | 1153     } | 
| Chris@45 | 1154 | 
| Chris@45 | 1155     m_inRow = true; | 
| Chris@45 | 1156 | 
| Chris@601 | 1157 //    SVCERR << "SV-XML: In row " << m_rowNumber << endl; | 
| Chris@45 | 1158 | 
| Chris@45 | 1159     return true; | 
| Chris@45 | 1160 } | 
| Chris@45 | 1161 | 
| Chris@45 | 1162 bool | 
| Chris@45 | 1163 SVFileReader::readRowData(const QString &text) | 
| Chris@45 | 1164 { | 
| Chris@45 | 1165     EditableDenseThreeDimensionalModel *dtdm = | 
| Chris@45 | 1166         dynamic_cast<EditableDenseThreeDimensionalModel *> | 
| Chris@595 | 1167         (m_currentDataset); | 
| Chris@45 | 1168 | 
| Chris@45 | 1169     bool warned = false; | 
| Chris@45 | 1170 | 
| Chris@45 | 1171     if (dtdm) { | 
| Chris@595 | 1172         QStringList data = text.split(m_datasetSeparator); | 
| Chris@45 | 1173 | 
| Chris@595 | 1174         DenseThreeDimensionalModel::Column values; | 
| Chris@45 | 1175 | 
| Chris@595 | 1176         for (QStringList::iterator i = data.begin(); i != data.end(); ++i) { | 
| Chris@45 | 1177 | 
| Chris@595 | 1178             if (int(values.size()) == dtdm->getHeight()) { | 
| Chris@595 | 1179                 if (!warned) { | 
| Chris@601 | 1180                     SVCERR << "WARNING: SV-XML: Too many y-bins in 3-D dataset row " | 
| Chris@595 | 1181                               << m_rowNumber << endl; | 
| Chris@595 | 1182                     warned = true; | 
| Chris@595 | 1183                 } | 
| Chris@595 | 1184             } | 
| Chris@45 | 1185 | 
| Chris@595 | 1186             bool ok; | 
| Chris@595 | 1187             float value = i->toFloat(&ok); | 
| Chris@595 | 1188             if (!ok) { | 
| Chris@601 | 1189                 SVCERR << "WARNING: SV-XML: Bad floating-point value " | 
| Chris@595 | 1190                           << i->toLocal8Bit().data() | 
| Chris@595 | 1191                           << " in row data" << endl; | 
| Chris@595 | 1192             } else { | 
| Chris@595 | 1193                 values.push_back(value); | 
| Chris@595 | 1194             } | 
| Chris@595 | 1195         } | 
| Chris@45 | 1196 | 
| Chris@595 | 1197         dtdm->setColumn(m_rowNumber, values); | 
| Chris@595 | 1198         return true; | 
| Chris@45 | 1199     } | 
| Chris@45 | 1200 | 
| Chris@601 | 1201     SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; | 
| Chris@45 | 1202 | 
| Chris@45 | 1203     return false; | 
| Chris@45 | 1204 } | 
| Chris@45 | 1205 | 
| Chris@45 | 1206 bool | 
| Chris@45 | 1207 SVFileReader::readDerivation(const QXmlAttributes &attributes) | 
| Chris@45 | 1208 { | 
| Chris@45 | 1209     int modelId = 0; | 
| Chris@45 | 1210     bool modelOk = false; | 
| Chris@45 | 1211     modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 1212 | 
| Chris@45 | 1213     if (!modelOk) { | 
| Chris@601 | 1214         SVCERR << "WARNING: SV-XML: No model id specified for derivation" << endl; | 
| Chris@595 | 1215         return false; | 
| Chris@45 | 1216     } | 
| Chris@45 | 1217 | 
| Chris@45 | 1218     if (haveModel(modelId)) { | 
| Chris@45 | 1219         m_currentDerivedModel = m_models[modelId]; | 
| Chris@45 | 1220     } else { | 
| Chris@45 | 1221         // we'll regenerate the model when the derivation element ends | 
| Chris@45 | 1222         m_currentDerivedModel = 0; | 
| Chris@45 | 1223     } | 
| Chris@45 | 1224 | 
| Chris@45 | 1225     m_currentDerivedModelId = modelId; | 
| Chris@45 | 1226 | 
| Chris@45 | 1227     int sourceId = 0; | 
| Chris@45 | 1228     bool sourceOk = false; | 
| Chris@45 | 1229     sourceId = attributes.value("source").trimmed().toInt(&sourceOk); | 
| Chris@45 | 1230 | 
| Chris@45 | 1231     if (sourceOk && haveModel(sourceId)) { | 
| Chris@72 | 1232         m_currentTransformSource = m_models[sourceId]; | 
| Chris@45 | 1233     } else { | 
| Chris@585 | 1234         SVDEBUG << "NOTE: SV-XML: Can't find a model with id " << sourceId | 
| Chris@585 | 1235                 << " for derivation source, falling back to main model" << endl; | 
| Chris@72 | 1236         m_currentTransformSource = m_document->getMainModel(); | 
| Chris@45 | 1237     } | 
| Chris@45 | 1238 | 
| Chris@72 | 1239     m_currentTransform = Transform(); | 
| Chris@45 | 1240 | 
| Chris@45 | 1241     bool ok = false; | 
| Chris@45 | 1242     int channel = attributes.value("channel").trimmed().toInt(&ok); | 
| Chris@72 | 1243     if (ok) m_currentTransformChannel = channel; | 
| Chris@72 | 1244     else m_currentTransformChannel = -1; | 
| Chris@45 | 1245 | 
| Chris@72 | 1246     QString type = attributes.value("type"); | 
| Chris@72 | 1247 | 
| Chris@72 | 1248     if (type == "transform") { | 
| Chris@72 | 1249         m_currentTransformIsNewStyle = true; | 
| Chris@72 | 1250         return true; | 
| Chris@72 | 1251     } else { | 
| Chris@72 | 1252         m_currentTransformIsNewStyle = false; | 
| Chris@233 | 1253         SVDEBUG << "NOTE: SV-XML: Reading old-style derivation element" | 
| Chris@229 | 1254                   << endl; | 
| Chris@72 | 1255     } | 
| Chris@72 | 1256 | 
| Chris@72 | 1257     QString transformId = attributes.value("transform"); | 
| Chris@72 | 1258 | 
| Chris@72 | 1259     m_currentTransform.setIdentifier(transformId); | 
| Chris@45 | 1260 | 
| Chris@45 | 1261     int stepSize = attributes.value("stepSize").trimmed().toInt(&ok); | 
| Chris@72 | 1262     if (ok) m_currentTransform.setStepSize(stepSize); | 
| Chris@45 | 1263 | 
| Chris@45 | 1264     int blockSize = attributes.value("blockSize").trimmed().toInt(&ok); | 
| Chris@72 | 1265     if (ok) m_currentTransform.setBlockSize(blockSize); | 
| Chris@45 | 1266 | 
| Chris@45 | 1267     int windowType = attributes.value("windowType").trimmed().toInt(&ok); | 
| Chris@72 | 1268     if (ok) m_currentTransform.setWindowType(WindowType(windowType)); | 
| Chris@72 | 1269 | 
| Chris@72 | 1270     if (!m_currentTransformSource) return true; | 
| Chris@45 | 1271 | 
| Chris@45 | 1272     QString startFrameStr = attributes.value("startFrame"); | 
| Chris@45 | 1273     QString durationStr = attributes.value("duration"); | 
| Chris@45 | 1274 | 
| Chris@366 | 1275     int startFrame = 0; | 
| Chris@366 | 1276     int duration = 0; | 
| Chris@45 | 1277 | 
| Chris@45 | 1278     if (startFrameStr != "") { | 
| Chris@45 | 1279         startFrame = startFrameStr.trimmed().toInt(&ok); | 
| Chris@45 | 1280         if (!ok) startFrame = 0; | 
| Chris@45 | 1281     } | 
| Chris@45 | 1282     if (durationStr != "") { | 
| Chris@45 | 1283         duration = durationStr.trimmed().toInt(&ok); | 
| Chris@45 | 1284         if (!ok) duration = 0; | 
| Chris@45 | 1285     } | 
| Chris@45 | 1286 | 
| Chris@72 | 1287     m_currentTransform.setStartTime | 
| Chris@72 | 1288         (RealTime::frame2RealTime | 
| Chris@72 | 1289          (startFrame, m_currentTransformSource->getSampleRate())); | 
| Chris@72 | 1290 | 
| Chris@72 | 1291     m_currentTransform.setDuration | 
| Chris@72 | 1292         (RealTime::frame2RealTime | 
| Chris@72 | 1293          (duration, m_currentTransformSource->getSampleRate())); | 
| Chris@45 | 1294 | 
| Chris@45 | 1295     return true; | 
| Chris@45 | 1296 } | 
| Chris@45 | 1297 | 
| Chris@45 | 1298 bool | 
| Chris@45 | 1299 SVFileReader::readPlayParameters(const QXmlAttributes &attributes) | 
| Chris@45 | 1300 { | 
| Chris@45 | 1301     m_currentPlayParameters = 0; | 
| Chris@45 | 1302 | 
| Chris@45 | 1303     int modelId = 0; | 
| Chris@45 | 1304     bool modelOk = false; | 
| Chris@45 | 1305     modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 1306 | 
| Chris@45 | 1307     if (!modelOk) { | 
| Chris@601 | 1308         SVCERR << "WARNING: SV-XML: No model id specified for play parameters" << endl; | 
| Chris@595 | 1309         return false; | 
| Chris@45 | 1310     } | 
| Chris@45 | 1311 | 
| Chris@45 | 1312     if (haveModel(modelId)) { | 
| Chris@45 | 1313 | 
| Chris@45 | 1314         bool ok = false; | 
| Chris@45 | 1315 | 
| Chris@45 | 1316         PlayParameters *parameters = PlayParameterRepository::getInstance()-> | 
| Chris@45 | 1317             getPlayParameters(m_models[modelId]); | 
| Chris@45 | 1318 | 
| Chris@45 | 1319         if (!parameters) { | 
| Chris@601 | 1320             SVCERR << "WARNING: SV-XML: Play parameters for model " | 
| Chris@45 | 1321                       << modelId | 
| Chris@45 | 1322                       << " not found - has model been added to document?" | 
| Chris@293 | 1323                       << endl; | 
| Chris@45 | 1324             return false; | 
| Chris@45 | 1325         } | 
| Chris@45 | 1326 | 
| Chris@45 | 1327         bool muted = (attributes.value("mute").trimmed() == "true"); | 
| Chris@45 | 1328         parameters->setPlayMuted(muted); | 
| Chris@45 | 1329 | 
| Chris@45 | 1330         float pan = attributes.value("pan").toFloat(&ok); | 
| Chris@45 | 1331         if (ok) parameters->setPlayPan(pan); | 
| Chris@45 | 1332 | 
| Chris@45 | 1333         float gain = attributes.value("gain").toFloat(&ok); | 
| Chris@45 | 1334         if (ok) parameters->setPlayGain(gain); | 
| Chris@45 | 1335 | 
| Chris@309 | 1336         QString clipId = attributes.value("clipId"); | 
| Chris@309 | 1337         if (clipId != "") parameters->setPlayClipId(clipId); | 
| Chris@45 | 1338 | 
| Chris@45 | 1339         m_currentPlayParameters = parameters; | 
| Chris@45 | 1340 | 
| Chris@601 | 1341 //        SVCERR << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl; | 
| Chris@45 | 1342 | 
| Chris@45 | 1343     } else { | 
| Chris@45 | 1344 | 
| Chris@601 | 1345         SVCERR << "WARNING: SV-XML: Unknown model " << modelId | 
| Chris@595 | 1346                   << " for play parameters" << endl; | 
| Chris@45 | 1347         return false; | 
| Chris@45 | 1348     } | 
| Chris@45 | 1349 | 
| Chris@45 | 1350     return true; | 
| Chris@45 | 1351 } | 
| Chris@45 | 1352 | 
| Chris@45 | 1353 bool | 
| Chris@45 | 1354 SVFileReader::readPlugin(const QXmlAttributes &attributes) | 
| Chris@45 | 1355 { | 
| Chris@308 | 1356     if (m_currentDerivedModelId >= 0) { | 
| Chris@308 | 1357         return readPluginForTransform(attributes); | 
| Chris@308 | 1358     } else if (m_currentPlayParameters) { | 
| Chris@308 | 1359         return readPluginForPlayback(attributes); | 
| Chris@308 | 1360     } else { | 
| Chris@601 | 1361         SVCERR << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl; | 
| Chris@45 | 1362         return false; | 
| Chris@45 | 1363     } | 
| Chris@308 | 1364 } | 
| Chris@45 | 1365 | 
| Chris@308 | 1366 bool | 
| Chris@308 | 1367 SVFileReader::readPluginForTransform(const QXmlAttributes &attributes) | 
| Chris@308 | 1368 { | 
| Chris@308 | 1369     if (m_currentTransformIsNewStyle) { | 
| Chris@308 | 1370         // Not needed, we have the transform element instead | 
| Chris@72 | 1371         return true; | 
| Chris@72 | 1372     } | 
| Chris@72 | 1373 | 
| Chris@45 | 1374     QString configurationXml = "<plugin"; | 
| Chris@308 | 1375 | 
| Chris@45 | 1376     for (int i = 0; i < attributes.length(); ++i) { | 
| Chris@45 | 1377         configurationXml += QString(" %1=\"%2\"") | 
| Chris@45 | 1378             .arg(attributes.qName(i)) | 
| Chris@45 | 1379             .arg(XmlExportable::encodeEntities(attributes.value(i))); | 
| Chris@45 | 1380     } | 
| Chris@45 | 1381 | 
| Chris@45 | 1382     configurationXml += "/>"; | 
| Chris@45 | 1383 | 
| Chris@308 | 1384     TransformFactory::getInstance()-> | 
| Chris@308 | 1385         setParametersFromPluginConfigurationXml(m_currentTransform, | 
| Chris@308 | 1386                                                 configurationXml); | 
| Chris@308 | 1387     return true; | 
| Chris@308 | 1388 } | 
| Chris@308 | 1389 | 
| Chris@308 | 1390 bool | 
| Chris@308 | 1391 SVFileReader::readPluginForPlayback(const QXmlAttributes &attributes) | 
| Chris@308 | 1392 { | 
| Chris@308 | 1393     // Obsolete but supported for compatibility | 
| Chris@308 | 1394 | 
| Chris@308 | 1395     QString ident = attributes.value("identifier"); | 
| Chris@308 | 1396     if (ident == "sample_player") { | 
| Chris@309 | 1397         QString clipId = attributes.value("program"); | 
| Chris@309 | 1398         if (clipId != "") m_currentPlayParameters->setPlayClipId(clipId); | 
| Chris@45 | 1399     } | 
| Chris@45 | 1400 | 
| Chris@45 | 1401     return true; | 
| Chris@45 | 1402 } | 
| Chris@45 | 1403 | 
| Chris@45 | 1404 bool | 
| Chris@72 | 1405 SVFileReader::readTransform(const QXmlAttributes &attributes) | 
| Chris@72 | 1406 { | 
| Chris@72 | 1407     if (m_currentDerivedModelId < 0) { | 
| Chris@601 | 1408         SVCERR << "WARNING: SV-XML: Transform found outside derivation" << endl; | 
| Chris@72 | 1409         return false; | 
| Chris@72 | 1410     } | 
| Chris@72 | 1411 | 
| Chris@82 | 1412     m_currentTransform = Transform(); | 
| Chris@72 | 1413     m_currentTransform.setFromXmlAttributes(attributes); | 
| Chris@72 | 1414     return true; | 
| Chris@72 | 1415 } | 
| Chris@72 | 1416 | 
| Chris@72 | 1417 bool | 
| Chris@72 | 1418 SVFileReader::readParameter(const QXmlAttributes &attributes) | 
| Chris@72 | 1419 { | 
| Chris@72 | 1420     if (m_currentDerivedModelId < 0) { | 
| Chris@601 | 1421         SVCERR << "WARNING: SV-XML: Parameter found outside derivation" << endl; | 
| Chris@72 | 1422         return false; | 
| Chris@72 | 1423     } | 
| Chris@72 | 1424 | 
| Chris@72 | 1425     QString name = attributes.value("name"); | 
| Chris@72 | 1426     if (name == "") { | 
| Chris@601 | 1427         SVCERR << "WARNING: SV-XML: Ignoring nameless transform parameter" | 
| Chris@293 | 1428                   << endl; | 
| Chris@72 | 1429         return false; | 
| Chris@72 | 1430     } | 
| Chris@72 | 1431 | 
| Chris@72 | 1432     float value = attributes.value("value").trimmed().toFloat(); | 
| Chris@72 | 1433 | 
| Chris@72 | 1434     m_currentTransform.setParameter(name, value); | 
| Chris@72 | 1435     return true; | 
| Chris@72 | 1436 } | 
| Chris@72 | 1437 | 
| Chris@72 | 1438 bool | 
| Chris@45 | 1439 SVFileReader::readSelection(const QXmlAttributes &attributes) | 
| Chris@45 | 1440 { | 
| Chris@45 | 1441     bool ok; | 
| Chris@45 | 1442 | 
| Chris@45 | 1443     READ_MANDATORY(int, start, toInt); | 
| Chris@45 | 1444     READ_MANDATORY(int, end, toInt); | 
| Chris@45 | 1445 | 
| Chris@45 | 1446     m_paneCallback.addSelection(start, end); | 
| Chris@45 | 1447 | 
| Chris@45 | 1448     return true; | 
| Chris@45 | 1449 } | 
| Chris@45 | 1450 | 
| Chris@45 | 1451 bool | 
| Chris@45 | 1452 SVFileReader::readMeasurement(const QXmlAttributes &attributes) | 
| Chris@45 | 1453 { | 
| Chris@233 | 1454     SVDEBUG << "SVFileReader::readMeasurement: inLayer " | 
| Chris@229 | 1455               << m_inLayer << ", layer " << m_currentLayer << endl; | 
| Chris@45 | 1456 | 
| Chris@45 | 1457     if (!m_inLayer) { | 
| Chris@601 | 1458         SVCERR << "WARNING: SV-XML: Measurement found outside layer" << endl; | 
| Chris@45 | 1459         return false; | 
| Chris@45 | 1460     } | 
| Chris@45 | 1461 | 
| Chris@45 | 1462     m_currentLayer->addMeasurementRect(attributes); | 
| Chris@45 | 1463     return true; | 
| Chris@45 | 1464 } | 
| Chris@45 | 1465 | 
| Chris@45 | 1466 SVFileReaderPaneCallback::~SVFileReaderPaneCallback() | 
| Chris@45 | 1467 { | 
| Chris@45 | 1468 } | 
| Chris@45 | 1469 | 
| Chris@140 | 1470 | 
| Chris@140 | 1471 class SVFileIdentifier : public QXmlDefaultHandler | 
| Chris@140 | 1472 { | 
| Chris@140 | 1473 public: | 
| Chris@140 | 1474     SVFileIdentifier() : | 
| Chris@140 | 1475         m_inSv(false), | 
| Chris@140 | 1476         m_inData(false), | 
| Chris@140 | 1477         m_type(SVFileReader::UnknownFileType) | 
| Chris@140 | 1478     { } | 
| Chris@140 | 1479     virtual ~SVFileIdentifier() { } | 
| Chris@140 | 1480 | 
| Chris@140 | 1481     void parse(QXmlInputSource &source) { | 
| Chris@140 | 1482         QXmlSimpleReader reader; | 
| Chris@140 | 1483         reader.setContentHandler(this); | 
| Chris@140 | 1484         reader.setErrorHandler(this); | 
| Chris@140 | 1485         reader.parse(source); | 
| Chris@140 | 1486     } | 
| Chris@140 | 1487 | 
| Chris@140 | 1488     SVFileReader::FileType getType() const { return m_type; } | 
| Chris@140 | 1489 | 
| Chris@140 | 1490     virtual bool startElement(const QString &, | 
| Chris@595 | 1491                               const QString &, | 
| Chris@595 | 1492                               const QString &qName, | 
| Chris@595 | 1493                               const QXmlAttributes& atts) | 
| Chris@140 | 1494     { | 
| Chris@140 | 1495         QString name = qName.toLower(); | 
| Chris@140 | 1496 | 
| Chris@140 | 1497         // SV session files have an sv element containing a data | 
| Chris@140 | 1498         // element containing a model element with mainModel="true". | 
| Chris@140 | 1499 | 
| Chris@140 | 1500         // If the sv element is present but the rest does not satisfy, | 
| Chris@140 | 1501         // then it's (probably) an SV layer file. | 
| Chris@140 | 1502 | 
| Chris@140 | 1503         // Otherwise, it's of unknown type. | 
| Chris@140 | 1504 | 
| Chris@140 | 1505         if (name == "sv") { | 
| Chris@140 | 1506             m_inSv = true; | 
| Chris@140 | 1507             if (m_type == SVFileReader::UnknownFileType) { | 
| Chris@140 | 1508                 m_type = SVFileReader::SVLayerFile; | 
| Chris@140 | 1509             } | 
| Chris@140 | 1510             return true; | 
| Chris@140 | 1511         } else if (name == "data") { | 
| Chris@140 | 1512             if (!m_inSv) return true; | 
| Chris@140 | 1513             m_inData = true; | 
| Chris@140 | 1514         } else if (name == "model") { | 
| Chris@140 | 1515             if (!m_inData) return true; | 
| Chris@140 | 1516             if (atts.value("mainModel").trimmed() == "true") { | 
| Chris@140 | 1517                 if (m_type == SVFileReader::SVLayerFile) { | 
| Chris@140 | 1518                     m_type = SVFileReader::SVSessionFile; | 
| Chris@140 | 1519                     return false; // done | 
| Chris@140 | 1520                 } | 
| Chris@140 | 1521             } | 
| Chris@140 | 1522         } | 
| Chris@140 | 1523         return true; | 
| Chris@140 | 1524     } | 
| Chris@140 | 1525 | 
| Chris@140 | 1526     virtual bool endElement(const QString &, | 
| Chris@595 | 1527                             const QString &, | 
| Chris@595 | 1528                             const QString &qName) | 
| Chris@140 | 1529     { | 
| Chris@140 | 1530         QString name = qName.toLower(); | 
| Chris@140 | 1531 | 
| Chris@140 | 1532         if (name == "sv") { | 
| Chris@140 | 1533             if (m_inSv) { | 
| Chris@140 | 1534                 m_inSv = false; | 
| Chris@140 | 1535                 return false; // done | 
| Chris@140 | 1536             } | 
| Chris@140 | 1537         } else if (name == "data") { | 
| Chris@140 | 1538             if (m_inData) { | 
| Chris@140 | 1539                 m_inData = false; | 
| Chris@140 | 1540                 return false; // also done, nothing after the first | 
| Chris@140 | 1541                               // data element is of use here | 
| Chris@140 | 1542             } | 
| Chris@140 | 1543         } | 
| Chris@140 | 1544         return true; | 
| Chris@140 | 1545     } | 
| Chris@140 | 1546 | 
| Chris@140 | 1547 private: | 
| Chris@140 | 1548     bool m_inSv; | 
| Chris@140 | 1549     bool m_inData; | 
| Chris@140 | 1550     SVFileReader::FileType m_type; | 
| Chris@140 | 1551 }; | 
| Chris@140 | 1552 | 
| Chris@140 | 1553 | 
| Chris@140 | 1554 SVFileReader::FileType | 
| Chris@140 | 1555 SVFileReader::identifyXmlFile(QString path) | 
| Chris@140 | 1556 { | 
| Chris@140 | 1557     QFile file(path); | 
| Chris@140 | 1558     SVFileIdentifier identifier; | 
| Chris@140 | 1559     QXmlInputSource source(&file); | 
| Chris@140 | 1560     identifier.parse(source); | 
| Chris@140 | 1561     return identifier.getType(); | 
| Chris@140 | 1562 } | 
| Chris@140 | 1563 | 
| Chris@140 | 1564 | 
| Chris@140 | 1565 |