annotate framework/SVFileReader.cpp @ 601:021d42e6c8cb

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