annotate framework/SVFileReader.cpp @ 588:d122d3595a32

Store aggregate models in the document and release them when they are invalidated (because their components have been released). They're no longer leaked, but we still don't save them in the session file.
author Chris Cannam
date Mon, 27 Feb 2017 16:26:37 +0000
parents 050c7b5bd11c
children c196680910dc
rev   line source
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@45 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@45 102
Chris@45 103 SVFileReader::~SVFileReader()
Chris@45 104 {
Chris@45 105 if (!m_awaitingDatasets.empty()) {
Chris@293 106 cerr << "WARNING: SV-XML: File ended with "
Chris@45 107 << m_awaitingDatasets.size() << " unfilled model dataset(s)"
Chris@293 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@45 114 i != m_models.end(); ++i) {
Chris@45 115 if (m_addedModels.find(i->second) == m_addedModels.end()) {
Chris@45 116 unaddedModels.insert(i->second);
Chris@45 117 }
Chris@45 118 }
Chris@45 119
Chris@45 120 if (!unaddedModels.empty()) {
Chris@293 121 cerr << "WARNING: SV-XML: File contained "
Chris@45 122 << unaddedModels.size() << " unused models"
Chris@293 123 << endl;
Chris@45 124 while (!unaddedModels.empty()) {
Chris@45 125 delete *unaddedModels.begin();
Chris@45 126 unaddedModels.erase(unaddedModels.begin());
Chris@45 127 }
Chris@45 128 }
Chris@45 129 }
Chris@45 130
Chris@45 131 bool
Chris@45 132 SVFileReader::startElement(const QString &, const QString &,
Chris@45 133 const QString &qName,
Chris@45 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@45 162 // nothing needed
Chris@45 163 ok = true;
Chris@45 164
Chris@45 165 } else if (name == "data") {
Chris@45 166
Chris@45 167 // nothing needed
Chris@45 168 m_inData = true;
Chris@45 169 ok = true;
Chris@45 170
Chris@45 171 } else if (name == "display") {
Chris@45 172
Chris@45 173 // nothing needed
Chris@45 174 ok = true;
Chris@45 175
Chris@45 176 } else if (name == "window") {
Chris@45 177
Chris@45 178 ok = readWindow(attributes);
Chris@45 179
Chris@45 180 } else if (name == "model") {
Chris@45 181
Chris@45 182 ok = readModel(attributes);
Chris@45 183
Chris@45 184 } else if (name == "dataset") {
Chris@45 185
Chris@45 186 ok = readDatasetStart(attributes);
Chris@45 187
Chris@45 188 } else if (name == "bin") {
Chris@45 189
Chris@45 190 ok = addBinToDataset(attributes);
Chris@45 191
Chris@45 192 } else if (name == "point") {
Chris@45 193
Chris@45 194 ok = addPointToDataset(attributes);
Chris@45 195
Chris@45 196 } else if (name == "row") {
Chris@45 197
Chris@45 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@45 203 ok = readLayer(attributes);
Chris@45 204
Chris@45 205 } else if (name == "view") {
Chris@45 206
Chris@45 207 m_inView = true;
Chris@45 208 ok = readView(attributes);
Chris@45 209
Chris@45 210 } else if (name == "derivation") {
Chris@45 211
Chris@45 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@45 220 ok = readPlugin(attributes);
Chris@45 221
Chris@45 222 } else if (name == "selections") {
Chris@45 223
Chris@45 224 m_inSelections = true;
Chris@45 225 ok = true;
Chris@45 226
Chris@45 227 } else if (name == "selection") {
Chris@45 228
Chris@45 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@293 244 cerr << "WARNING: SV-XML: Unexpected element \""
Chris@294 245 << name << "\"" << endl;
Chris@45 246 }
Chris@45 247
Chris@45 248 if (!ok) {
Chris@293 249 cerr << "WARNING: SV-XML: Failed to completely process element \""
Chris@294 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@45 262 ok = readRowData(text);
Chris@45 263 if (!ok) {
Chris@293 264 cerr << "WARNING: SV-XML: Failed to read row data content for row " << m_rowNumber << endl;
Chris@45 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@45 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@45 279 if (m_currentDataset) {
Chris@45 280
Chris@45 281 bool foundInAwaiting = false;
Chris@45 282
Chris@45 283 for (std::map<int, int>::iterator i = m_awaitingDatasets.begin();
Chris@45 284 i != m_awaitingDatasets.end(); ++i) {
Chris@45 285 if (haveModel(i->second) &&
Chris@45 286 m_models[i->second] == m_currentDataset) {
Chris@45 287 m_awaitingDatasets.erase(i);
Chris@45 288 foundInAwaiting = true;
Chris@45 289 break;
Chris@45 290 }
Chris@45 291 }
Chris@45 292
Chris@45 293 if (!foundInAwaiting) {
Chris@293 294 cerr << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl;
Chris@45 295 }
Chris@45 296 }
Chris@45 297
Chris@45 298 m_currentDataset = 0;
Chris@45 299
Chris@45 300 } else if (name == "data") {
Chris@45 301
Chris@45 302 addUnaddedModels();
Chris@45 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@293 309 cerr << "WARNING: SV-XML: Bad derivation output model id "
Chris@293 310 << m_currentDerivedModelId << endl;
Chris@45 311 } else if (haveModel(m_currentDerivedModelId)) {
Chris@293 312 cerr << "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@45 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@45 353 m_inView = false;
Chris@45 354 } else if (name == "selections") {
Chris@45 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@45 367 QString("ERROR: SV-XML: %1 at line %2, column %3")
Chris@45 368 .arg(exception.message())
Chris@45 369 .arg(exception.lineNumber())
Chris@45 370 .arg(exception.columnNumber());
Chris@294 371 cerr << 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@45 379 QString("FATAL ERROR: SV-XML: %1 at line %2, column %3")
Chris@45 380 .arg(exception.message())
Chris@45 381 .arg(exception.lineNumber())
Chris@45 382 .arg(exception.columnNumber());
Chris@294 383 cerr << m_errorString << endl;
Chris@45 384 return QXmlDefaultHandler::fatalError(exception);
Chris@45 385 }
Chris@45 386
Chris@45 387
Chris@45 388 #define READ_MANDATORY(TYPE, NAME, CONVERSION) \
Chris@45 389 TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \
Chris@45 390 if (!ok) { \
Chris@293 391 cerr << "WARNING: SV-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << endl; \
Chris@45 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@293 442 cerr << "WARNING: SV-XML: Ignoring duplicate model id " << id
Chris@293 443 << endl;
Chris@45 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@45 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@293 472 cerr << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: " << file.getErrorString() << endl;
Chris@45 473 } else if (!file.isAvailable()) {
Chris@293 474 cerr << "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@45 497 if (!model) return false;
Chris@45 498
Chris@45 499 model->setObjectName(name);
Chris@45 500 m_models[id] = model;
Chris@362 501 if (isMainModel) {
Chris@45 502 m_document->setMainModel(model);
Chris@45 503 m_addedModels.insert(model);
Chris@45 504 }
Chris@45 505 // Derived models will be added when their derivation
Chris@45 506 // is found.
Chris@45 507
Chris@45 508 return true;
Chris@45 509
Chris@45 510 } else if (type == "dense") {
Chris@45 511
Chris@45 512 READ_MANDATORY(int, dimensions, toInt);
Chris@45 513
Chris@45 514 // Currently the only dense model we support here is the dense
Chris@45 515 // 3d model. Dense time-value models are always file-backed
Chris@45 516 // waveform data, at this point, and they come in as wavefile
Chris@45 517 // models.
Chris@45 518
Chris@45 519 if (dimensions == 3) {
Chris@45 520
Chris@45 521 READ_MANDATORY(int, windowSize, toInt);
Chris@45 522 READ_MANDATORY(int, yBinCount, toInt);
Chris@45 523
Chris@45 524 EditableDenseThreeDimensionalModel *model =
Chris@45 525 new EditableDenseThreeDimensionalModel
Chris@153 526 (sampleRate, windowSize, yBinCount,
Chris@153 527 EditableDenseThreeDimensionalModel::NoCompression);
Chris@45 528
Chris@45 529 float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
Chris@45 530 if (ok) model->setMinimumLevel(minimum);
Chris@45 531
Chris@45 532 float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
Chris@45 533 if (ok) model->setMaximumLevel(maximum);
Chris@45 534
Chris@45 535 int dataset = attributes.value("dataset").trimmed().toInt(&ok);
Chris@45 536 if (ok) m_awaitingDatasets[dataset] = id;
Chris@45 537
Chris@181 538 int startFrame = attributes.value("startFrame").trimmed().toInt(&ok);
Chris@181 539 if (ok) model->setStartFrame(startFrame);
Chris@181 540
Chris@45 541 model->setObjectName(name);
Chris@45 542 m_models[id] = model;
Chris@45 543 return true;
Chris@45 544
Chris@45 545 } else {
Chris@45 546
Chris@293 547 cerr << "WARNING: SV-XML: Unexpected dense model dimension ("
Chris@293 548 << dimensions << ")" << endl;
Chris@45 549 }
Chris@45 550 } else if (type == "sparse") {
Chris@45 551
Chris@45 552 READ_MANDATORY(int, dimensions, toInt);
Chris@45 553
Chris@45 554 if (dimensions == 1) {
Chris@45 555
Chris@45 556 READ_MANDATORY(int, resolution, toInt);
Chris@45 557
Chris@45 558 if (attributes.value("subtype") == "image") {
Chris@45 559
Chris@45 560 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
Chris@45 561 ImageModel *model = new ImageModel(sampleRate, resolution,
Chris@45 562 notifyOnAdd);
Chris@45 563 model->setObjectName(name);
Chris@45 564 m_models[id] = model;
Chris@45 565
Chris@45 566 } else {
Chris@45 567
Chris@45 568 SparseOneDimensionalModel *model = new SparseOneDimensionalModel
Chris@45 569 (sampleRate, resolution);
Chris@45 570 model->setObjectName(name);
Chris@45 571 m_models[id] = model;
Chris@45 572 }
Chris@45 573
Chris@45 574 int dataset = attributes.value("dataset").trimmed().toInt(&ok);
Chris@45 575 if (ok) m_awaitingDatasets[dataset] = id;
Chris@45 576
Chris@45 577 return true;
Chris@45 578
Chris@45 579 } else if (dimensions == 2 || dimensions == 3) {
Chris@45 580
Chris@45 581 READ_MANDATORY(int, resolution, toInt);
Chris@45 582
Chris@45 583 bool haveMinMax = true;
Chris@45 584 float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
Chris@45 585 if (!ok) haveMinMax = false;
Chris@45 586 float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
Chris@45 587 if (!ok) haveMinMax = false;
Chris@45 588
Chris@45 589 float valueQuantization =
Chris@45 590 attributes.value("valueQuantization").trimmed().toFloat(&ok);
Chris@45 591
Chris@45 592 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
Chris@45 593
Chris@45 594 QString units = attributes.value("units");
Chris@45 595
Chris@45 596 if (dimensions == 2) {
Chris@45 597 if (attributes.value("subtype") == "text") {
Chris@45 598 TextModel *model = new TextModel
Chris@45 599 (sampleRate, resolution, notifyOnAdd);
Chris@45 600 model->setObjectName(name);
Chris@45 601 m_models[id] = model;
Chris@111 602 } else if (attributes.value("subtype") == "path") {
Chris@111 603 PathModel *model = new PathModel
Chris@111 604 (sampleRate, resolution, notifyOnAdd);
Chris@111 605 model->setObjectName(name);
Chris@111 606 m_models[id] = model;
Chris@45 607 } else {
Chris@45 608 SparseTimeValueModel *model;
Chris@45 609 if (haveMinMax) {
Chris@45 610 model = new SparseTimeValueModel
Chris@45 611 (sampleRate, resolution, minimum, maximum, notifyOnAdd);
Chris@45 612 } else {
Chris@45 613 model = new SparseTimeValueModel
Chris@45 614 (sampleRate, resolution, notifyOnAdd);
Chris@45 615 }
Chris@45 616 model->setScaleUnits(units);
Chris@45 617 model->setObjectName(name);
Chris@45 618 m_models[id] = model;
Chris@45 619 }
Chris@45 620 } else {
Chris@137 621 if (attributes.value("subtype") == "region") {
Chris@137 622 RegionModel *model;
Chris@137 623 if (haveMinMax) {
Chris@137 624 model = new RegionModel
Chris@137 625 (sampleRate, resolution, minimum, maximum, notifyOnAdd);
Chris@137 626 } else {
Chris@137 627 model = new RegionModel
Chris@137 628 (sampleRate, resolution, notifyOnAdd);
Chris@137 629 }
Chris@137 630 model->setValueQuantization(valueQuantization);
Chris@137 631 model->setScaleUnits(units);
Chris@137 632 model->setObjectName(name);
Chris@137 633 m_models[id] = model;
Chris@343 634 } else if (attributes.value("subtype") == "flexinote") {
Chris@343 635 FlexiNoteModel *model;
Chris@343 636 if (haveMinMax) {
Chris@343 637 model = new FlexiNoteModel
Chris@343 638 (sampleRate, resolution, minimum, maximum, notifyOnAdd);
Chris@343 639 } else {
Chris@343 640 model = new FlexiNoteModel
Chris@343 641 (sampleRate, resolution, notifyOnAdd);
Chris@343 642 }
Chris@343 643 model->setValueQuantization(valueQuantization);
Chris@343 644 model->setScaleUnits(units);
Chris@343 645 model->setObjectName(name);
Chris@343 646 m_models[id] = model;
Chris@45 647 } else {
Chris@137 648 // note models written out by SV 1.3 and earlier
Chris@137 649 // have no subtype, so we can't test that
Chris@137 650 NoteModel *model;
Chris@137 651 if (haveMinMax) {
Chris@137 652 model = new NoteModel
Chris@137 653 (sampleRate, resolution, minimum, maximum, notifyOnAdd);
Chris@137 654 } else {
Chris@137 655 model = new NoteModel
Chris@137 656 (sampleRate, resolution, notifyOnAdd);
Chris@137 657 }
Chris@137 658 model->setValueQuantization(valueQuantization);
Chris@137 659 model->setScaleUnits(units);
Chris@137 660 model->setObjectName(name);
Chris@137 661 m_models[id] = model;
Chris@45 662 }
Chris@137 663 }
Chris@45 664
Chris@45 665 int dataset = attributes.value("dataset").trimmed().toInt(&ok);
Chris@45 666 if (ok) m_awaitingDatasets[dataset] = id;
Chris@45 667
Chris@45 668 return true;
Chris@45 669
Chris@45 670 } else {
Chris@45 671
Chris@293 672 cerr << "WARNING: SV-XML: Unexpected sparse model dimension ("
Chris@293 673 << dimensions << ")" << endl;
Chris@45 674 }
Chris@111 675
Chris@111 676 } else if (type == "alignment") {
Chris@111 677
Chris@111 678 READ_MANDATORY(int, reference, toInt);
Chris@111 679 READ_MANDATORY(int, aligned, toInt);
Chris@111 680 READ_MANDATORY(int, path, toInt);
Chris@111 681
Chris@111 682 Model *refModel = 0, *alignedModel = 0, *pathModel = 0;
Chris@111 683
Chris@111 684 if (m_models.find(reference) != m_models.end()) {
Chris@111 685 refModel = m_models[reference];
Chris@111 686 } else {
Chris@293 687 cerr << "WARNING: SV-XML: Unknown reference model id "
Chris@111 688 << reference << " in alignment model id " << id
Chris@293 689 << endl;
Chris@111 690 }
Chris@111 691
Chris@111 692 if (m_models.find(aligned) != m_models.end()) {
Chris@111 693 alignedModel = m_models[aligned];
Chris@111 694 } else {
Chris@293 695 cerr << "WARNING: SV-XML: Unknown aligned model id "
Chris@111 696 << aligned << " in alignment model id " << id
Chris@293 697 << endl;
Chris@111 698 }
Chris@111 699
Chris@111 700 if (m_models.find(path) != m_models.end()) {
Chris@111 701 pathModel = m_models[path];
Chris@111 702 } else {
Chris@293 703 cerr << "WARNING: SV-XML: Unknown path model id "
Chris@111 704 << path << " in alignment model id " << id
Chris@293 705 << endl;
Chris@111 706 }
Chris@111 707
Chris@111 708 if (refModel && alignedModel && pathModel) {
Chris@111 709 AlignmentModel *model = new AlignmentModel
Chris@111 710 (refModel, alignedModel, 0, 0);
Chris@111 711 PathModel *pm = dynamic_cast<PathModel *>(pathModel);
Chris@111 712 if (!pm) {
Chris@293 713 cerr << "WARNING: SV-XML: Model id " << path
Chris@111 714 << " referenced as path for alignment " << id
Chris@293 715 << " is not a path model" << endl;
Chris@111 716 } else {
Chris@111 717 model->setPath(pm);
Chris@111 718 pm->setCompletion(100);
Chris@111 719 }
Chris@111 720 model->setObjectName(name);
Chris@111 721 m_models[id] = model;
Chris@111 722 alignedModel->setAlignment(model);
Chris@111 723 return true;
Chris@111 724 }
Chris@111 725
Chris@45 726 } else {
Chris@45 727
Chris@293 728 cerr << "WARNING: SV-XML: Unexpected model type \""
Chris@294 729 << type << "\" for model id " << id << endl;
Chris@45 730 }
Chris@45 731
Chris@45 732 return false;
Chris@45 733 }
Chris@45 734
Chris@45 735 bool
Chris@45 736 SVFileReader::readView(const QXmlAttributes &attributes)
Chris@45 737 {
Chris@45 738 QString type = attributes.value("type");
Chris@45 739 m_currentPane = 0;
Chris@45 740
Chris@45 741 if (type != "pane") {
Chris@293 742 cerr << "WARNING: SV-XML: Unexpected view type \""
Chris@294 743 << type << "\"" << endl;
Chris@45 744 return false;
Chris@45 745 }
Chris@45 746
Chris@45 747 m_currentPane = m_paneCallback.addPane();
Chris@45 748
Chris@342 749 cerr << "SVFileReader::addPane: pane is " << m_currentPane << endl;
Chris@342 750
Chris@45 751 if (!m_currentPane) {
Chris@293 752 cerr << "WARNING: SV-XML: Internal error: Failed to add pane!"
Chris@293 753 << endl;
Chris@45 754 return false;
Chris@45 755 }
Chris@45 756
Chris@45 757 bool ok = false;
Chris@45 758
Chris@45 759 View *view = m_currentPane;
Chris@45 760
Chris@45 761 // The view properties first
Chris@45 762
Chris@366 763 READ_MANDATORY(int, centre, toInt);
Chris@366 764 READ_MANDATORY(int, zoom, toInt);
Chris@45 765 READ_MANDATORY(int, followPan, toInt);
Chris@45 766 READ_MANDATORY(int, followZoom, toInt);
Chris@45 767 QString tracking = attributes.value("tracking");
Chris@45 768
Chris@45 769 // Specify the follow modes before we set the actual values
Chris@45 770 view->setFollowGlobalPan(followPan);
Chris@45 771 view->setFollowGlobalZoom(followZoom);
Chris@45 772 view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
Chris@379 773 tracking == "page" ? PlaybackScrollPageWithCentre :
Chris@379 774 tracking == "daw" ? PlaybackScrollPage
Chris@45 775 : PlaybackIgnore);
Chris@45 776
Chris@45 777 // Then set these values
Chris@45 778 view->setCentreFrame(centre);
Chris@45 779 view->setZoomLevel(zoom);
Chris@45 780
Chris@45 781 // And pane properties
Chris@45 782 READ_MANDATORY(int, centreLineVisible, toInt);
Chris@45 783 m_currentPane->setCentreLineVisible(centreLineVisible);
Chris@45 784
Chris@45 785 int height = attributes.value("height").toInt(&ok);
Chris@45 786 if (ok) {
Chris@45 787 m_currentPane->resize(m_currentPane->width(), height);
Chris@45 788 }
Chris@45 789
Chris@45 790 return true;
Chris@45 791 }
Chris@45 792
Chris@45 793 bool
Chris@45 794 SVFileReader::readLayer(const QXmlAttributes &attributes)
Chris@45 795 {
Chris@45 796 QString type = attributes.value("type");
Chris@45 797
Chris@45 798 int id;
Chris@45 799 bool ok = false;
Chris@45 800 id = attributes.value("id").trimmed().toInt(&ok);
Chris@45 801
Chris@45 802 if (!ok) {
Chris@293 803 cerr << "WARNING: SV-XML: No layer id for layer of type \""
Chris@294 804 << type
Chris@293 805 << "\"" << endl;
Chris@45 806 return false;
Chris@45 807 }
Chris@45 808
Chris@45 809 Layer *layer = 0;
Chris@45 810 bool isNewLayer = false;
Chris@45 811
Chris@45 812 // Layers are expected to be defined in layer elements in the data
Chris@45 813 // section, and referred to in layer elements in the view
Chris@45 814 // sections. So if we're in the data section, we expect this
Chris@45 815 // layer not to exist already; if we're in the view section, we
Chris@45 816 // expect it to exist.
Chris@45 817
Chris@45 818 if (m_inData) {
Chris@45 819
Chris@45 820 if (m_layers.find(id) != m_layers.end()) {
Chris@293 821 cerr << "WARNING: SV-XML: Ignoring duplicate layer id " << id
Chris@293 822 << " in data section" << endl;
Chris@45 823 return false;
Chris@45 824 }
Chris@45 825
Chris@45 826 layer = m_layers[id] = m_document->createLayer
Chris@45 827 (LayerFactory::getInstance()->getLayerTypeForName(type));
Chris@45 828
Chris@45 829 if (layer) {
Chris@45 830 m_layers[id] = layer;
Chris@45 831 isNewLayer = true;
Chris@45 832 }
Chris@45 833
Chris@45 834 } else {
Chris@45 835
Chris@45 836 if (!m_currentPane) {
Chris@293 837 cerr << "WARNING: SV-XML: No current pane for layer " << id
Chris@293 838 << " in view section" << endl;
Chris@45 839 return false;
Chris@45 840 }
Chris@45 841
Chris@45 842 if (m_layers.find(id) != m_layers.end()) {
Chris@45 843
Chris@45 844 layer = m_layers[id];
Chris@45 845
Chris@45 846 } else {
Chris@293 847 cerr << "WARNING: SV-XML: Layer id " << id
Chris@45 848 << " in view section has not been defined -- defining it here"
Chris@293 849 << endl;
Chris@45 850
Chris@45 851 layer = m_document->createLayer
Chris@45 852 (LayerFactory::getInstance()->getLayerTypeForName(type));
Chris@45 853
Chris@45 854 if (layer) {
Chris@45 855 m_layers[id] = layer;
Chris@45 856 isNewLayer = true;
Chris@45 857 }
Chris@45 858 }
Chris@45 859 }
Chris@45 860
Chris@45 861 if (!layer) {
Chris@293 862 cerr << "WARNING: SV-XML: Failed to add layer of type \""
Chris@294 863 << type
Chris@293 864 << "\"" << endl;
Chris@45 865 return false;
Chris@45 866 }
Chris@45 867
Chris@45 868 if (isNewLayer) {
Chris@45 869
Chris@45 870 QString name = attributes.value("name");
Chris@45 871 layer->setObjectName(name);
Chris@45 872
Chris@89 873 QString presentationName = attributes.value("presentationName");
Chris@89 874 layer->setPresentationName(presentationName);
Chris@89 875
Chris@45 876 int modelId;
Chris@45 877 bool modelOk = false;
Chris@45 878 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 879
Chris@45 880 if (modelOk) {
Chris@45 881 if (haveModel(modelId)) {
Chris@45 882 Model *model = m_models[modelId];
Chris@45 883 m_document->setModel(layer, model);
Chris@45 884 } else {
Chris@293 885 cerr << "WARNING: SV-XML: Unknown model id " << modelId
Chris@293 886 << " in layer definition" << endl;
Chris@451 887 if (!layer->canExistWithoutModel()) {
Chris@451 888 // Don't add a layer with an unknown model id
Chris@451 889 // unless it explicitly supports this state
Chris@451 890 m_document->deleteLayer(layer);
Chris@451 891 m_layers[id] = layer = 0;
Chris@451 892 return false;
Chris@451 893 }
Chris@451 894 }
Chris@45 895 }
Chris@45 896
Chris@447 897 if (layer) layer->setProperties(attributes);
Chris@45 898 }
Chris@45 899
Chris@447 900 if (!m_inData && m_currentPane && layer) {
Chris@45 901
Chris@45 902 QString visible = attributes.value("visible");
Chris@45 903 bool dormant = (visible == "false");
Chris@45 904
Chris@45 905 // We need to do this both before and after adding the layer
Chris@45 906 // to the view -- we need it to be dormant if appropriate
Chris@45 907 // before it's actually added to the view so that any property
Chris@45 908 // box gets the right state when it's added, but the add layer
Chris@45 909 // command sets dormant to false because it assumes it may be
Chris@45 910 // restoring a previously dormant layer, so we need to set it
Chris@45 911 // again afterwards too. Hm
Chris@45 912 layer->setLayerDormant(m_currentPane, dormant);
Chris@45 913
Chris@45 914 m_document->addLayerToView(m_currentPane, layer);
Chris@45 915
Chris@45 916 layer->setLayerDormant(m_currentPane, dormant);
Chris@45 917 }
Chris@45 918
Chris@45 919 m_currentLayer = layer;
Chris@447 920 m_inLayer = (layer != 0);
Chris@45 921
Chris@45 922 return true;
Chris@45 923 }
Chris@45 924
Chris@45 925 bool
Chris@45 926 SVFileReader::readDatasetStart(const QXmlAttributes &attributes)
Chris@45 927 {
Chris@45 928 bool ok = false;
Chris@45 929
Chris@45 930 READ_MANDATORY(int, id, toInt);
Chris@45 931 READ_MANDATORY(int, dimensions, toInt);
Chris@45 932
Chris@45 933 if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) {
Chris@293 934 cerr << "WARNING: SV-XML: Unwanted dataset " << id << endl;
Chris@45 935 return false;
Chris@45 936 }
Chris@45 937
Chris@45 938 int modelId = m_awaitingDatasets[id];
Chris@45 939
Chris@45 940 Model *model = 0;
Chris@45 941 if (haveModel(modelId)) {
Chris@45 942 model = m_models[modelId];
Chris@45 943 } else {
Chris@293 944 cerr << "WARNING: SV-XML: Internal error: Unknown model " << modelId
Chris@293 945 << " expecting dataset " << id << endl;
Chris@45 946 return false;
Chris@45 947 }
Chris@45 948
Chris@45 949 bool good = false;
Chris@45 950
Chris@45 951 switch (dimensions) {
Chris@45 952 case 1:
Chris@45 953 if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true;
Chris@45 954 else if (dynamic_cast<ImageModel *>(model)) good = true;
Chris@45 955 break;
Chris@45 956
Chris@45 957 case 2:
Chris@45 958 if (dynamic_cast<SparseTimeValueModel *>(model)) good = true;
Chris@45 959 else if (dynamic_cast<TextModel *>(model)) good = true;
Chris@111 960 else if (dynamic_cast<PathModel *>(model)) good = true;
Chris@45 961 break;
Chris@45 962
Chris@45 963 case 3:
Chris@45 964 if (dynamic_cast<NoteModel *>(model)) good = true;
Chris@343 965 else if (dynamic_cast<FlexiNoteModel *>(model)) good = true;
Chris@137 966 else if (dynamic_cast<RegionModel *>(model)) good = true;
Chris@45 967 else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) {
Chris@45 968 m_datasetSeparator = attributes.value("separator");
Chris@45 969 good = true;
Chris@45 970 }
Chris@45 971 break;
Chris@45 972 }
Chris@45 973
Chris@45 974 if (!good) {
Chris@293 975 cerr << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl;
Chris@45 976 m_currentDataset = 0;
Chris@45 977 return false;
Chris@45 978 }
Chris@45 979
Chris@45 980 m_currentDataset = model;
Chris@45 981 return true;
Chris@45 982 }
Chris@45 983
Chris@45 984 bool
Chris@45 985 SVFileReader::addPointToDataset(const QXmlAttributes &attributes)
Chris@45 986 {
Chris@45 987 bool ok = false;
Chris@45 988
Chris@45 989 READ_MANDATORY(int, frame, toInt);
Chris@45 990
Chris@233 991 // SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl;
Chris@45 992
Chris@45 993 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@45 994 (m_currentDataset);
Chris@45 995
Chris@45 996 if (sodm) {
Chris@293 997 // cerr << "Current dataset is a sparse one dimensional model" << endl;
Chris@45 998 QString label = attributes.value("label");
Chris@45 999 sodm->addPoint(SparseOneDimensionalModel::Point(frame, label));
Chris@45 1000 return true;
Chris@45 1001 }
Chris@45 1002
Chris@45 1003 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>
Chris@45 1004 (m_currentDataset);
Chris@45 1005
Chris@45 1006 if (stvm) {
Chris@446 1007 // cerr << "Current dataset is a sparse time-value model" << endl;
Chris@45 1008 float value = 0.0;
Chris@45 1009 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@45 1010 QString label = attributes.value("label");
Chris@45 1011 stvm->addPoint(SparseTimeValueModel::Point(frame, value, label));
Chris@45 1012 return ok;
Chris@45 1013 }
Chris@45 1014
Chris@45 1015 NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset);
Chris@45 1016
Chris@45 1017 if (nm) {
Chris@446 1018 // cerr << "Current dataset is a note model" << endl;
Chris@45 1019 float value = 0.0;
Chris@45 1020 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@366 1021 int duration = 0;
Chris@366 1022 duration = attributes.value("duration").trimmed().toInt(&ok);
Chris@45 1023 QString label = attributes.value("label");
Chris@61 1024 float level = attributes.value("level").trimmed().toFloat(&ok);
Chris@61 1025 if (!ok) { // level is optional
Chris@61 1026 level = 1.f;
Chris@61 1027 ok = true;
Chris@61 1028 }
Chris@61 1029 nm->addPoint(NoteModel::Point(frame, value, duration, level, label));
Chris@45 1030 return ok;
Chris@45 1031 }
Chris@45 1032
Chris@343 1033 FlexiNoteModel *fnm = dynamic_cast<FlexiNoteModel *>(m_currentDataset);
Chris@343 1034
Chris@343 1035 if (fnm) {
Chris@446 1036 // cerr << "Current dataset is a flexinote model" << endl;
Chris@343 1037 float value = 0.0;
Chris@343 1038 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@366 1039 int duration = 0;
Chris@366 1040 duration = attributes.value("duration").trimmed().toInt(&ok);
Chris@343 1041 QString label = attributes.value("label");
Chris@343 1042 float level = attributes.value("level").trimmed().toFloat(&ok);
Chris@343 1043 if (!ok) { // level is optional
Chris@343 1044 level = 1.f;
Chris@343 1045 ok = true;
Chris@343 1046 }
Chris@343 1047 fnm->addPoint(FlexiNoteModel::Point(frame, value, duration, level, label));
Chris@343 1048 return ok;
Chris@343 1049 }
Chris@343 1050
Chris@137 1051 RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset);
Chris@137 1052
Chris@137 1053 if (rm) {
Chris@446 1054 // cerr << "Current dataset is a region model" << endl;
Chris@137 1055 float value = 0.0;
Chris@137 1056 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@366 1057 int duration = 0;
Chris@366 1058 duration = attributes.value("duration").trimmed().toInt(&ok);
Chris@137 1059 QString label = attributes.value("label");
Chris@137 1060 rm->addPoint(RegionModel::Point(frame, value, duration, label));
Chris@137 1061 return ok;
Chris@137 1062 }
Chris@137 1063
Chris@45 1064 TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset);
Chris@45 1065
Chris@45 1066 if (tm) {
Chris@293 1067 // cerr << "Current dataset is a text model" << endl;
Chris@45 1068 float height = 0.0;
Chris@45 1069 height = attributes.value("height").trimmed().toFloat(&ok);
Chris@45 1070 QString label = attributes.value("label");
Chris@233 1071 // SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl;
Chris@45 1072 tm->addPoint(TextModel::Point(frame, height, label));
Chris@45 1073 return ok;
Chris@45 1074 }
Chris@45 1075
Chris@111 1076 PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset);
Chris@111 1077
Chris@111 1078 if (pm) {
Chris@293 1079 // cerr << "Current dataset is a path model" << endl;
Chris@111 1080 int mapframe = attributes.value("mapframe").trimmed().toInt(&ok);
Chris@233 1081 // SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl;
Chris@111 1082 pm->addPoint(PathModel::Point(frame, mapframe));
Chris@111 1083 return ok;
Chris@111 1084 }
Chris@111 1085
Chris@45 1086 ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset);
Chris@45 1087
Chris@45 1088 if (im) {
Chris@293 1089 // cerr << "Current dataset is an image model" << endl;
Chris@45 1090 QString image = attributes.value("image");
Chris@45 1091 QString label = attributes.value("label");
Chris@233 1092 // SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl;
Chris@45 1093 im->addPoint(ImageModel::Point(frame, image, label));
Chris@45 1094 return ok;
Chris@45 1095 }
Chris@45 1096
Chris@293 1097 cerr << "WARNING: SV-XML: Point element found in non-point dataset" << endl;
Chris@45 1098
Chris@45 1099 return false;
Chris@45 1100 }
Chris@45 1101
Chris@45 1102 bool
Chris@45 1103 SVFileReader::addBinToDataset(const QXmlAttributes &attributes)
Chris@45 1104 {
Chris@45 1105 EditableDenseThreeDimensionalModel *dtdm =
Chris@45 1106 dynamic_cast<EditableDenseThreeDimensionalModel *>
Chris@45 1107 (m_currentDataset);
Chris@45 1108
Chris@45 1109 if (dtdm) {
Chris@45 1110
Chris@45 1111 bool ok = false;
Chris@45 1112 int n = attributes.value("number").trimmed().toInt(&ok);
Chris@45 1113 if (!ok) {
Chris@293 1114 cerr << "WARNING: SV-XML: Missing or invalid bin number"
Chris@293 1115 << endl;
Chris@45 1116 return false;
Chris@45 1117 }
Chris@45 1118
Chris@45 1119 QString name = attributes.value("name");
Chris@45 1120
Chris@45 1121 dtdm->setBinName(n, name);
Chris@45 1122 return true;
Chris@45 1123 }
Chris@45 1124
Chris@293 1125 cerr << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl;
Chris@45 1126
Chris@45 1127 return false;
Chris@45 1128 }
Chris@45 1129
Chris@45 1130
Chris@45 1131 bool
Chris@45 1132 SVFileReader::addRowToDataset(const QXmlAttributes &attributes)
Chris@45 1133 {
Chris@45 1134 m_inRow = false;
Chris@45 1135
Chris@45 1136 bool ok = false;
Chris@45 1137 m_rowNumber = attributes.value("n").trimmed().toInt(&ok);
Chris@45 1138 if (!ok) {
Chris@293 1139 cerr << "WARNING: SV-XML: Missing or invalid row number"
Chris@293 1140 << endl;
Chris@45 1141 return false;
Chris@45 1142 }
Chris@45 1143
Chris@45 1144 m_inRow = true;
Chris@45 1145
Chris@293 1146 // cerr << "SV-XML: In row " << m_rowNumber << endl;
Chris@45 1147
Chris@45 1148 return true;
Chris@45 1149 }
Chris@45 1150
Chris@45 1151 bool
Chris@45 1152 SVFileReader::readRowData(const QString &text)
Chris@45 1153 {
Chris@45 1154 EditableDenseThreeDimensionalModel *dtdm =
Chris@45 1155 dynamic_cast<EditableDenseThreeDimensionalModel *>
Chris@45 1156 (m_currentDataset);
Chris@45 1157
Chris@45 1158 bool warned = false;
Chris@45 1159
Chris@45 1160 if (dtdm) {
Chris@45 1161 QStringList data = text.split(m_datasetSeparator);
Chris@45 1162
Chris@45 1163 DenseThreeDimensionalModel::Column values;
Chris@45 1164
Chris@45 1165 for (QStringList::iterator i = data.begin(); i != data.end(); ++i) {
Chris@45 1166
Chris@512 1167 if (int(values.size()) == dtdm->getHeight()) {
Chris@45 1168 if (!warned) {
Chris@293 1169 cerr << "WARNING: SV-XML: Too many y-bins in 3-D dataset row "
Chris@293 1170 << m_rowNumber << endl;
Chris@45 1171 warned = true;
Chris@45 1172 }
Chris@45 1173 }
Chris@45 1174
Chris@45 1175 bool ok;
Chris@45 1176 float value = i->toFloat(&ok);
Chris@45 1177 if (!ok) {
Chris@293 1178 cerr << "WARNING: SV-XML: Bad floating-point value "
Chris@45 1179 << i->toLocal8Bit().data()
Chris@293 1180 << " in row data" << endl;
Chris@45 1181 } else {
Chris@45 1182 values.push_back(value);
Chris@45 1183 }
Chris@45 1184 }
Chris@45 1185
Chris@45 1186 dtdm->setColumn(m_rowNumber, values);
Chris@45 1187 return true;
Chris@45 1188 }
Chris@45 1189
Chris@293 1190 cerr << "WARNING: SV-XML: Row data found in non-row dataset" << endl;
Chris@45 1191
Chris@45 1192 return false;
Chris@45 1193 }
Chris@45 1194
Chris@45 1195 bool
Chris@45 1196 SVFileReader::readDerivation(const QXmlAttributes &attributes)
Chris@45 1197 {
Chris@45 1198 int modelId = 0;
Chris@45 1199 bool modelOk = false;
Chris@45 1200 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 1201
Chris@45 1202 if (!modelOk) {
Chris@293 1203 cerr << "WARNING: SV-XML: No model id specified for derivation" << endl;
Chris@45 1204 return false;
Chris@45 1205 }
Chris@45 1206
Chris@45 1207 if (haveModel(modelId)) {
Chris@45 1208 m_currentDerivedModel = m_models[modelId];
Chris@45 1209 } else {
Chris@45 1210 // we'll regenerate the model when the derivation element ends
Chris@45 1211 m_currentDerivedModel = 0;
Chris@45 1212 }
Chris@45 1213
Chris@45 1214 m_currentDerivedModelId = modelId;
Chris@45 1215
Chris@45 1216 int sourceId = 0;
Chris@45 1217 bool sourceOk = false;
Chris@45 1218 sourceId = attributes.value("source").trimmed().toInt(&sourceOk);
Chris@45 1219
Chris@45 1220 if (sourceOk && haveModel(sourceId)) {
Chris@72 1221 m_currentTransformSource = m_models[sourceId];
Chris@45 1222 } else {
Chris@585 1223 SVDEBUG << "NOTE: SV-XML: Can't find a model with id " << sourceId
Chris@585 1224 << " for derivation source, falling back to main model" << endl;
Chris@72 1225 m_currentTransformSource = m_document->getMainModel();
Chris@45 1226 }
Chris@45 1227
Chris@72 1228 m_currentTransform = Transform();
Chris@45 1229
Chris@45 1230 bool ok = false;
Chris@45 1231 int channel = attributes.value("channel").trimmed().toInt(&ok);
Chris@72 1232 if (ok) m_currentTransformChannel = channel;
Chris@72 1233 else m_currentTransformChannel = -1;
Chris@45 1234
Chris@72 1235 QString type = attributes.value("type");
Chris@72 1236
Chris@72 1237 if (type == "transform") {
Chris@72 1238 m_currentTransformIsNewStyle = true;
Chris@72 1239 return true;
Chris@72 1240 } else {
Chris@72 1241 m_currentTransformIsNewStyle = false;
Chris@233 1242 SVDEBUG << "NOTE: SV-XML: Reading old-style derivation element"
Chris@229 1243 << endl;
Chris@72 1244 }
Chris@72 1245
Chris@72 1246 QString transformId = attributes.value("transform");
Chris@72 1247
Chris@72 1248 m_currentTransform.setIdentifier(transformId);
Chris@45 1249
Chris@45 1250 int stepSize = attributes.value("stepSize").trimmed().toInt(&ok);
Chris@72 1251 if (ok) m_currentTransform.setStepSize(stepSize);
Chris@45 1252
Chris@45 1253 int blockSize = attributes.value("blockSize").trimmed().toInt(&ok);
Chris@72 1254 if (ok) m_currentTransform.setBlockSize(blockSize);
Chris@45 1255
Chris@45 1256 int windowType = attributes.value("windowType").trimmed().toInt(&ok);
Chris@72 1257 if (ok) m_currentTransform.setWindowType(WindowType(windowType));
Chris@72 1258
Chris@72 1259 if (!m_currentTransformSource) return true;
Chris@45 1260
Chris@45 1261 QString startFrameStr = attributes.value("startFrame");
Chris@45 1262 QString durationStr = attributes.value("duration");
Chris@45 1263
Chris@366 1264 int startFrame = 0;
Chris@366 1265 int duration = 0;
Chris@45 1266
Chris@45 1267 if (startFrameStr != "") {
Chris@45 1268 startFrame = startFrameStr.trimmed().toInt(&ok);
Chris@45 1269 if (!ok) startFrame = 0;
Chris@45 1270 }
Chris@45 1271 if (durationStr != "") {
Chris@45 1272 duration = durationStr.trimmed().toInt(&ok);
Chris@45 1273 if (!ok) duration = 0;
Chris@45 1274 }
Chris@45 1275
Chris@72 1276 m_currentTransform.setStartTime
Chris@72 1277 (RealTime::frame2RealTime
Chris@72 1278 (startFrame, m_currentTransformSource->getSampleRate()));
Chris@72 1279
Chris@72 1280 m_currentTransform.setDuration
Chris@72 1281 (RealTime::frame2RealTime
Chris@72 1282 (duration, m_currentTransformSource->getSampleRate()));
Chris@45 1283
Chris@45 1284 return true;
Chris@45 1285 }
Chris@45 1286
Chris@45 1287 bool
Chris@45 1288 SVFileReader::readPlayParameters(const QXmlAttributes &attributes)
Chris@45 1289 {
Chris@45 1290 m_currentPlayParameters = 0;
Chris@45 1291
Chris@45 1292 int modelId = 0;
Chris@45 1293 bool modelOk = false;
Chris@45 1294 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 1295
Chris@45 1296 if (!modelOk) {
Chris@293 1297 cerr << "WARNING: SV-XML: No model id specified for play parameters" << endl;
Chris@45 1298 return false;
Chris@45 1299 }
Chris@45 1300
Chris@45 1301 if (haveModel(modelId)) {
Chris@45 1302
Chris@45 1303 bool ok = false;
Chris@45 1304
Chris@45 1305 PlayParameters *parameters = PlayParameterRepository::getInstance()->
Chris@45 1306 getPlayParameters(m_models[modelId]);
Chris@45 1307
Chris@45 1308 if (!parameters) {
Chris@293 1309 cerr << "WARNING: SV-XML: Play parameters for model "
Chris@45 1310 << modelId
Chris@45 1311 << " not found - has model been added to document?"
Chris@293 1312 << endl;
Chris@45 1313 return false;
Chris@45 1314 }
Chris@45 1315
Chris@45 1316 bool muted = (attributes.value("mute").trimmed() == "true");
Chris@45 1317 parameters->setPlayMuted(muted);
Chris@45 1318
Chris@45 1319 float pan = attributes.value("pan").toFloat(&ok);
Chris@45 1320 if (ok) parameters->setPlayPan(pan);
Chris@45 1321
Chris@45 1322 float gain = attributes.value("gain").toFloat(&ok);
Chris@45 1323 if (ok) parameters->setPlayGain(gain);
Chris@45 1324
Chris@309 1325 QString clipId = attributes.value("clipId");
Chris@309 1326 if (clipId != "") parameters->setPlayClipId(clipId);
Chris@45 1327
Chris@45 1328 m_currentPlayParameters = parameters;
Chris@45 1329
Chris@293 1330 // cerr << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl;
Chris@45 1331
Chris@45 1332 } else {
Chris@45 1333
Chris@293 1334 cerr << "WARNING: SV-XML: Unknown model " << modelId
Chris@293 1335 << " for play parameters" << endl;
Chris@45 1336 return false;
Chris@45 1337 }
Chris@45 1338
Chris@45 1339 return true;
Chris@45 1340 }
Chris@45 1341
Chris@45 1342 bool
Chris@45 1343 SVFileReader::readPlugin(const QXmlAttributes &attributes)
Chris@45 1344 {
Chris@308 1345 if (m_currentDerivedModelId >= 0) {
Chris@308 1346 return readPluginForTransform(attributes);
Chris@308 1347 } else if (m_currentPlayParameters) {
Chris@308 1348 return readPluginForPlayback(attributes);
Chris@308 1349 } else {
Chris@293 1350 cerr << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl;
Chris@45 1351 return false;
Chris@45 1352 }
Chris@308 1353 }
Chris@45 1354
Chris@308 1355 bool
Chris@308 1356 SVFileReader::readPluginForTransform(const QXmlAttributes &attributes)
Chris@308 1357 {
Chris@308 1358 if (m_currentTransformIsNewStyle) {
Chris@308 1359 // Not needed, we have the transform element instead
Chris@72 1360 return true;
Chris@72 1361 }
Chris@72 1362
Chris@45 1363 QString configurationXml = "<plugin";
Chris@308 1364
Chris@45 1365 for (int i = 0; i < attributes.length(); ++i) {
Chris@45 1366 configurationXml += QString(" %1=\"%2\"")
Chris@45 1367 .arg(attributes.qName(i))
Chris@45 1368 .arg(XmlExportable::encodeEntities(attributes.value(i)));
Chris@45 1369 }
Chris@45 1370
Chris@45 1371 configurationXml += "/>";
Chris@45 1372
Chris@308 1373 TransformFactory::getInstance()->
Chris@308 1374 setParametersFromPluginConfigurationXml(m_currentTransform,
Chris@308 1375 configurationXml);
Chris@308 1376 return true;
Chris@308 1377 }
Chris@308 1378
Chris@308 1379 bool
Chris@308 1380 SVFileReader::readPluginForPlayback(const QXmlAttributes &attributes)
Chris@308 1381 {
Chris@308 1382 // Obsolete but supported for compatibility
Chris@308 1383
Chris@308 1384 QString ident = attributes.value("identifier");
Chris@308 1385 if (ident == "sample_player") {
Chris@309 1386 QString clipId = attributes.value("program");
Chris@309 1387 if (clipId != "") m_currentPlayParameters->setPlayClipId(clipId);
Chris@45 1388 }
Chris@45 1389
Chris@45 1390 return true;
Chris@45 1391 }
Chris@45 1392
Chris@45 1393 bool
Chris@72 1394 SVFileReader::readTransform(const QXmlAttributes &attributes)
Chris@72 1395 {
Chris@72 1396 if (m_currentDerivedModelId < 0) {
Chris@293 1397 cerr << "WARNING: SV-XML: Transform found outside derivation" << endl;
Chris@72 1398 return false;
Chris@72 1399 }
Chris@72 1400
Chris@82 1401 m_currentTransform = Transform();
Chris@72 1402 m_currentTransform.setFromXmlAttributes(attributes);
Chris@72 1403 return true;
Chris@72 1404 }
Chris@72 1405
Chris@72 1406 bool
Chris@72 1407 SVFileReader::readParameter(const QXmlAttributes &attributes)
Chris@72 1408 {
Chris@72 1409 if (m_currentDerivedModelId < 0) {
Chris@293 1410 cerr << "WARNING: SV-XML: Parameter found outside derivation" << endl;
Chris@72 1411 return false;
Chris@72 1412 }
Chris@72 1413
Chris@72 1414 QString name = attributes.value("name");
Chris@72 1415 if (name == "") {
Chris@293 1416 cerr << "WARNING: SV-XML: Ignoring nameless transform parameter"
Chris@293 1417 << endl;
Chris@72 1418 return false;
Chris@72 1419 }
Chris@72 1420
Chris@72 1421 float value = attributes.value("value").trimmed().toFloat();
Chris@72 1422
Chris@72 1423 m_currentTransform.setParameter(name, value);
Chris@72 1424 return true;
Chris@72 1425 }
Chris@72 1426
Chris@72 1427 bool
Chris@45 1428 SVFileReader::readSelection(const QXmlAttributes &attributes)
Chris@45 1429 {
Chris@45 1430 bool ok;
Chris@45 1431
Chris@45 1432 READ_MANDATORY(int, start, toInt);
Chris@45 1433 READ_MANDATORY(int, end, toInt);
Chris@45 1434
Chris@45 1435 m_paneCallback.addSelection(start, end);
Chris@45 1436
Chris@45 1437 return true;
Chris@45 1438 }
Chris@45 1439
Chris@45 1440 bool
Chris@45 1441 SVFileReader::readMeasurement(const QXmlAttributes &attributes)
Chris@45 1442 {
Chris@233 1443 SVDEBUG << "SVFileReader::readMeasurement: inLayer "
Chris@229 1444 << m_inLayer << ", layer " << m_currentLayer << endl;
Chris@45 1445
Chris@45 1446 if (!m_inLayer) {
Chris@293 1447 cerr << "WARNING: SV-XML: Measurement found outside layer" << endl;
Chris@45 1448 return false;
Chris@45 1449 }
Chris@45 1450
Chris@45 1451 m_currentLayer->addMeasurementRect(attributes);
Chris@45 1452 return true;
Chris@45 1453 }
Chris@45 1454
Chris@45 1455 SVFileReaderPaneCallback::~SVFileReaderPaneCallback()
Chris@45 1456 {
Chris@45 1457 }
Chris@45 1458
Chris@140 1459
Chris@140 1460 class SVFileIdentifier : public QXmlDefaultHandler
Chris@140 1461 {
Chris@140 1462 public:
Chris@140 1463 SVFileIdentifier() :
Chris@140 1464 m_inSv(false),
Chris@140 1465 m_inData(false),
Chris@140 1466 m_type(SVFileReader::UnknownFileType)
Chris@140 1467 { }
Chris@140 1468 virtual ~SVFileIdentifier() { }
Chris@140 1469
Chris@140 1470 void parse(QXmlInputSource &source) {
Chris@140 1471 QXmlSimpleReader reader;
Chris@140 1472 reader.setContentHandler(this);
Chris@140 1473 reader.setErrorHandler(this);
Chris@140 1474 reader.parse(source);
Chris@140 1475 }
Chris@140 1476
Chris@140 1477 SVFileReader::FileType getType() const { return m_type; }
Chris@140 1478
Chris@140 1479 virtual bool startElement(const QString &,
Chris@140 1480 const QString &,
Chris@140 1481 const QString &qName,
Chris@140 1482 const QXmlAttributes& atts)
Chris@140 1483 {
Chris@140 1484 QString name = qName.toLower();
Chris@140 1485
Chris@140 1486 // SV session files have an sv element containing a data
Chris@140 1487 // element containing a model element with mainModel="true".
Chris@140 1488
Chris@140 1489 // If the sv element is present but the rest does not satisfy,
Chris@140 1490 // then it's (probably) an SV layer file.
Chris@140 1491
Chris@140 1492 // Otherwise, it's of unknown type.
Chris@140 1493
Chris@140 1494 if (name == "sv") {
Chris@140 1495 m_inSv = true;
Chris@140 1496 if (m_type == SVFileReader::UnknownFileType) {
Chris@140 1497 m_type = SVFileReader::SVLayerFile;
Chris@140 1498 }
Chris@140 1499 return true;
Chris@140 1500 } else if (name == "data") {
Chris@140 1501 if (!m_inSv) return true;
Chris@140 1502 m_inData = true;
Chris@140 1503 } else if (name == "model") {
Chris@140 1504 if (!m_inData) return true;
Chris@140 1505 if (atts.value("mainModel").trimmed() == "true") {
Chris@140 1506 if (m_type == SVFileReader::SVLayerFile) {
Chris@140 1507 m_type = SVFileReader::SVSessionFile;
Chris@140 1508 return false; // done
Chris@140 1509 }
Chris@140 1510 }
Chris@140 1511 }
Chris@140 1512 return true;
Chris@140 1513 }
Chris@140 1514
Chris@140 1515 virtual bool endElement(const QString &,
Chris@140 1516 const QString &,
Chris@140 1517 const QString &qName)
Chris@140 1518 {
Chris@140 1519 QString name = qName.toLower();
Chris@140 1520
Chris@140 1521 if (name == "sv") {
Chris@140 1522 if (m_inSv) {
Chris@140 1523 m_inSv = false;
Chris@140 1524 return false; // done
Chris@140 1525 }
Chris@140 1526 } else if (name == "data") {
Chris@140 1527 if (m_inData) {
Chris@140 1528 m_inData = false;
Chris@140 1529 return false; // also done, nothing after the first
Chris@140 1530 // data element is of use here
Chris@140 1531 }
Chris@140 1532 }
Chris@140 1533 return true;
Chris@140 1534 }
Chris@140 1535
Chris@140 1536 private:
Chris@140 1537 bool m_inSv;
Chris@140 1538 bool m_inData;
Chris@140 1539 SVFileReader::FileType m_type;
Chris@140 1540 };
Chris@140 1541
Chris@140 1542
Chris@140 1543 SVFileReader::FileType
Chris@140 1544 SVFileReader::identifyXmlFile(QString path)
Chris@140 1545 {
Chris@140 1546 QFile file(path);
Chris@140 1547 SVFileIdentifier identifier;
Chris@140 1548 QXmlInputSource source(&file);
Chris@140 1549 identifier.parse(source);
Chris@140 1550 return identifier.getType();
Chris@140 1551 }
Chris@140 1552
Chris@140 1553
Chris@140 1554