| 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@45 | 22 | 
| Chris@45 | 23 #include "data/fileio/AudioFileReaderFactory.h" | 
| Chris@45 | 24 #include "data/fileio/FileFinder.h" | 
| Chris@45 | 25 #include "data/fileio/FileSource.h" | 
| Chris@45 | 26 | 
| Chris@45 | 27 #include "data/model/WaveFileModel.h" | 
| Chris@45 | 28 #include "data/model/EditableDenseThreeDimensionalModel.h" | 
| Chris@45 | 29 #include "data/model/SparseOneDimensionalModel.h" | 
| Chris@45 | 30 #include "data/model/SparseTimeValueModel.h" | 
| Chris@45 | 31 #include "data/model/NoteModel.h" | 
| Chris@45 | 32 #include "data/model/TextModel.h" | 
| Chris@45 | 33 #include "data/model/ImageModel.h" | 
| Chris@45 | 34 | 
| Chris@72 | 35 #include "plugin/transform/TransformFactory.h" | 
| Chris@72 | 36 | 
| Chris@45 | 37 #include "view/Pane.h" | 
| Chris@45 | 38 | 
| Chris@45 | 39 #include "Document.h" | 
| Chris@45 | 40 | 
| Chris@45 | 41 #include <QString> | 
| Chris@45 | 42 #include <QMessageBox> | 
| Chris@45 | 43 #include <QFileDialog> | 
| Chris@45 | 44 | 
| Chris@45 | 45 #include <iostream> | 
| Chris@45 | 46 | 
| Chris@45 | 47 SVFileReader::SVFileReader(Document *document, | 
| Chris@45 | 48 			   SVFileReaderPaneCallback &callback, | 
| Chris@45 | 49                            QString location) : | 
| Chris@45 | 50     m_document(document), | 
| Chris@45 | 51     m_paneCallback(callback), | 
| Chris@45 | 52     m_location(location), | 
| Chris@45 | 53     m_currentPane(0), | 
| Chris@45 | 54     m_currentDataset(0), | 
| Chris@45 | 55     m_currentDerivedModel(0), | 
| Chris@45 | 56     m_currentDerivedModelId(-1), | 
| Chris@45 | 57     m_currentPlayParameters(0), | 
| Chris@72 | 58     m_currentTransformSource(0), | 
| Chris@45 | 59     m_datasetSeparator(" "), | 
| Chris@45 | 60     m_inRow(false), | 
| Chris@45 | 61     m_inLayer(false), | 
| Chris@45 | 62     m_inView(false), | 
| Chris@45 | 63     m_rowNumber(0), | 
| Chris@45 | 64     m_ok(false) | 
| Chris@45 | 65 { | 
| Chris@45 | 66 } | 
| Chris@45 | 67 | 
| Chris@45 | 68 void | 
| Chris@45 | 69 SVFileReader::parse(const QString &xmlData) | 
| Chris@45 | 70 { | 
| Chris@45 | 71     QXmlInputSource inputSource; | 
| Chris@45 | 72     inputSource.setData(xmlData); | 
| Chris@45 | 73     parse(inputSource); | 
| Chris@45 | 74 } | 
| Chris@45 | 75 | 
| Chris@45 | 76 void | 
| Chris@45 | 77 SVFileReader::parse(QXmlInputSource &inputSource) | 
| Chris@45 | 78 { | 
| Chris@45 | 79     QXmlSimpleReader reader; | 
| Chris@45 | 80     reader.setContentHandler(this); | 
| Chris@45 | 81     reader.setErrorHandler(this); | 
| Chris@45 | 82     m_ok = reader.parse(inputSource); | 
| Chris@45 | 83 } | 
| Chris@45 | 84 | 
| Chris@45 | 85 bool | 
| Chris@45 | 86 SVFileReader::isOK() | 
| Chris@45 | 87 { | 
| Chris@45 | 88     return m_ok; | 
| Chris@45 | 89 } | 
| Chris@45 | 90 | 
| Chris@45 | 91 SVFileReader::~SVFileReader() | 
| Chris@45 | 92 { | 
| Chris@45 | 93     if (!m_awaitingDatasets.empty()) { | 
| Chris@45 | 94 	std::cerr << "WARNING: SV-XML: File ended with " | 
| Chris@45 | 95 		  << m_awaitingDatasets.size() << " unfilled model dataset(s)" | 
| Chris@45 | 96 		  << std::endl; | 
| Chris@45 | 97     } | 
| Chris@45 | 98 | 
| Chris@45 | 99     std::set<Model *> unaddedModels; | 
| Chris@45 | 100 | 
| Chris@45 | 101     for (std::map<int, Model *>::iterator i = m_models.begin(); | 
| Chris@45 | 102 	 i != m_models.end(); ++i) { | 
| Chris@45 | 103 	if (m_addedModels.find(i->second) == m_addedModels.end()) { | 
| Chris@45 | 104 	    unaddedModels.insert(i->second); | 
| Chris@45 | 105 	} | 
| Chris@45 | 106     } | 
| Chris@45 | 107 | 
| Chris@45 | 108     if (!unaddedModels.empty()) { | 
| Chris@45 | 109 	std::cerr << "WARNING: SV-XML: File contained " | 
| Chris@45 | 110 		  << unaddedModels.size() << " unused models" | 
| Chris@45 | 111 		  << std::endl; | 
| Chris@45 | 112 	while (!unaddedModels.empty()) { | 
| Chris@45 | 113 	    delete *unaddedModels.begin(); | 
| Chris@45 | 114 	    unaddedModels.erase(unaddedModels.begin()); | 
| Chris@45 | 115 	} | 
| Chris@45 | 116     } | 
| Chris@45 | 117 } | 
| Chris@45 | 118 | 
| Chris@45 | 119 bool | 
| Chris@45 | 120 SVFileReader::startElement(const QString &, const QString &, | 
| Chris@45 | 121 			   const QString &qName, | 
| Chris@45 | 122 			   const QXmlAttributes &attributes) | 
| Chris@45 | 123 { | 
| Chris@45 | 124     QString name = qName.toLower(); | 
| Chris@45 | 125 | 
| Chris@45 | 126     bool ok = false; | 
| Chris@45 | 127 | 
| Chris@45 | 128     // Valid element names: | 
| Chris@45 | 129     // | 
| Chris@45 | 130     // sv | 
| Chris@45 | 131     // data | 
| Chris@45 | 132     // dataset | 
| Chris@45 | 133     // display | 
| Chris@45 | 134     // derivation | 
| Chris@45 | 135     // playparameters | 
| Chris@45 | 136     // layer | 
| Chris@45 | 137     // model | 
| Chris@45 | 138     // point | 
| Chris@45 | 139     // row | 
| Chris@45 | 140     // view | 
| Chris@45 | 141     // window | 
| Chris@72 | 142     // plugin | 
| Chris@72 | 143     // transform | 
| Chris@72 | 144     // selections | 
| Chris@72 | 145     // selection | 
| Chris@72 | 146     // measurement | 
| Chris@45 | 147 | 
| Chris@45 | 148     if (name == "sv") { | 
| Chris@45 | 149 | 
| Chris@45 | 150 	// nothing needed | 
| Chris@45 | 151 	ok = true; | 
| Chris@45 | 152 | 
| Chris@45 | 153     } else if (name == "data") { | 
| Chris@45 | 154 | 
| Chris@45 | 155 	// nothing needed | 
| Chris@45 | 156 	m_inData = true; | 
| Chris@45 | 157 	ok = true; | 
| Chris@45 | 158 | 
| Chris@45 | 159     } else if (name == "display") { | 
| Chris@45 | 160 | 
| Chris@45 | 161 	// nothing needed | 
| Chris@45 | 162 	ok = true; | 
| Chris@45 | 163 | 
| Chris@45 | 164     } else if (name == "window") { | 
| Chris@45 | 165 | 
| Chris@45 | 166 	ok = readWindow(attributes); | 
| Chris@45 | 167 | 
| Chris@45 | 168     } else if (name == "model") { | 
| Chris@45 | 169 | 
| Chris@45 | 170 	ok = readModel(attributes); | 
| Chris@45 | 171 | 
| Chris@45 | 172     } else if (name == "dataset") { | 
| Chris@45 | 173 | 
| Chris@45 | 174 	ok = readDatasetStart(attributes); | 
| Chris@45 | 175 | 
| Chris@45 | 176     } else if (name == "bin") { | 
| Chris@45 | 177 | 
| Chris@45 | 178 	ok = addBinToDataset(attributes); | 
| Chris@45 | 179 | 
| Chris@45 | 180     } else if (name == "point") { | 
| Chris@45 | 181 | 
| Chris@45 | 182 	ok = addPointToDataset(attributes); | 
| Chris@45 | 183 | 
| Chris@45 | 184     } else if (name == "row") { | 
| Chris@45 | 185 | 
| Chris@45 | 186 	ok = addRowToDataset(attributes); | 
| Chris@45 | 187 | 
| Chris@45 | 188     } else if (name == "layer") { | 
| Chris@45 | 189 | 
| Chris@45 | 190         addUnaddedModels(); // all models must be specified before first layer | 
| Chris@45 | 191 	ok = readLayer(attributes); | 
| Chris@45 | 192 | 
| Chris@45 | 193     } else if (name == "view") { | 
| Chris@45 | 194 | 
| Chris@45 | 195 	m_inView = true; | 
| Chris@45 | 196 	ok = readView(attributes); | 
| Chris@45 | 197 | 
| Chris@45 | 198     } else if (name == "derivation") { | 
| Chris@45 | 199 | 
| Chris@45 | 200 	ok = readDerivation(attributes); | 
| Chris@45 | 201 | 
| Chris@45 | 202     } else if (name == "playparameters") { | 
| Chris@45 | 203 | 
| Chris@45 | 204         ok = readPlayParameters(attributes); | 
| Chris@45 | 205 | 
| Chris@45 | 206     } else if (name == "plugin") { | 
| Chris@45 | 207 | 
| Chris@45 | 208 	ok = readPlugin(attributes); | 
| Chris@45 | 209 | 
| Chris@45 | 210     } else if (name == "selections") { | 
| Chris@45 | 211 | 
| Chris@45 | 212 	m_inSelections = true; | 
| Chris@45 | 213 	ok = true; | 
| Chris@45 | 214 | 
| Chris@45 | 215     } else if (name == "selection") { | 
| Chris@45 | 216 | 
| Chris@45 | 217 	ok = readSelection(attributes); | 
| Chris@45 | 218 | 
| Chris@45 | 219     } else if (name == "measurement") { | 
| Chris@45 | 220 | 
| Chris@45 | 221         ok = readMeasurement(attributes); | 
| Chris@45 | 222 | 
| Chris@72 | 223     } else if (name == "transform") { | 
| Chris@72 | 224 | 
| Chris@72 | 225         ok = readTransform(attributes); | 
| Chris@72 | 226 | 
| Chris@72 | 227     } else if (name == "parameter") { | 
| Chris@72 | 228 | 
| Chris@72 | 229         ok = readParameter(attributes); | 
| Chris@72 | 230 | 
| Chris@45 | 231     } else { | 
| Chris@45 | 232         std::cerr << "WARNING: SV-XML: Unexpected element \"" | 
| Chris@45 | 233                   << name.toLocal8Bit().data() << "\"" << std::endl; | 
| Chris@45 | 234     } | 
| Chris@45 | 235 | 
| Chris@45 | 236     if (!ok) { | 
| Chris@45 | 237 	std::cerr << "WARNING: SV-XML: Failed to completely process element \"" | 
| Chris@45 | 238 		  << name.toLocal8Bit().data() << "\"" << std::endl; | 
| Chris@45 | 239     } | 
| Chris@45 | 240 | 
| Chris@45 | 241     return true; | 
| Chris@45 | 242 } | 
| Chris@45 | 243 | 
| Chris@45 | 244 bool | 
| Chris@45 | 245 SVFileReader::characters(const QString &text) | 
| Chris@45 | 246 { | 
| Chris@45 | 247     bool ok = false; | 
| Chris@45 | 248 | 
| Chris@45 | 249     if (m_inRow) { | 
| Chris@45 | 250 	ok = readRowData(text); | 
| Chris@45 | 251 	if (!ok) { | 
| Chris@45 | 252 	    std::cerr << "WARNING: SV-XML: Failed to read row data content for row " << m_rowNumber << std::endl; | 
| Chris@45 | 253 	} | 
| Chris@45 | 254     } | 
| Chris@45 | 255 | 
| Chris@45 | 256     return true; | 
| Chris@45 | 257 } | 
| Chris@45 | 258 | 
| Chris@45 | 259 bool | 
| Chris@45 | 260 SVFileReader::endElement(const QString &, const QString &, | 
| Chris@45 | 261 			 const QString &qName) | 
| Chris@45 | 262 { | 
| Chris@45 | 263     QString name = qName.toLower(); | 
| Chris@45 | 264 | 
| Chris@45 | 265     if (name == "dataset") { | 
| Chris@45 | 266 | 
| Chris@45 | 267 	if (m_currentDataset) { | 
| Chris@45 | 268 | 
| Chris@45 | 269 	    bool foundInAwaiting = false; | 
| Chris@45 | 270 | 
| Chris@45 | 271 	    for (std::map<int, int>::iterator i = m_awaitingDatasets.begin(); | 
| Chris@45 | 272 		 i != m_awaitingDatasets.end(); ++i) { | 
| Chris@45 | 273 		if (haveModel(i->second) && | 
| Chris@45 | 274                     m_models[i->second] == m_currentDataset) { | 
| Chris@45 | 275 		    m_awaitingDatasets.erase(i); | 
| Chris@45 | 276 		    foundInAwaiting = true; | 
| Chris@45 | 277 		    break; | 
| Chris@45 | 278 		} | 
| Chris@45 | 279 	    } | 
| Chris@45 | 280 | 
| Chris@45 | 281 	    if (!foundInAwaiting) { | 
| Chris@45 | 282 		std::cerr << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << std::endl; | 
| Chris@45 | 283 	    } | 
| Chris@45 | 284 	} | 
| Chris@45 | 285 | 
| Chris@45 | 286 	m_currentDataset = 0; | 
| Chris@45 | 287 | 
| Chris@45 | 288     } else if (name == "data") { | 
| Chris@45 | 289 | 
| Chris@45 | 290         addUnaddedModels(); | 
| Chris@45 | 291 	m_inData = false; | 
| Chris@45 | 292 | 
| Chris@45 | 293     } else if (name == "derivation") { | 
| Chris@45 | 294 | 
| Chris@45 | 295         if (!m_currentDerivedModel) { | 
| Chris@45 | 296             if (m_currentDerivedModel < 0) { | 
| Chris@45 | 297                 std::cerr << "WARNING: SV-XML: Bad derivation output model id " | 
| Chris@45 | 298                           << m_currentDerivedModelId << std::endl; | 
| Chris@45 | 299             } else if (haveModel(m_currentDerivedModelId)) { | 
| Chris@45 | 300                 std::cerr << "WARNING: SV-XML: Derivation has existing model " | 
| Chris@45 | 301                           << m_currentDerivedModelId | 
| Chris@45 | 302                           << " as target, not regenerating" << std::endl; | 
| Chris@45 | 303             } else { | 
| Chris@45 | 304                 m_currentDerivedModel = m_models[m_currentDerivedModelId] = | 
| Chris@72 | 305                     m_document->addDerivedModel | 
| Chris@72 | 306                     (m_currentTransform, | 
| Chris@72 | 307                      ModelTransformer::Input(m_currentTransformSource, | 
| Chris@72 | 308                                              m_currentTransformChannel)); | 
| Chris@45 | 309             } | 
| Chris@45 | 310         } else { | 
| Chris@72 | 311             m_document->addDerivedModel | 
| Chris@72 | 312                 (m_currentTransform, | 
| Chris@72 | 313                  ModelTransformer::Input(m_currentTransformSource, | 
| Chris@72 | 314                                          m_currentTransformChannel), | 
| Chris@72 | 315                  m_currentDerivedModel); | 
| Chris@45 | 316         } | 
| Chris@45 | 317 | 
| Chris@45 | 318         m_addedModels.insert(m_currentDerivedModel); | 
| Chris@45 | 319         m_currentDerivedModel = 0; | 
| Chris@45 | 320         m_currentDerivedModelId = -1; | 
| Chris@72 | 321         m_currentTransformSource = 0; | 
| Chris@72 | 322         m_currentTransform = Transform(); | 
| Chris@72 | 323         m_currentTransformChannel = -1; | 
| Chris@45 | 324 | 
| Chris@45 | 325     } else if (name == "row") { | 
| Chris@45 | 326 	m_inRow = false; | 
| Chris@45 | 327     } else if (name == "layer") { | 
| Chris@45 | 328         m_inLayer = false; | 
| Chris@45 | 329     } else if (name == "view") { | 
| Chris@45 | 330 	m_inView = false; | 
| Chris@45 | 331     } else if (name == "selections") { | 
| Chris@45 | 332 	m_inSelections = false; | 
| Chris@45 | 333     } else if (name == "playparameters") { | 
| Chris@45 | 334         m_currentPlayParameters = 0; | 
| Chris@45 | 335     } | 
| Chris@45 | 336 | 
| Chris@45 | 337     return true; | 
| Chris@45 | 338 } | 
| Chris@45 | 339 | 
| Chris@45 | 340 bool | 
| Chris@45 | 341 SVFileReader::error(const QXmlParseException &exception) | 
| Chris@45 | 342 { | 
| Chris@45 | 343     m_errorString = | 
| Chris@45 | 344 	QString("ERROR: SV-XML: %1 at line %2, column %3") | 
| Chris@45 | 345 	.arg(exception.message()) | 
| Chris@45 | 346 	.arg(exception.lineNumber()) | 
| Chris@45 | 347 	.arg(exception.columnNumber()); | 
| Chris@45 | 348     std::cerr << m_errorString.toLocal8Bit().data() << std::endl; | 
| Chris@45 | 349     return QXmlDefaultHandler::error(exception); | 
| Chris@45 | 350 } | 
| Chris@45 | 351 | 
| Chris@45 | 352 bool | 
| Chris@45 | 353 SVFileReader::fatalError(const QXmlParseException &exception) | 
| Chris@45 | 354 { | 
| Chris@45 | 355     m_errorString = | 
| Chris@45 | 356 	QString("FATAL ERROR: SV-XML: %1 at line %2, column %3") | 
| Chris@45 | 357 	.arg(exception.message()) | 
| Chris@45 | 358 	.arg(exception.lineNumber()) | 
| Chris@45 | 359 	.arg(exception.columnNumber()); | 
| Chris@45 | 360     std::cerr << m_errorString.toLocal8Bit().data() << std::endl; | 
| Chris@45 | 361     return QXmlDefaultHandler::fatalError(exception); | 
| Chris@45 | 362 } | 
| Chris@45 | 363 | 
| Chris@45 | 364 | 
| Chris@45 | 365 #define READ_MANDATORY(TYPE, NAME, CONVERSION)		      \ | 
| Chris@45 | 366     TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \ | 
| Chris@45 | 367     if (!ok) { \ | 
| Chris@45 | 368 	std::cerr << "WARNING: SV-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << std::endl; \ | 
| Chris@45 | 369 	return false; \ | 
| Chris@45 | 370     } | 
| Chris@45 | 371 | 
| Chris@45 | 372 bool | 
| Chris@45 | 373 SVFileReader::readWindow(const QXmlAttributes &attributes) | 
| Chris@45 | 374 { | 
| Chris@45 | 375     bool ok = false; | 
| Chris@45 | 376 | 
| Chris@45 | 377     READ_MANDATORY(int, width, toInt); | 
| Chris@45 | 378     READ_MANDATORY(int, height, toInt); | 
| Chris@45 | 379 | 
| Chris@45 | 380     m_paneCallback.setWindowSize(width, height); | 
| Chris@45 | 381     return true; | 
| Chris@45 | 382 } | 
| Chris@45 | 383 | 
| Chris@45 | 384 void | 
| Chris@45 | 385 SVFileReader::addUnaddedModels() | 
| Chris@45 | 386 { | 
| Chris@45 | 387     std::set<Model *> unaddedModels; | 
| Chris@45 | 388 | 
| Chris@45 | 389     for (std::map<int, Model *>::iterator i = m_models.begin(); | 
| Chris@45 | 390          i != m_models.end(); ++i) { | 
| Chris@45 | 391         if (m_addedModels.find(i->second) == m_addedModels.end()) { | 
| Chris@45 | 392             unaddedModels.insert(i->second); | 
| Chris@45 | 393         } | 
| Chris@45 | 394     } | 
| Chris@45 | 395 | 
| Chris@45 | 396     for (std::set<Model *>::iterator i = unaddedModels.begin(); | 
| Chris@45 | 397          i != unaddedModels.end(); ++i) { | 
| Chris@45 | 398         m_document->addImportedModel(*i); | 
| Chris@45 | 399         m_addedModels.insert(*i); | 
| Chris@45 | 400     } | 
| Chris@45 | 401 } | 
| Chris@45 | 402 | 
| Chris@45 | 403 bool | 
| Chris@45 | 404 SVFileReader::readModel(const QXmlAttributes &attributes) | 
| Chris@45 | 405 { | 
| Chris@45 | 406     bool ok = false; | 
| Chris@45 | 407 | 
| Chris@45 | 408     READ_MANDATORY(int, id, toInt); | 
| Chris@45 | 409 | 
| Chris@45 | 410     if (haveModel(id)) { | 
| Chris@45 | 411 	std::cerr << "WARNING: SV-XML: Ignoring duplicate model id " << id | 
| Chris@45 | 412 		  << std::endl; | 
| Chris@45 | 413 	return false; | 
| Chris@45 | 414     } | 
| Chris@45 | 415 | 
| Chris@45 | 416     QString name = attributes.value("name"); | 
| Chris@45 | 417 | 
| Chris@45 | 418     std::cerr << "SVFileReader::readModel: model name \"" << name.toStdString() << "\"" << std::endl; | 
| Chris@45 | 419 | 
| Chris@45 | 420     READ_MANDATORY(int, sampleRate, toInt); | 
| Chris@45 | 421 | 
| Chris@45 | 422     QString type = attributes.value("type").trimmed(); | 
| Chris@45 | 423     bool mainModel = (attributes.value("mainModel").trimmed() == "true"); | 
| Chris@45 | 424 | 
| Chris@45 | 425     if (type == "wavefile") { | 
| Chris@45 | 426 | 
| Chris@45 | 427         WaveFileModel *model = 0; | 
| Chris@45 | 428         FileFinder *ff = FileFinder::getInstance(); | 
| Chris@45 | 429         QString originalPath = attributes.value("file"); | 
| Chris@45 | 430         QString path = ff->find(FileFinder::AudioFile, | 
| Chris@45 | 431                                 originalPath, m_location); | 
| Chris@45 | 432 | 
| Chris@76 | 433         FileSource file(path, FileSource::ProgressDialog); | 
| Chris@45 | 434         file.waitForStatus(); | 
| Chris@45 | 435 | 
| Chris@45 | 436         if (!file.isOK()) { | 
| Chris@45 | 437             std::cerr << "SVFileReader::readModel: Failed to retrieve file \"" << path.toStdString() << "\" for wave file model: " << file.getErrorString().toStdString() << std::endl; | 
| Chris@45 | 438         } else if (!file.isAvailable()) { | 
| Chris@45 | 439             std::cerr << "SVFileReader::readModel: Failed to retrieve file \"" << path.toStdString() << "\" for wave file model: Source unavailable" << std::endl; | 
| Chris@45 | 440         } else { | 
| Chris@45 | 441 | 
| Chris@45 | 442             file.waitForData(); | 
| Chris@45 | 443             model = new WaveFileModel(file); | 
| Chris@45 | 444             if (!model->isOK()) { | 
| Chris@45 | 445                 delete model; | 
| Chris@45 | 446                 model = 0; | 
| Chris@45 | 447             } | 
| Chris@45 | 448         } | 
| Chris@45 | 449 | 
| Chris@45 | 450         if (!model) return false; | 
| Chris@45 | 451 | 
| Chris@45 | 452         model->setObjectName(name); | 
| Chris@45 | 453 	m_models[id] = model; | 
| Chris@45 | 454 	if (mainModel) { | 
| Chris@45 | 455 	    m_document->setMainModel(model); | 
| Chris@45 | 456 	    m_addedModels.insert(model); | 
| Chris@45 | 457 	} | 
| Chris@45 | 458 	// Derived models will be added when their derivation | 
| Chris@45 | 459 	// is found. | 
| Chris@45 | 460 | 
| Chris@45 | 461 	return true; | 
| Chris@45 | 462 | 
| Chris@45 | 463     } else if (type == "dense") { | 
| Chris@45 | 464 | 
| Chris@45 | 465 	READ_MANDATORY(int, dimensions, toInt); | 
| Chris@45 | 466 | 
| Chris@45 | 467 	// Currently the only dense model we support here is the dense | 
| Chris@45 | 468 	// 3d model.  Dense time-value models are always file-backed | 
| Chris@45 | 469 	// waveform data, at this point, and they come in as wavefile | 
| Chris@45 | 470 	// models. | 
| Chris@45 | 471 | 
| Chris@45 | 472 	if (dimensions == 3) { | 
| Chris@45 | 473 | 
| Chris@45 | 474 	    READ_MANDATORY(int, windowSize, toInt); | 
| Chris@45 | 475 	    READ_MANDATORY(int, yBinCount, toInt); | 
| Chris@45 | 476 | 
| Chris@45 | 477             EditableDenseThreeDimensionalModel *model = | 
| Chris@45 | 478 		new EditableDenseThreeDimensionalModel | 
| Chris@45 | 479                 (sampleRate, windowSize, yBinCount); | 
| Chris@45 | 480 | 
| Chris@45 | 481 	    float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 
| Chris@45 | 482 	    if (ok) model->setMinimumLevel(minimum); | 
| Chris@45 | 483 | 
| Chris@45 | 484 	    float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 
| Chris@45 | 485 	    if (ok) model->setMaximumLevel(maximum); | 
| Chris@45 | 486 | 
| Chris@45 | 487 	    int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@45 | 488 	    if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 489 | 
| Chris@45 | 490             model->setObjectName(name); | 
| Chris@45 | 491 	    m_models[id] = model; | 
| Chris@45 | 492 	    return true; | 
| Chris@45 | 493 | 
| Chris@45 | 494 	} else { | 
| Chris@45 | 495 | 
| Chris@45 | 496 	    std::cerr << "WARNING: SV-XML: Unexpected dense model dimension (" | 
| Chris@45 | 497 		      << dimensions << ")" << std::endl; | 
| Chris@45 | 498 	} | 
| Chris@45 | 499     } else if (type == "sparse") { | 
| Chris@45 | 500 | 
| Chris@45 | 501 	READ_MANDATORY(int, dimensions, toInt); | 
| Chris@45 | 502 | 
| Chris@45 | 503 	if (dimensions == 1) { | 
| Chris@45 | 504 | 
| Chris@45 | 505 	    READ_MANDATORY(int, resolution, toInt); | 
| Chris@45 | 506 | 
| Chris@45 | 507             if (attributes.value("subtype") == "image") { | 
| Chris@45 | 508 | 
| Chris@45 | 509                 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 
| Chris@45 | 510                 ImageModel *model = new ImageModel(sampleRate, resolution, | 
| Chris@45 | 511                                                    notifyOnAdd); | 
| Chris@45 | 512                 model->setObjectName(name); | 
| Chris@45 | 513                 m_models[id] = model; | 
| Chris@45 | 514 | 
| Chris@45 | 515             } else { | 
| Chris@45 | 516 | 
| Chris@45 | 517                 SparseOneDimensionalModel *model = new SparseOneDimensionalModel | 
| Chris@45 | 518                     (sampleRate, resolution); | 
| Chris@45 | 519                 model->setObjectName(name); | 
| Chris@45 | 520                 m_models[id] = model; | 
| Chris@45 | 521             } | 
| Chris@45 | 522 | 
| Chris@45 | 523 	    int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@45 | 524 	    if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 525 | 
| Chris@45 | 526 	    return true; | 
| Chris@45 | 527 | 
| Chris@45 | 528 	} else if (dimensions == 2 || dimensions == 3) { | 
| Chris@45 | 529 | 
| Chris@45 | 530 	    READ_MANDATORY(int, resolution, toInt); | 
| Chris@45 | 531 | 
| Chris@45 | 532             bool haveMinMax = true; | 
| Chris@45 | 533 	    float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 
| Chris@45 | 534             if (!ok) haveMinMax = false; | 
| Chris@45 | 535 	    float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 
| Chris@45 | 536             if (!ok) haveMinMax = false; | 
| Chris@45 | 537 | 
| Chris@45 | 538 	    float valueQuantization = | 
| Chris@45 | 539 		attributes.value("valueQuantization").trimmed().toFloat(&ok); | 
| Chris@45 | 540 | 
| Chris@45 | 541 	    bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 
| Chris@45 | 542 | 
| Chris@45 | 543             QString units = attributes.value("units"); | 
| Chris@45 | 544 | 
| Chris@45 | 545 	    if (dimensions == 2) { | 
| Chris@45 | 546 		if (attributes.value("subtype") == "text") { | 
| Chris@45 | 547 		    TextModel *model = new TextModel | 
| Chris@45 | 548 			(sampleRate, resolution, notifyOnAdd); | 
| Chris@45 | 549                     model->setObjectName(name); | 
| Chris@45 | 550 		    m_models[id] = model; | 
| Chris@45 | 551 		} else { | 
| Chris@45 | 552 		    SparseTimeValueModel *model; | 
| Chris@45 | 553                     if (haveMinMax) { | 
| Chris@45 | 554                         model = new SparseTimeValueModel | 
| Chris@45 | 555                             (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@45 | 556                     } else { | 
| Chris@45 | 557                         model = new SparseTimeValueModel | 
| Chris@45 | 558                             (sampleRate, resolution, notifyOnAdd); | 
| Chris@45 | 559                     } | 
| Chris@45 | 560                     model->setScaleUnits(units); | 
| Chris@45 | 561                     model->setObjectName(name); | 
| Chris@45 | 562 		    m_models[id] = model; | 
| Chris@45 | 563 		} | 
| Chris@45 | 564 	    } else { | 
| Chris@45 | 565 		NoteModel *model; | 
| Chris@45 | 566                 if (haveMinMax) { | 
| Chris@45 | 567                     model = new NoteModel | 
| Chris@45 | 568                         (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| Chris@45 | 569                 } else { | 
| Chris@45 | 570                     model = new NoteModel | 
| Chris@45 | 571                         (sampleRate, resolution, notifyOnAdd); | 
| Chris@45 | 572                 } | 
| Chris@45 | 573 		model->setValueQuantization(valueQuantization); | 
| Chris@45 | 574                 model->setScaleUnits(units); | 
| Chris@45 | 575                 model->setObjectName(name); | 
| Chris@45 | 576 		m_models[id] = model; | 
| Chris@45 | 577 	    } | 
| Chris@45 | 578 | 
| Chris@45 | 579 	    int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| Chris@45 | 580 	    if (ok) m_awaitingDatasets[dataset] = id; | 
| Chris@45 | 581 | 
| Chris@45 | 582 	    return true; | 
| Chris@45 | 583 | 
| Chris@45 | 584 	} else { | 
| Chris@45 | 585 | 
| Chris@45 | 586 	    std::cerr << "WARNING: SV-XML: Unexpected sparse model dimension (" | 
| Chris@45 | 587 		      << dimensions << ")" << std::endl; | 
| Chris@45 | 588 	} | 
| Chris@45 | 589     } else { | 
| Chris@45 | 590 | 
| Chris@45 | 591 	std::cerr << "WARNING: SV-XML: Unexpected model type \"" | 
| Chris@45 | 592 		  << type.toLocal8Bit().data() << "\" for model id " << id << std::endl; | 
| Chris@45 | 593     } | 
| Chris@45 | 594 | 
| Chris@45 | 595     return false; | 
| Chris@45 | 596 } | 
| Chris@45 | 597 | 
| Chris@45 | 598 bool | 
| Chris@45 | 599 SVFileReader::readView(const QXmlAttributes &attributes) | 
| Chris@45 | 600 { | 
| Chris@45 | 601     QString type = attributes.value("type"); | 
| Chris@45 | 602     m_currentPane = 0; | 
| Chris@45 | 603 | 
| Chris@45 | 604     if (type != "pane") { | 
| Chris@45 | 605 	std::cerr << "WARNING: SV-XML: Unexpected view type \"" | 
| Chris@45 | 606 		  << type.toLocal8Bit().data() << "\"" << std::endl; | 
| Chris@45 | 607 	return false; | 
| Chris@45 | 608     } | 
| Chris@45 | 609 | 
| Chris@45 | 610     m_currentPane = m_paneCallback.addPane(); | 
| Chris@45 | 611 | 
| Chris@45 | 612     if (!m_currentPane) { | 
| Chris@45 | 613 	std::cerr << "WARNING: SV-XML: Internal error: Failed to add pane!" | 
| Chris@45 | 614 		  << std::endl; | 
| Chris@45 | 615 	return false; | 
| Chris@45 | 616     } | 
| Chris@45 | 617 | 
| Chris@45 | 618     bool ok = false; | 
| Chris@45 | 619 | 
| Chris@45 | 620     View *view = m_currentPane; | 
| Chris@45 | 621 | 
| Chris@45 | 622     // The view properties first | 
| Chris@45 | 623 | 
| Chris@45 | 624     READ_MANDATORY(size_t, centre, toUInt); | 
| Chris@45 | 625     READ_MANDATORY(size_t, zoom, toUInt); | 
| Chris@45 | 626     READ_MANDATORY(int, followPan, toInt); | 
| Chris@45 | 627     READ_MANDATORY(int, followZoom, toInt); | 
| Chris@45 | 628     QString tracking = attributes.value("tracking"); | 
| Chris@45 | 629 | 
| Chris@45 | 630     // Specify the follow modes before we set the actual values | 
| Chris@45 | 631     view->setFollowGlobalPan(followPan); | 
| Chris@45 | 632     view->setFollowGlobalZoom(followZoom); | 
| Chris@45 | 633     view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous : | 
| Chris@45 | 634 			    tracking == "page" ? PlaybackScrollPage | 
| Chris@45 | 635 			    : PlaybackIgnore); | 
| Chris@45 | 636 | 
| Chris@45 | 637     // Then set these values | 
| Chris@45 | 638     view->setCentreFrame(centre); | 
| Chris@45 | 639     view->setZoomLevel(zoom); | 
| Chris@45 | 640 | 
| Chris@45 | 641     // And pane properties | 
| Chris@45 | 642     READ_MANDATORY(int, centreLineVisible, toInt); | 
| Chris@45 | 643     m_currentPane->setCentreLineVisible(centreLineVisible); | 
| Chris@45 | 644 | 
| Chris@45 | 645     int height = attributes.value("height").toInt(&ok); | 
| Chris@45 | 646     if (ok) { | 
| Chris@45 | 647 	m_currentPane->resize(m_currentPane->width(), height); | 
| Chris@45 | 648     } | 
| Chris@45 | 649 | 
| Chris@45 | 650     return true; | 
| Chris@45 | 651 } | 
| Chris@45 | 652 | 
| Chris@45 | 653 bool | 
| Chris@45 | 654 SVFileReader::readLayer(const QXmlAttributes &attributes) | 
| Chris@45 | 655 { | 
| Chris@45 | 656     QString type = attributes.value("type"); | 
| Chris@45 | 657 | 
| Chris@45 | 658     int id; | 
| Chris@45 | 659     bool ok = false; | 
| Chris@45 | 660     id = attributes.value("id").trimmed().toInt(&ok); | 
| Chris@45 | 661 | 
| Chris@45 | 662     if (!ok) { | 
| Chris@45 | 663 	std::cerr << "WARNING: SV-XML: No layer id for layer of type \"" | 
| Chris@45 | 664 		  << type.toLocal8Bit().data() | 
| Chris@45 | 665 		  << "\"" << std::endl; | 
| Chris@45 | 666 	return false; | 
| Chris@45 | 667     } | 
| Chris@45 | 668 | 
| Chris@45 | 669     Layer *layer = 0; | 
| Chris@45 | 670     bool isNewLayer = false; | 
| Chris@45 | 671 | 
| Chris@45 | 672     // Layers are expected to be defined in layer elements in the data | 
| Chris@45 | 673     // section, and referred to in layer elements in the view | 
| Chris@45 | 674     // sections.  So if we're in the data section, we expect this | 
| Chris@45 | 675     // layer not to exist already; if we're in the view section, we | 
| Chris@45 | 676     // expect it to exist. | 
| Chris@45 | 677 | 
| Chris@45 | 678     if (m_inData) { | 
| Chris@45 | 679 | 
| Chris@45 | 680 	if (m_layers.find(id) != m_layers.end()) { | 
| Chris@45 | 681 	    std::cerr << "WARNING: SV-XML: Ignoring duplicate layer id " << id | 
| Chris@45 | 682 		      << " in data section" << std::endl; | 
| Chris@45 | 683 	    return false; | 
| Chris@45 | 684 	} | 
| Chris@45 | 685 | 
| Chris@45 | 686 	layer = m_layers[id] = m_document->createLayer | 
| Chris@45 | 687 	    (LayerFactory::getInstance()->getLayerTypeForName(type)); | 
| Chris@45 | 688 | 
| Chris@45 | 689 	if (layer) { | 
| Chris@45 | 690 	    m_layers[id] = layer; | 
| Chris@45 | 691 	    isNewLayer = true; | 
| Chris@45 | 692 	} | 
| Chris@45 | 693 | 
| Chris@45 | 694     } else { | 
| Chris@45 | 695 | 
| Chris@45 | 696 	if (!m_currentPane) { | 
| Chris@45 | 697 	    std::cerr << "WARNING: SV-XML: No current pane for layer " << id | 
| Chris@45 | 698 		      << " in view section" << std::endl; | 
| Chris@45 | 699 	    return false; | 
| Chris@45 | 700 	} | 
| Chris@45 | 701 | 
| Chris@45 | 702 	if (m_layers.find(id) != m_layers.end()) { | 
| Chris@45 | 703 | 
| Chris@45 | 704 	    layer = m_layers[id]; | 
| Chris@45 | 705 | 
| Chris@45 | 706 	} else { | 
| Chris@45 | 707 	    std::cerr << "WARNING: SV-XML: Layer id " << id | 
| Chris@45 | 708 		      << " in view section has not been defined -- defining it here" | 
| Chris@45 | 709 		      << std::endl; | 
| Chris@45 | 710 | 
| Chris@45 | 711 	    layer = m_document->createLayer | 
| Chris@45 | 712 		(LayerFactory::getInstance()->getLayerTypeForName(type)); | 
| Chris@45 | 713 | 
| Chris@45 | 714 	    if (layer) { | 
| Chris@45 | 715 		m_layers[id] = layer; | 
| Chris@45 | 716 		isNewLayer = true; | 
| Chris@45 | 717 	    } | 
| Chris@45 | 718 	} | 
| Chris@45 | 719     } | 
| Chris@45 | 720 | 
| Chris@45 | 721     if (!layer) { | 
| Chris@45 | 722 	std::cerr << "WARNING: SV-XML: Failed to add layer of type \"" | 
| Chris@45 | 723 		  << type.toLocal8Bit().data() | 
| Chris@45 | 724 		  << "\"" << std::endl; | 
| Chris@45 | 725 	return false; | 
| Chris@45 | 726     } | 
| Chris@45 | 727 | 
| Chris@45 | 728     if (isNewLayer) { | 
| Chris@45 | 729 | 
| Chris@45 | 730 	QString name = attributes.value("name"); | 
| Chris@45 | 731 	layer->setObjectName(name); | 
| Chris@45 | 732 | 
| Chris@45 | 733 	int modelId; | 
| Chris@45 | 734 	bool modelOk = false; | 
| Chris@45 | 735 	modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 736 | 
| Chris@45 | 737 	if (modelOk) { | 
| Chris@45 | 738 	    if (haveModel(modelId)) { | 
| Chris@45 | 739 		Model *model = m_models[modelId]; | 
| Chris@45 | 740 		m_document->setModel(layer, model); | 
| Chris@45 | 741 	    } else { | 
| Chris@45 | 742 		std::cerr << "WARNING: SV-XML: Unknown model id " << modelId | 
| Chris@45 | 743 			  << " in layer definition" << std::endl; | 
| Chris@45 | 744 	    } | 
| Chris@45 | 745 	} | 
| Chris@45 | 746 | 
| Chris@45 | 747 	layer->setProperties(attributes); | 
| Chris@45 | 748     } | 
| Chris@45 | 749 | 
| Chris@45 | 750     if (!m_inData && m_currentPane) { | 
| Chris@45 | 751 | 
| Chris@45 | 752         QString visible = attributes.value("visible"); | 
| Chris@45 | 753         bool dormant = (visible == "false"); | 
| Chris@45 | 754 | 
| Chris@45 | 755         // We need to do this both before and after adding the layer | 
| Chris@45 | 756         // to the view -- we need it to be dormant if appropriate | 
| Chris@45 | 757         // before it's actually added to the view so that any property | 
| Chris@45 | 758         // box gets the right state when it's added, but the add layer | 
| Chris@45 | 759         // command sets dormant to false because it assumes it may be | 
| Chris@45 | 760         // restoring a previously dormant layer, so we need to set it | 
| Chris@45 | 761         // again afterwards too.  Hm | 
| Chris@45 | 762         layer->setLayerDormant(m_currentPane, dormant); | 
| Chris@45 | 763 | 
| Chris@45 | 764 	m_document->addLayerToView(m_currentPane, layer); | 
| Chris@45 | 765 | 
| Chris@45 | 766         layer->setLayerDormant(m_currentPane, dormant); | 
| Chris@45 | 767     } | 
| Chris@45 | 768 | 
| Chris@45 | 769     m_currentLayer = layer; | 
| Chris@45 | 770     m_inLayer = true; | 
| Chris@45 | 771 | 
| Chris@45 | 772     return true; | 
| Chris@45 | 773 } | 
| Chris@45 | 774 | 
| Chris@45 | 775 bool | 
| Chris@45 | 776 SVFileReader::readDatasetStart(const QXmlAttributes &attributes) | 
| Chris@45 | 777 { | 
| Chris@45 | 778     bool ok = false; | 
| Chris@45 | 779 | 
| Chris@45 | 780     READ_MANDATORY(int, id, toInt); | 
| Chris@45 | 781     READ_MANDATORY(int, dimensions, toInt); | 
| Chris@45 | 782 | 
| Chris@45 | 783     if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) { | 
| Chris@45 | 784 	std::cerr << "WARNING: SV-XML: Unwanted dataset " << id << std::endl; | 
| Chris@45 | 785 	return false; | 
| Chris@45 | 786     } | 
| Chris@45 | 787 | 
| Chris@45 | 788     int modelId = m_awaitingDatasets[id]; | 
| Chris@45 | 789 | 
| Chris@45 | 790     Model *model = 0; | 
| Chris@45 | 791     if (haveModel(modelId)) { | 
| Chris@45 | 792 	model = m_models[modelId]; | 
| Chris@45 | 793     } else { | 
| Chris@45 | 794 	std::cerr << "WARNING: SV-XML: Internal error: Unknown model " << modelId | 
| Chris@45 | 795 		  << " expecting dataset " << id << std::endl; | 
| Chris@45 | 796 	return false; | 
| Chris@45 | 797     } | 
| Chris@45 | 798 | 
| Chris@45 | 799     bool good = false; | 
| Chris@45 | 800 | 
| Chris@45 | 801     switch (dimensions) { | 
| Chris@45 | 802     case 1: | 
| Chris@45 | 803 	if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true; | 
| Chris@45 | 804         else if (dynamic_cast<ImageModel *>(model)) good = true; | 
| Chris@45 | 805 	break; | 
| Chris@45 | 806 | 
| Chris@45 | 807     case 2: | 
| Chris@45 | 808 	if (dynamic_cast<SparseTimeValueModel *>(model)) good = true; | 
| Chris@45 | 809 	else if (dynamic_cast<TextModel *>(model)) good = true; | 
| Chris@45 | 810 	break; | 
| Chris@45 | 811 | 
| Chris@45 | 812     case 3: | 
| Chris@45 | 813 	if (dynamic_cast<NoteModel *>(model)) good = true; | 
| Chris@45 | 814 	else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) { | 
| Chris@45 | 815 	    m_datasetSeparator = attributes.value("separator"); | 
| Chris@45 | 816 	    good = true; | 
| Chris@45 | 817 	} | 
| Chris@45 | 818 	break; | 
| Chris@45 | 819     } | 
| Chris@45 | 820 | 
| Chris@45 | 821     if (!good) { | 
| Chris@45 | 822 	std::cerr << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << std::endl; | 
| Chris@45 | 823 	m_currentDataset = 0; | 
| Chris@45 | 824 	return false; | 
| Chris@45 | 825     } | 
| Chris@45 | 826 | 
| Chris@45 | 827     m_currentDataset = model; | 
| Chris@45 | 828     return true; | 
| Chris@45 | 829 } | 
| Chris@45 | 830 | 
| Chris@45 | 831 bool | 
| Chris@45 | 832 SVFileReader::addPointToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 833 { | 
| Chris@45 | 834     bool ok = false; | 
| Chris@45 | 835 | 
| Chris@45 | 836     READ_MANDATORY(int, frame, toInt); | 
| Chris@45 | 837 | 
| Chris@45 | 838 //    std::cerr << "SVFileReader::addPointToDataset: frame = " << frame << std::endl; | 
| Chris@45 | 839 | 
| Chris@45 | 840     SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 
| Chris@45 | 841 	(m_currentDataset); | 
| Chris@45 | 842 | 
| Chris@45 | 843     if (sodm) { | 
| Chris@45 | 844 //        std::cerr << "Current dataset is a sparse one dimensional model" << std::endl; | 
| Chris@45 | 845 	QString label = attributes.value("label"); | 
| Chris@45 | 846 	sodm->addPoint(SparseOneDimensionalModel::Point(frame, label)); | 
| Chris@45 | 847 	return true; | 
| Chris@45 | 848     } | 
| Chris@45 | 849 | 
| Chris@45 | 850     SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *> | 
| Chris@45 | 851 	(m_currentDataset); | 
| Chris@45 | 852 | 
| Chris@45 | 853     if (stvm) { | 
| Chris@45 | 854 //        std::cerr << "Current dataset is a sparse time-value model" << std::endl; | 
| Chris@45 | 855 	float value = 0.0; | 
| Chris@45 | 856 	value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@45 | 857 	QString label = attributes.value("label"); | 
| Chris@45 | 858 	stvm->addPoint(SparseTimeValueModel::Point(frame, value, label)); | 
| Chris@45 | 859 	return ok; | 
| Chris@45 | 860     } | 
| Chris@45 | 861 | 
| Chris@45 | 862     NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset); | 
| Chris@45 | 863 | 
| Chris@45 | 864     if (nm) { | 
| Chris@45 | 865 //        std::cerr << "Current dataset is a note model" << std::endl; | 
| Chris@45 | 866 	float value = 0.0; | 
| Chris@45 | 867 	value = attributes.value("value").trimmed().toFloat(&ok); | 
| Chris@45 | 868 	size_t duration = 0; | 
| Chris@45 | 869 	duration = attributes.value("duration").trimmed().toUInt(&ok); | 
| Chris@45 | 870 	QString label = attributes.value("label"); | 
| Chris@61 | 871         float level = attributes.value("level").trimmed().toFloat(&ok); | 
| Chris@61 | 872         if (!ok) { // level is optional | 
| Chris@61 | 873             level = 1.f; | 
| Chris@61 | 874             ok = true; | 
| Chris@61 | 875         } | 
| Chris@61 | 876 	nm->addPoint(NoteModel::Point(frame, value, duration, level, label)); | 
| Chris@45 | 877 	return ok; | 
| Chris@45 | 878     } | 
| Chris@45 | 879 | 
| Chris@45 | 880     TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset); | 
| Chris@45 | 881 | 
| Chris@45 | 882     if (tm) { | 
| Chris@45 | 883 //        std::cerr << "Current dataset is a text model" << std::endl; | 
| Chris@45 | 884 	float height = 0.0; | 
| Chris@45 | 885 	height = attributes.value("height").trimmed().toFloat(&ok); | 
| Chris@45 | 886 	QString label = attributes.value("label"); | 
| Chris@45 | 887 //        std::cerr << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label.toStdString() << ", ok = " << ok << std::endl; | 
| Chris@45 | 888 	tm->addPoint(TextModel::Point(frame, height, label)); | 
| Chris@45 | 889 	return ok; | 
| Chris@45 | 890     } | 
| Chris@45 | 891 | 
| Chris@45 | 892     ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset); | 
| Chris@45 | 893 | 
| Chris@45 | 894     if (im) { | 
| Chris@45 | 895 //        std::cerr << "Current dataset is an image model" << std::endl; | 
| Chris@45 | 896 	QString image = attributes.value("image"); | 
| Chris@45 | 897 	QString label = attributes.value("label"); | 
| Chris@45 | 898 //        std::cerr << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image.toStdString() << ", label = " << label.toStdString() << ", ok = " << ok << std::endl; | 
| Chris@45 | 899 	im->addPoint(ImageModel::Point(frame, image, label)); | 
| Chris@45 | 900 	return ok; | 
| Chris@45 | 901     } | 
| Chris@45 | 902 | 
| Chris@45 | 903     std::cerr << "WARNING: SV-XML: Point element found in non-point dataset" << std::endl; | 
| Chris@45 | 904 | 
| Chris@45 | 905     return false; | 
| Chris@45 | 906 } | 
| Chris@45 | 907 | 
| Chris@45 | 908 bool | 
| Chris@45 | 909 SVFileReader::addBinToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 910 { | 
| Chris@45 | 911     EditableDenseThreeDimensionalModel *dtdm = | 
| Chris@45 | 912         dynamic_cast<EditableDenseThreeDimensionalModel *> | 
| Chris@45 | 913 	(m_currentDataset); | 
| Chris@45 | 914 | 
| Chris@45 | 915     if (dtdm) { | 
| Chris@45 | 916 | 
| Chris@45 | 917 	bool ok = false; | 
| Chris@45 | 918 	int n = attributes.value("number").trimmed().toInt(&ok); | 
| Chris@45 | 919 	if (!ok) { | 
| Chris@45 | 920 	    std::cerr << "WARNING: SV-XML: Missing or invalid bin number" | 
| Chris@45 | 921 		      << std::endl; | 
| Chris@45 | 922 	    return false; | 
| Chris@45 | 923 	} | 
| Chris@45 | 924 | 
| Chris@45 | 925 	QString name = attributes.value("name"); | 
| Chris@45 | 926 | 
| Chris@45 | 927 	dtdm->setBinName(n, name); | 
| Chris@45 | 928 	return true; | 
| Chris@45 | 929     } | 
| Chris@45 | 930 | 
| Chris@45 | 931     std::cerr << "WARNING: SV-XML: Bin definition found in incompatible dataset" << std::endl; | 
| Chris@45 | 932 | 
| Chris@45 | 933     return false; | 
| Chris@45 | 934 } | 
| Chris@45 | 935 | 
| Chris@45 | 936 | 
| Chris@45 | 937 bool | 
| Chris@45 | 938 SVFileReader::addRowToDataset(const QXmlAttributes &attributes) | 
| Chris@45 | 939 { | 
| Chris@45 | 940     m_inRow = false; | 
| Chris@45 | 941 | 
| Chris@45 | 942     bool ok = false; | 
| Chris@45 | 943     m_rowNumber = attributes.value("n").trimmed().toInt(&ok); | 
| Chris@45 | 944     if (!ok) { | 
| Chris@45 | 945 	std::cerr << "WARNING: SV-XML: Missing or invalid row number" | 
| Chris@45 | 946 		  << std::endl; | 
| Chris@45 | 947 	return false; | 
| Chris@45 | 948     } | 
| Chris@45 | 949 | 
| Chris@45 | 950     m_inRow = true; | 
| Chris@45 | 951 | 
| Chris@45 | 952 //    std::cerr << "SV-XML: In row " << m_rowNumber << std::endl; | 
| Chris@45 | 953 | 
| Chris@45 | 954     return true; | 
| Chris@45 | 955 } | 
| Chris@45 | 956 | 
| Chris@45 | 957 bool | 
| Chris@45 | 958 SVFileReader::readRowData(const QString &text) | 
| Chris@45 | 959 { | 
| Chris@45 | 960     EditableDenseThreeDimensionalModel *dtdm = | 
| Chris@45 | 961         dynamic_cast<EditableDenseThreeDimensionalModel *> | 
| Chris@45 | 962 	(m_currentDataset); | 
| Chris@45 | 963 | 
| Chris@45 | 964     bool warned = false; | 
| Chris@45 | 965 | 
| Chris@45 | 966     if (dtdm) { | 
| Chris@45 | 967 	QStringList data = text.split(m_datasetSeparator); | 
| Chris@45 | 968 | 
| Chris@45 | 969 	DenseThreeDimensionalModel::Column values; | 
| Chris@45 | 970 | 
| Chris@45 | 971 	for (QStringList::iterator i = data.begin(); i != data.end(); ++i) { | 
| Chris@45 | 972 | 
| Chris@45 | 973 	    if (values.size() == dtdm->getHeight()) { | 
| Chris@45 | 974 		if (!warned) { | 
| Chris@45 | 975 		    std::cerr << "WARNING: SV-XML: Too many y-bins in 3-D dataset row " | 
| Chris@45 | 976 			      << m_rowNumber << std::endl; | 
| Chris@45 | 977 		    warned = true; | 
| Chris@45 | 978 		} | 
| Chris@45 | 979 	    } | 
| Chris@45 | 980 | 
| Chris@45 | 981 	    bool ok; | 
| Chris@45 | 982 	    float value = i->toFloat(&ok); | 
| Chris@45 | 983 	    if (!ok) { | 
| Chris@45 | 984 		std::cerr << "WARNING: SV-XML: Bad floating-point value " | 
| Chris@45 | 985 			  << i->toLocal8Bit().data() | 
| Chris@45 | 986 			  << " in row data" << std::endl; | 
| Chris@45 | 987 	    } else { | 
| Chris@45 | 988 		values.push_back(value); | 
| Chris@45 | 989 	    } | 
| Chris@45 | 990 	} | 
| Chris@45 | 991 | 
| Chris@45 | 992 	dtdm->setColumn(m_rowNumber, values); | 
| Chris@45 | 993 	return true; | 
| Chris@45 | 994     } | 
| Chris@45 | 995 | 
| Chris@45 | 996     std::cerr << "WARNING: SV-XML: Row data found in non-row dataset" << std::endl; | 
| Chris@45 | 997 | 
| Chris@45 | 998     return false; | 
| Chris@45 | 999 } | 
| Chris@45 | 1000 | 
| Chris@45 | 1001 bool | 
| Chris@45 | 1002 SVFileReader::readDerivation(const QXmlAttributes &attributes) | 
| Chris@45 | 1003 { | 
| Chris@45 | 1004     int modelId = 0; | 
| Chris@45 | 1005     bool modelOk = false; | 
| Chris@45 | 1006     modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 1007 | 
| Chris@45 | 1008     if (!modelOk) { | 
| Chris@45 | 1009 	std::cerr << "WARNING: SV-XML: No model id specified for derivation" << std::endl; | 
| Chris@45 | 1010 	return false; | 
| Chris@45 | 1011     } | 
| Chris@45 | 1012 | 
| Chris@45 | 1013     if (haveModel(modelId)) { | 
| Chris@45 | 1014         m_currentDerivedModel = m_models[modelId]; | 
| Chris@45 | 1015     } else { | 
| Chris@45 | 1016         // we'll regenerate the model when the derivation element ends | 
| Chris@45 | 1017         m_currentDerivedModel = 0; | 
| Chris@45 | 1018     } | 
| Chris@45 | 1019 | 
| Chris@45 | 1020     m_currentDerivedModelId = modelId; | 
| Chris@45 | 1021 | 
| Chris@45 | 1022     int sourceId = 0; | 
| Chris@45 | 1023     bool sourceOk = false; | 
| Chris@45 | 1024     sourceId = attributes.value("source").trimmed().toInt(&sourceOk); | 
| Chris@45 | 1025 | 
| Chris@45 | 1026     if (sourceOk && haveModel(sourceId)) { | 
| Chris@72 | 1027         m_currentTransformSource = m_models[sourceId]; | 
| Chris@45 | 1028     } else { | 
| Chris@72 | 1029         m_currentTransformSource = m_document->getMainModel(); | 
| Chris@45 | 1030     } | 
| Chris@45 | 1031 | 
| Chris@72 | 1032     m_currentTransform = Transform(); | 
| Chris@45 | 1033 | 
| Chris@45 | 1034     bool ok = false; | 
| Chris@45 | 1035     int channel = attributes.value("channel").trimmed().toInt(&ok); | 
| Chris@72 | 1036     if (ok) m_currentTransformChannel = channel; | 
| Chris@72 | 1037     else m_currentTransformChannel = -1; | 
| Chris@45 | 1038 | 
| Chris@72 | 1039     QString type = attributes.value("type"); | 
| Chris@72 | 1040 | 
| Chris@72 | 1041     if (type == "transform") { | 
| Chris@72 | 1042         m_currentTransformIsNewStyle = true; | 
| Chris@72 | 1043         return true; | 
| Chris@72 | 1044     } else { | 
| Chris@72 | 1045         m_currentTransformIsNewStyle = false; | 
| Chris@72 | 1046         std::cerr << "NOTE: SV-XML: Reading old-style derivation element" | 
| Chris@72 | 1047                   << std::endl; | 
| Chris@72 | 1048     } | 
| Chris@72 | 1049 | 
| Chris@72 | 1050     QString transformId = attributes.value("transform"); | 
| Chris@72 | 1051 | 
| Chris@72 | 1052     m_currentTransform.setIdentifier(transformId); | 
| Chris@45 | 1053 | 
| Chris@45 | 1054     int stepSize = attributes.value("stepSize").trimmed().toInt(&ok); | 
| Chris@72 | 1055     if (ok) m_currentTransform.setStepSize(stepSize); | 
| Chris@45 | 1056 | 
| Chris@45 | 1057     int blockSize = attributes.value("blockSize").trimmed().toInt(&ok); | 
| Chris@72 | 1058     if (ok) m_currentTransform.setBlockSize(blockSize); | 
| Chris@45 | 1059 | 
| Chris@45 | 1060     int windowType = attributes.value("windowType").trimmed().toInt(&ok); | 
| Chris@72 | 1061     if (ok) m_currentTransform.setWindowType(WindowType(windowType)); | 
| Chris@72 | 1062 | 
| Chris@72 | 1063     if (!m_currentTransformSource) return true; | 
| Chris@45 | 1064 | 
| Chris@45 | 1065     QString startFrameStr = attributes.value("startFrame"); | 
| Chris@45 | 1066     QString durationStr = attributes.value("duration"); | 
| Chris@45 | 1067 | 
| Chris@45 | 1068     size_t startFrame = 0; | 
| Chris@45 | 1069     size_t duration = 0; | 
| Chris@45 | 1070 | 
| Chris@45 | 1071     if (startFrameStr != "") { | 
| Chris@45 | 1072         startFrame = startFrameStr.trimmed().toInt(&ok); | 
| Chris@45 | 1073         if (!ok) startFrame = 0; | 
| Chris@45 | 1074     } | 
| Chris@45 | 1075     if (durationStr != "") { | 
| Chris@45 | 1076         duration = durationStr.trimmed().toInt(&ok); | 
| Chris@45 | 1077         if (!ok) duration = 0; | 
| Chris@45 | 1078     } | 
| Chris@45 | 1079 | 
| Chris@72 | 1080     m_currentTransform.setStartTime | 
| Chris@72 | 1081         (RealTime::frame2RealTime | 
| Chris@72 | 1082          (startFrame, m_currentTransformSource->getSampleRate())); | 
| Chris@72 | 1083 | 
| Chris@72 | 1084     m_currentTransform.setDuration | 
| Chris@72 | 1085         (RealTime::frame2RealTime | 
| Chris@72 | 1086          (duration, m_currentTransformSource->getSampleRate())); | 
| Chris@45 | 1087 | 
| Chris@45 | 1088     return true; | 
| Chris@45 | 1089 } | 
| Chris@45 | 1090 | 
| Chris@45 | 1091 bool | 
| Chris@45 | 1092 SVFileReader::readPlayParameters(const QXmlAttributes &attributes) | 
| Chris@45 | 1093 { | 
| Chris@45 | 1094     m_currentPlayParameters = 0; | 
| Chris@45 | 1095 | 
| Chris@45 | 1096     int modelId = 0; | 
| Chris@45 | 1097     bool modelOk = false; | 
| Chris@45 | 1098     modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| Chris@45 | 1099 | 
| Chris@45 | 1100     if (!modelOk) { | 
| Chris@45 | 1101 	std::cerr << "WARNING: SV-XML: No model id specified for play parameters" << std::endl; | 
| Chris@45 | 1102 	return false; | 
| Chris@45 | 1103     } | 
| Chris@45 | 1104 | 
| Chris@45 | 1105     if (haveModel(modelId)) { | 
| Chris@45 | 1106 | 
| Chris@45 | 1107         bool ok = false; | 
| Chris@45 | 1108 | 
| Chris@45 | 1109         PlayParameters *parameters = PlayParameterRepository::getInstance()-> | 
| Chris@45 | 1110             getPlayParameters(m_models[modelId]); | 
| Chris@45 | 1111 | 
| Chris@45 | 1112         if (!parameters) { | 
| Chris@45 | 1113             std::cerr << "WARNING: SV-XML: Play parameters for model " | 
| Chris@45 | 1114                       << modelId | 
| Chris@45 | 1115                       << " not found - has model been added to document?" | 
| Chris@45 | 1116                       << std::endl; | 
| Chris@45 | 1117             return false; | 
| Chris@45 | 1118         } | 
| Chris@45 | 1119 | 
| Chris@45 | 1120         bool muted = (attributes.value("mute").trimmed() == "true"); | 
| Chris@45 | 1121         parameters->setPlayMuted(muted); | 
| Chris@45 | 1122 | 
| Chris@45 | 1123         float pan = attributes.value("pan").toFloat(&ok); | 
| Chris@45 | 1124         if (ok) parameters->setPlayPan(pan); | 
| Chris@45 | 1125 | 
| Chris@45 | 1126         float gain = attributes.value("gain").toFloat(&ok); | 
| Chris@45 | 1127         if (ok) parameters->setPlayGain(gain); | 
| Chris@45 | 1128 | 
| Chris@45 | 1129         QString pluginId = attributes.value("pluginId"); | 
| Chris@45 | 1130         if (pluginId != "") parameters->setPlayPluginId(pluginId); | 
| Chris@45 | 1131 | 
| Chris@45 | 1132         m_currentPlayParameters = parameters; | 
| Chris@45 | 1133 | 
| Chris@45 | 1134 //        std::cerr << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << std::endl; | 
| Chris@45 | 1135 | 
| Chris@45 | 1136     } else { | 
| Chris@45 | 1137 | 
| Chris@45 | 1138 	std::cerr << "WARNING: SV-XML: Unknown model " << modelId | 
| Chris@45 | 1139 		  << " for play parameters" << std::endl; | 
| Chris@45 | 1140         return false; | 
| Chris@45 | 1141     } | 
| Chris@45 | 1142 | 
| Chris@45 | 1143     return true; | 
| Chris@45 | 1144 } | 
| Chris@45 | 1145 | 
| Chris@45 | 1146 bool | 
| Chris@45 | 1147 SVFileReader::readPlugin(const QXmlAttributes &attributes) | 
| Chris@45 | 1148 { | 
| Chris@45 | 1149     if (m_currentDerivedModelId < 0 && !m_currentPlayParameters) { | 
| Chris@45 | 1150         std::cerr << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << std::endl; | 
| Chris@45 | 1151         return false; | 
| Chris@45 | 1152     } | 
| Chris@45 | 1153 | 
| Chris@72 | 1154     if (!m_currentPlayParameters && m_currentTransformIsNewStyle) { | 
| Chris@72 | 1155         return true; | 
| Chris@72 | 1156     } | 
| Chris@72 | 1157 | 
| Chris@45 | 1158     QString configurationXml = "<plugin"; | 
| Chris@45 | 1159 | 
| Chris@45 | 1160     for (int i = 0; i < attributes.length(); ++i) { | 
| Chris@45 | 1161         configurationXml += QString(" %1=\"%2\"") | 
| Chris@45 | 1162             .arg(attributes.qName(i)) | 
| Chris@45 | 1163             .arg(XmlExportable::encodeEntities(attributes.value(i))); | 
| Chris@45 | 1164     } | 
| Chris@45 | 1165 | 
| Chris@45 | 1166     configurationXml += "/>"; | 
| Chris@45 | 1167 | 
| Chris@45 | 1168     if (m_currentPlayParameters) { | 
| Chris@45 | 1169         m_currentPlayParameters->setPlayPluginConfiguration(configurationXml); | 
| Chris@45 | 1170     } else { | 
| Chris@72 | 1171         TransformFactory::getInstance()-> | 
| Chris@72 | 1172             setParametersFromPluginConfigurationXml(m_currentTransform, | 
| Chris@72 | 1173                                                     configurationXml); | 
| Chris@45 | 1174     } | 
| Chris@45 | 1175 | 
| Chris@45 | 1176     return true; | 
| Chris@45 | 1177 } | 
| Chris@45 | 1178 | 
| Chris@45 | 1179 bool | 
| Chris@72 | 1180 SVFileReader::readTransform(const QXmlAttributes &attributes) | 
| Chris@72 | 1181 { | 
| Chris@72 | 1182     if (m_currentDerivedModelId < 0) { | 
| Chris@72 | 1183         std::cerr << "WARNING: SV-XML: Transform found outside derivation" << std::endl; | 
| Chris@72 | 1184         return false; | 
| Chris@72 | 1185     } | 
| Chris@72 | 1186 | 
| Chris@72 | 1187     m_currentTransform.setFromXmlAttributes(attributes); | 
| Chris@72 | 1188     return true; | 
| Chris@72 | 1189 } | 
| Chris@72 | 1190 | 
| Chris@72 | 1191 bool | 
| Chris@72 | 1192 SVFileReader::readParameter(const QXmlAttributes &attributes) | 
| Chris@72 | 1193 { | 
| Chris@72 | 1194     if (m_currentDerivedModelId < 0) { | 
| Chris@72 | 1195         std::cerr << "WARNING: SV-XML: Parameter found outside derivation" << std::endl; | 
| Chris@72 | 1196         return false; | 
| Chris@72 | 1197     } | 
| Chris@72 | 1198 | 
| Chris@72 | 1199     QString name = attributes.value("name"); | 
| Chris@72 | 1200     if (name == "") { | 
| Chris@72 | 1201         std::cerr << "WARNING: SV-XML: Ignoring nameless transform parameter" | 
| Chris@72 | 1202                   << std::endl; | 
| Chris@72 | 1203         return false; | 
| Chris@72 | 1204     } | 
| Chris@72 | 1205 | 
| Chris@72 | 1206     float value = attributes.value("value").trimmed().toFloat(); | 
| Chris@72 | 1207 | 
| Chris@72 | 1208     m_currentTransform.setParameter(name, value); | 
| Chris@72 | 1209     return true; | 
| Chris@72 | 1210 } | 
| Chris@72 | 1211 | 
| Chris@72 | 1212 bool | 
| Chris@45 | 1213 SVFileReader::readSelection(const QXmlAttributes &attributes) | 
| Chris@45 | 1214 { | 
| Chris@45 | 1215     bool ok; | 
| Chris@45 | 1216 | 
| Chris@45 | 1217     READ_MANDATORY(int, start, toInt); | 
| Chris@45 | 1218     READ_MANDATORY(int, end, toInt); | 
| Chris@45 | 1219 | 
| Chris@45 | 1220     m_paneCallback.addSelection(start, end); | 
| Chris@45 | 1221 | 
| Chris@45 | 1222     return true; | 
| Chris@45 | 1223 } | 
| Chris@45 | 1224 | 
| Chris@45 | 1225 bool | 
| Chris@45 | 1226 SVFileReader::readMeasurement(const QXmlAttributes &attributes) | 
| Chris@45 | 1227 { | 
| Chris@45 | 1228     std::cerr << "SVFileReader::readMeasurement: inLayer " | 
| Chris@45 | 1229               << m_inLayer << ", layer " << m_currentLayer << std::endl; | 
| Chris@45 | 1230 | 
| Chris@45 | 1231     if (!m_inLayer) { | 
| Chris@45 | 1232         std::cerr << "WARNING: SV-XML: Measurement found outside layer" << std::endl; | 
| Chris@45 | 1233         return false; | 
| Chris@45 | 1234     } | 
| Chris@45 | 1235 | 
| Chris@45 | 1236     m_currentLayer->addMeasurementRect(attributes); | 
| Chris@45 | 1237     return true; | 
| Chris@45 | 1238 } | 
| Chris@45 | 1239 | 
| Chris@45 | 1240 SVFileReaderPaneCallback::~SVFileReaderPaneCallback() | 
| Chris@45 | 1241 { | 
| Chris@45 | 1242 } | 
| Chris@45 | 1243 |