annotate framework/SVFileReader.cpp @ 342:4eccff14b4d8 tonioni

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