annotate framework/SVFileReader.cpp @ 332:151b7c5864e3 tonioni

Need to call back on handler even when there are no additional layers (because it has not yet learned about the primary layers)
author Chris Cannam
date Wed, 05 Mar 2014 09:45:10 +0000
parents f72d58d1ccb0
children 4eccff14b4d8
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@45 729 if (!m_currentPane) {
Chris@293 730 cerr << "WARNING: SV-XML: Internal error: Failed to add pane!"
Chris@293 731 << endl;
Chris@45 732 return false;
Chris@45 733 }
Chris@45 734
Chris@45 735 bool ok = false;
Chris@45 736
Chris@45 737 View *view = m_currentPane;
Chris@45 738
Chris@45 739 // The view properties first
Chris@45 740
Chris@45 741 READ_MANDATORY(size_t, centre, toUInt);
Chris@45 742 READ_MANDATORY(size_t, zoom, toUInt);
Chris@45 743 READ_MANDATORY(int, followPan, toInt);
Chris@45 744 READ_MANDATORY(int, followZoom, toInt);
Chris@45 745 QString tracking = attributes.value("tracking");
Chris@45 746
Chris@45 747 // Specify the follow modes before we set the actual values
Chris@45 748 view->setFollowGlobalPan(followPan);
Chris@45 749 view->setFollowGlobalZoom(followZoom);
Chris@45 750 view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
Chris@45 751 tracking == "page" ? PlaybackScrollPage
Chris@45 752 : PlaybackIgnore);
Chris@45 753
Chris@45 754 // Then set these values
Chris@45 755 view->setCentreFrame(centre);
Chris@45 756 view->setZoomLevel(zoom);
Chris@45 757
Chris@45 758 // And pane properties
Chris@45 759 READ_MANDATORY(int, centreLineVisible, toInt);
Chris@45 760 m_currentPane->setCentreLineVisible(centreLineVisible);
Chris@45 761
Chris@45 762 int height = attributes.value("height").toInt(&ok);
Chris@45 763 if (ok) {
Chris@45 764 m_currentPane->resize(m_currentPane->width(), height);
Chris@45 765 }
Chris@45 766
Chris@45 767 return true;
Chris@45 768 }
Chris@45 769
Chris@45 770 bool
Chris@45 771 SVFileReader::readLayer(const QXmlAttributes &attributes)
Chris@45 772 {
Chris@45 773 QString type = attributes.value("type");
Chris@45 774
Chris@45 775 int id;
Chris@45 776 bool ok = false;
Chris@45 777 id = attributes.value("id").trimmed().toInt(&ok);
Chris@45 778
Chris@45 779 if (!ok) {
Chris@293 780 cerr << "WARNING: SV-XML: No layer id for layer of type \""
Chris@294 781 << type
Chris@293 782 << "\"" << endl;
Chris@45 783 return false;
Chris@45 784 }
Chris@45 785
Chris@45 786 Layer *layer = 0;
Chris@45 787 bool isNewLayer = false;
Chris@45 788
Chris@45 789 // Layers are expected to be defined in layer elements in the data
Chris@45 790 // section, and referred to in layer elements in the view
Chris@45 791 // sections. So if we're in the data section, we expect this
Chris@45 792 // layer not to exist already; if we're in the view section, we
Chris@45 793 // expect it to exist.
Chris@45 794
Chris@45 795 if (m_inData) {
Chris@45 796
Chris@45 797 if (m_layers.find(id) != m_layers.end()) {
Chris@293 798 cerr << "WARNING: SV-XML: Ignoring duplicate layer id " << id
Chris@293 799 << " in data section" << endl;
Chris@45 800 return false;
Chris@45 801 }
Chris@45 802
Chris@45 803 layer = m_layers[id] = m_document->createLayer
Chris@45 804 (LayerFactory::getInstance()->getLayerTypeForName(type));
Chris@45 805
Chris@45 806 if (layer) {
Chris@45 807 m_layers[id] = layer;
Chris@45 808 isNewLayer = true;
Chris@45 809 }
Chris@45 810
Chris@45 811 } else {
Chris@45 812
Chris@45 813 if (!m_currentPane) {
Chris@293 814 cerr << "WARNING: SV-XML: No current pane for layer " << id
Chris@293 815 << " in view section" << endl;
Chris@45 816 return false;
Chris@45 817 }
Chris@45 818
Chris@45 819 if (m_layers.find(id) != m_layers.end()) {
Chris@45 820
Chris@45 821 layer = m_layers[id];
Chris@45 822
Chris@45 823 } else {
Chris@293 824 cerr << "WARNING: SV-XML: Layer id " << id
Chris@45 825 << " in view section has not been defined -- defining it here"
Chris@293 826 << endl;
Chris@45 827
Chris@45 828 layer = m_document->createLayer
Chris@45 829 (LayerFactory::getInstance()->getLayerTypeForName(type));
Chris@45 830
Chris@45 831 if (layer) {
Chris@45 832 m_layers[id] = layer;
Chris@45 833 isNewLayer = true;
Chris@45 834 }
Chris@45 835 }
Chris@45 836 }
Chris@45 837
Chris@45 838 if (!layer) {
Chris@293 839 cerr << "WARNING: SV-XML: Failed to add layer of type \""
Chris@294 840 << type
Chris@293 841 << "\"" << endl;
Chris@45 842 return false;
Chris@45 843 }
Chris@45 844
Chris@45 845 if (isNewLayer) {
Chris@45 846
Chris@45 847 QString name = attributes.value("name");
Chris@45 848 layer->setObjectName(name);
Chris@45 849
Chris@89 850 QString presentationName = attributes.value("presentationName");
Chris@89 851 layer->setPresentationName(presentationName);
Chris@89 852
Chris@45 853 int modelId;
Chris@45 854 bool modelOk = false;
Chris@45 855 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 856
Chris@45 857 if (modelOk) {
Chris@45 858 if (haveModel(modelId)) {
Chris@45 859 Model *model = m_models[modelId];
Chris@45 860 m_document->setModel(layer, model);
Chris@45 861 } else {
Chris@293 862 cerr << "WARNING: SV-XML: Unknown model id " << modelId
Chris@293 863 << " in layer definition" << endl;
Chris@45 864 }
Chris@45 865 }
Chris@45 866
Chris@45 867 layer->setProperties(attributes);
Chris@45 868 }
Chris@45 869
Chris@45 870 if (!m_inData && m_currentPane) {
Chris@45 871
Chris@45 872 QString visible = attributes.value("visible");
Chris@45 873 bool dormant = (visible == "false");
Chris@45 874
Chris@45 875 // We need to do this both before and after adding the layer
Chris@45 876 // to the view -- we need it to be dormant if appropriate
Chris@45 877 // before it's actually added to the view so that any property
Chris@45 878 // box gets the right state when it's added, but the add layer
Chris@45 879 // command sets dormant to false because it assumes it may be
Chris@45 880 // restoring a previously dormant layer, so we need to set it
Chris@45 881 // again afterwards too. Hm
Chris@45 882 layer->setLayerDormant(m_currentPane, dormant);
Chris@45 883
Chris@45 884 m_document->addLayerToView(m_currentPane, layer);
Chris@45 885
Chris@45 886 layer->setLayerDormant(m_currentPane, dormant);
Chris@45 887 }
Chris@45 888
Chris@45 889 m_currentLayer = layer;
Chris@45 890 m_inLayer = true;
Chris@45 891
Chris@45 892 return true;
Chris@45 893 }
Chris@45 894
Chris@45 895 bool
Chris@45 896 SVFileReader::readDatasetStart(const QXmlAttributes &attributes)
Chris@45 897 {
Chris@45 898 bool ok = false;
Chris@45 899
Chris@45 900 READ_MANDATORY(int, id, toInt);
Chris@45 901 READ_MANDATORY(int, dimensions, toInt);
Chris@45 902
Chris@45 903 if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) {
Chris@293 904 cerr << "WARNING: SV-XML: Unwanted dataset " << id << endl;
Chris@45 905 return false;
Chris@45 906 }
Chris@45 907
Chris@45 908 int modelId = m_awaitingDatasets[id];
Chris@45 909
Chris@45 910 Model *model = 0;
Chris@45 911 if (haveModel(modelId)) {
Chris@45 912 model = m_models[modelId];
Chris@45 913 } else {
Chris@293 914 cerr << "WARNING: SV-XML: Internal error: Unknown model " << modelId
Chris@293 915 << " expecting dataset " << id << endl;
Chris@45 916 return false;
Chris@45 917 }
Chris@45 918
Chris@45 919 bool good = false;
Chris@45 920
Chris@45 921 switch (dimensions) {
Chris@45 922 case 1:
Chris@45 923 if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true;
Chris@45 924 else if (dynamic_cast<ImageModel *>(model)) good = true;
Chris@45 925 break;
Chris@45 926
Chris@45 927 case 2:
Chris@45 928 if (dynamic_cast<SparseTimeValueModel *>(model)) good = true;
Chris@45 929 else if (dynamic_cast<TextModel *>(model)) good = true;
Chris@111 930 else if (dynamic_cast<PathModel *>(model)) good = true;
Chris@45 931 break;
Chris@45 932
Chris@45 933 case 3:
Chris@45 934 if (dynamic_cast<NoteModel *>(model)) good = true;
Chris@137 935 else if (dynamic_cast<RegionModel *>(model)) good = true;
Chris@45 936 else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) {
Chris@45 937 m_datasetSeparator = attributes.value("separator");
Chris@45 938 good = true;
Chris@45 939 }
Chris@45 940 break;
Chris@45 941 }
Chris@45 942
Chris@45 943 if (!good) {
Chris@293 944 cerr << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl;
Chris@45 945 m_currentDataset = 0;
Chris@45 946 return false;
Chris@45 947 }
Chris@45 948
Chris@45 949 m_currentDataset = model;
Chris@45 950 return true;
Chris@45 951 }
Chris@45 952
Chris@45 953 bool
Chris@45 954 SVFileReader::addPointToDataset(const QXmlAttributes &attributes)
Chris@45 955 {
Chris@45 956 bool ok = false;
Chris@45 957
Chris@45 958 READ_MANDATORY(int, frame, toInt);
Chris@45 959
Chris@233 960 // SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl;
Chris@45 961
Chris@45 962 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@45 963 (m_currentDataset);
Chris@45 964
Chris@45 965 if (sodm) {
Chris@293 966 // cerr << "Current dataset is a sparse one dimensional model" << endl;
Chris@45 967 QString label = attributes.value("label");
Chris@45 968 sodm->addPoint(SparseOneDimensionalModel::Point(frame, label));
Chris@45 969 return true;
Chris@45 970 }
Chris@45 971
Chris@45 972 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>
Chris@45 973 (m_currentDataset);
Chris@45 974
Chris@45 975 if (stvm) {
Chris@293 976 // cerr << "Current dataset is a sparse time-value model" << endl;
Chris@45 977 float value = 0.0;
Chris@45 978 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@45 979 QString label = attributes.value("label");
Chris@45 980 stvm->addPoint(SparseTimeValueModel::Point(frame, value, label));
Chris@45 981 return ok;
Chris@45 982 }
Chris@45 983
Chris@45 984 NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset);
Chris@45 985
Chris@45 986 if (nm) {
Chris@293 987 // cerr << "Current dataset is a note model" << endl;
Chris@45 988 float value = 0.0;
Chris@45 989 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@45 990 size_t duration = 0;
Chris@45 991 duration = attributes.value("duration").trimmed().toUInt(&ok);
Chris@45 992 QString label = attributes.value("label");
Chris@61 993 float level = attributes.value("level").trimmed().toFloat(&ok);
Chris@61 994 if (!ok) { // level is optional
Chris@61 995 level = 1.f;
Chris@61 996 ok = true;
Chris@61 997 }
Chris@61 998 nm->addPoint(NoteModel::Point(frame, value, duration, level, label));
Chris@45 999 return ok;
Chris@45 1000 }
Chris@45 1001
Chris@137 1002 RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset);
Chris@137 1003
Chris@137 1004 if (rm) {
Chris@293 1005 // cerr << "Current dataset is a note model" << endl;
Chris@137 1006 float value = 0.0;
Chris@137 1007 value = attributes.value("value").trimmed().toFloat(&ok);
Chris@137 1008 size_t duration = 0;
Chris@137 1009 duration = attributes.value("duration").trimmed().toUInt(&ok);
Chris@137 1010 QString label = attributes.value("label");
Chris@137 1011 rm->addPoint(RegionModel::Point(frame, value, duration, label));
Chris@137 1012 return ok;
Chris@137 1013 }
Chris@137 1014
Chris@45 1015 TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset);
Chris@45 1016
Chris@45 1017 if (tm) {
Chris@293 1018 // cerr << "Current dataset is a text model" << endl;
Chris@45 1019 float height = 0.0;
Chris@45 1020 height = attributes.value("height").trimmed().toFloat(&ok);
Chris@45 1021 QString label = attributes.value("label");
Chris@233 1022 // SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl;
Chris@45 1023 tm->addPoint(TextModel::Point(frame, height, label));
Chris@45 1024 return ok;
Chris@45 1025 }
Chris@45 1026
Chris@111 1027 PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset);
Chris@111 1028
Chris@111 1029 if (pm) {
Chris@293 1030 // cerr << "Current dataset is a path model" << endl;
Chris@111 1031 int mapframe = attributes.value("mapframe").trimmed().toInt(&ok);
Chris@233 1032 // SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl;
Chris@111 1033 pm->addPoint(PathModel::Point(frame, mapframe));
Chris@111 1034 return ok;
Chris@111 1035 }
Chris@111 1036
Chris@45 1037 ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset);
Chris@45 1038
Chris@45 1039 if (im) {
Chris@293 1040 // cerr << "Current dataset is an image model" << endl;
Chris@45 1041 QString image = attributes.value("image");
Chris@45 1042 QString label = attributes.value("label");
Chris@233 1043 // SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl;
Chris@45 1044 im->addPoint(ImageModel::Point(frame, image, label));
Chris@45 1045 return ok;
Chris@45 1046 }
Chris@45 1047
Chris@293 1048 cerr << "WARNING: SV-XML: Point element found in non-point dataset" << endl;
Chris@45 1049
Chris@45 1050 return false;
Chris@45 1051 }
Chris@45 1052
Chris@45 1053 bool
Chris@45 1054 SVFileReader::addBinToDataset(const QXmlAttributes &attributes)
Chris@45 1055 {
Chris@45 1056 EditableDenseThreeDimensionalModel *dtdm =
Chris@45 1057 dynamic_cast<EditableDenseThreeDimensionalModel *>
Chris@45 1058 (m_currentDataset);
Chris@45 1059
Chris@45 1060 if (dtdm) {
Chris@45 1061
Chris@45 1062 bool ok = false;
Chris@45 1063 int n = attributes.value("number").trimmed().toInt(&ok);
Chris@45 1064 if (!ok) {
Chris@293 1065 cerr << "WARNING: SV-XML: Missing or invalid bin number"
Chris@293 1066 << endl;
Chris@45 1067 return false;
Chris@45 1068 }
Chris@45 1069
Chris@45 1070 QString name = attributes.value("name");
Chris@45 1071
Chris@45 1072 dtdm->setBinName(n, name);
Chris@45 1073 return true;
Chris@45 1074 }
Chris@45 1075
Chris@293 1076 cerr << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl;
Chris@45 1077
Chris@45 1078 return false;
Chris@45 1079 }
Chris@45 1080
Chris@45 1081
Chris@45 1082 bool
Chris@45 1083 SVFileReader::addRowToDataset(const QXmlAttributes &attributes)
Chris@45 1084 {
Chris@45 1085 m_inRow = false;
Chris@45 1086
Chris@45 1087 bool ok = false;
Chris@45 1088 m_rowNumber = attributes.value("n").trimmed().toInt(&ok);
Chris@45 1089 if (!ok) {
Chris@293 1090 cerr << "WARNING: SV-XML: Missing or invalid row number"
Chris@293 1091 << endl;
Chris@45 1092 return false;
Chris@45 1093 }
Chris@45 1094
Chris@45 1095 m_inRow = true;
Chris@45 1096
Chris@293 1097 // cerr << "SV-XML: In row " << m_rowNumber << endl;
Chris@45 1098
Chris@45 1099 return true;
Chris@45 1100 }
Chris@45 1101
Chris@45 1102 bool
Chris@45 1103 SVFileReader::readRowData(const QString &text)
Chris@45 1104 {
Chris@45 1105 EditableDenseThreeDimensionalModel *dtdm =
Chris@45 1106 dynamic_cast<EditableDenseThreeDimensionalModel *>
Chris@45 1107 (m_currentDataset);
Chris@45 1108
Chris@45 1109 bool warned = false;
Chris@45 1110
Chris@45 1111 if (dtdm) {
Chris@45 1112 QStringList data = text.split(m_datasetSeparator);
Chris@45 1113
Chris@45 1114 DenseThreeDimensionalModel::Column values;
Chris@45 1115
Chris@45 1116 for (QStringList::iterator i = data.begin(); i != data.end(); ++i) {
Chris@45 1117
Chris@45 1118 if (values.size() == dtdm->getHeight()) {
Chris@45 1119 if (!warned) {
Chris@293 1120 cerr << "WARNING: SV-XML: Too many y-bins in 3-D dataset row "
Chris@293 1121 << m_rowNumber << endl;
Chris@45 1122 warned = true;
Chris@45 1123 }
Chris@45 1124 }
Chris@45 1125
Chris@45 1126 bool ok;
Chris@45 1127 float value = i->toFloat(&ok);
Chris@45 1128 if (!ok) {
Chris@293 1129 cerr << "WARNING: SV-XML: Bad floating-point value "
Chris@45 1130 << i->toLocal8Bit().data()
Chris@293 1131 << " in row data" << endl;
Chris@45 1132 } else {
Chris@45 1133 values.push_back(value);
Chris@45 1134 }
Chris@45 1135 }
Chris@45 1136
Chris@45 1137 dtdm->setColumn(m_rowNumber, values);
Chris@45 1138 return true;
Chris@45 1139 }
Chris@45 1140
Chris@293 1141 cerr << "WARNING: SV-XML: Row data found in non-row dataset" << endl;
Chris@45 1142
Chris@45 1143 return false;
Chris@45 1144 }
Chris@45 1145
Chris@45 1146 bool
Chris@45 1147 SVFileReader::readDerivation(const QXmlAttributes &attributes)
Chris@45 1148 {
Chris@45 1149 int modelId = 0;
Chris@45 1150 bool modelOk = false;
Chris@45 1151 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 1152
Chris@45 1153 if (!modelOk) {
Chris@293 1154 cerr << "WARNING: SV-XML: No model id specified for derivation" << endl;
Chris@45 1155 return false;
Chris@45 1156 }
Chris@45 1157
Chris@45 1158 if (haveModel(modelId)) {
Chris@45 1159 m_currentDerivedModel = m_models[modelId];
Chris@45 1160 } else {
Chris@45 1161 // we'll regenerate the model when the derivation element ends
Chris@45 1162 m_currentDerivedModel = 0;
Chris@45 1163 }
Chris@45 1164
Chris@45 1165 m_currentDerivedModelId = modelId;
Chris@45 1166
Chris@45 1167 int sourceId = 0;
Chris@45 1168 bool sourceOk = false;
Chris@45 1169 sourceId = attributes.value("source").trimmed().toInt(&sourceOk);
Chris@45 1170
Chris@45 1171 if (sourceOk && haveModel(sourceId)) {
Chris@72 1172 m_currentTransformSource = m_models[sourceId];
Chris@45 1173 } else {
Chris@72 1174 m_currentTransformSource = m_document->getMainModel();
Chris@45 1175 }
Chris@45 1176
Chris@72 1177 m_currentTransform = Transform();
Chris@45 1178
Chris@45 1179 bool ok = false;
Chris@45 1180 int channel = attributes.value("channel").trimmed().toInt(&ok);
Chris@72 1181 if (ok) m_currentTransformChannel = channel;
Chris@72 1182 else m_currentTransformChannel = -1;
Chris@45 1183
Chris@72 1184 QString type = attributes.value("type");
Chris@72 1185
Chris@72 1186 if (type == "transform") {
Chris@72 1187 m_currentTransformIsNewStyle = true;
Chris@72 1188 return true;
Chris@72 1189 } else {
Chris@72 1190 m_currentTransformIsNewStyle = false;
Chris@233 1191 SVDEBUG << "NOTE: SV-XML: Reading old-style derivation element"
Chris@229 1192 << endl;
Chris@72 1193 }
Chris@72 1194
Chris@72 1195 QString transformId = attributes.value("transform");
Chris@72 1196
Chris@72 1197 m_currentTransform.setIdentifier(transformId);
Chris@45 1198
Chris@45 1199 int stepSize = attributes.value("stepSize").trimmed().toInt(&ok);
Chris@72 1200 if (ok) m_currentTransform.setStepSize(stepSize);
Chris@45 1201
Chris@45 1202 int blockSize = attributes.value("blockSize").trimmed().toInt(&ok);
Chris@72 1203 if (ok) m_currentTransform.setBlockSize(blockSize);
Chris@45 1204
Chris@45 1205 int windowType = attributes.value("windowType").trimmed().toInt(&ok);
Chris@72 1206 if (ok) m_currentTransform.setWindowType(WindowType(windowType));
Chris@72 1207
Chris@72 1208 if (!m_currentTransformSource) return true;
Chris@45 1209
Chris@45 1210 QString startFrameStr = attributes.value("startFrame");
Chris@45 1211 QString durationStr = attributes.value("duration");
Chris@45 1212
Chris@45 1213 size_t startFrame = 0;
Chris@45 1214 size_t duration = 0;
Chris@45 1215
Chris@45 1216 if (startFrameStr != "") {
Chris@45 1217 startFrame = startFrameStr.trimmed().toInt(&ok);
Chris@45 1218 if (!ok) startFrame = 0;
Chris@45 1219 }
Chris@45 1220 if (durationStr != "") {
Chris@45 1221 duration = durationStr.trimmed().toInt(&ok);
Chris@45 1222 if (!ok) duration = 0;
Chris@45 1223 }
Chris@45 1224
Chris@72 1225 m_currentTransform.setStartTime
Chris@72 1226 (RealTime::frame2RealTime
Chris@72 1227 (startFrame, m_currentTransformSource->getSampleRate()));
Chris@72 1228
Chris@72 1229 m_currentTransform.setDuration
Chris@72 1230 (RealTime::frame2RealTime
Chris@72 1231 (duration, m_currentTransformSource->getSampleRate()));
Chris@45 1232
Chris@45 1233 return true;
Chris@45 1234 }
Chris@45 1235
Chris@45 1236 bool
Chris@45 1237 SVFileReader::readPlayParameters(const QXmlAttributes &attributes)
Chris@45 1238 {
Chris@45 1239 m_currentPlayParameters = 0;
Chris@45 1240
Chris@45 1241 int modelId = 0;
Chris@45 1242 bool modelOk = false;
Chris@45 1243 modelId = attributes.value("model").trimmed().toInt(&modelOk);
Chris@45 1244
Chris@45 1245 if (!modelOk) {
Chris@293 1246 cerr << "WARNING: SV-XML: No model id specified for play parameters" << endl;
Chris@45 1247 return false;
Chris@45 1248 }
Chris@45 1249
Chris@45 1250 if (haveModel(modelId)) {
Chris@45 1251
Chris@45 1252 bool ok = false;
Chris@45 1253
Chris@45 1254 PlayParameters *parameters = PlayParameterRepository::getInstance()->
Chris@45 1255 getPlayParameters(m_models[modelId]);
Chris@45 1256
Chris@45 1257 if (!parameters) {
Chris@293 1258 cerr << "WARNING: SV-XML: Play parameters for model "
Chris@45 1259 << modelId
Chris@45 1260 << " not found - has model been added to document?"
Chris@293 1261 << endl;
Chris@45 1262 return false;
Chris@45 1263 }
Chris@45 1264
Chris@45 1265 bool muted = (attributes.value("mute").trimmed() == "true");
Chris@45 1266 parameters->setPlayMuted(muted);
Chris@45 1267
Chris@45 1268 float pan = attributes.value("pan").toFloat(&ok);
Chris@45 1269 if (ok) parameters->setPlayPan(pan);
Chris@45 1270
Chris@45 1271 float gain = attributes.value("gain").toFloat(&ok);
Chris@45 1272 if (ok) parameters->setPlayGain(gain);
Chris@45 1273
Chris@309 1274 QString clipId = attributes.value("clipId");
Chris@309 1275 if (clipId != "") parameters->setPlayClipId(clipId);
Chris@45 1276
Chris@45 1277 m_currentPlayParameters = parameters;
Chris@45 1278
Chris@293 1279 // cerr << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl;
Chris@45 1280
Chris@45 1281 } else {
Chris@45 1282
Chris@293 1283 cerr << "WARNING: SV-XML: Unknown model " << modelId
Chris@293 1284 << " for play parameters" << endl;
Chris@45 1285 return false;
Chris@45 1286 }
Chris@45 1287
Chris@45 1288 return true;
Chris@45 1289 }
Chris@45 1290
Chris@45 1291 bool
Chris@45 1292 SVFileReader::readPlugin(const QXmlAttributes &attributes)
Chris@45 1293 {
Chris@308 1294 if (m_currentDerivedModelId >= 0) {
Chris@308 1295 return readPluginForTransform(attributes);
Chris@308 1296 } else if (m_currentPlayParameters) {
Chris@308 1297 return readPluginForPlayback(attributes);
Chris@308 1298 } else {
Chris@293 1299 cerr << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl;
Chris@45 1300 return false;
Chris@45 1301 }
Chris@308 1302 }
Chris@45 1303
Chris@308 1304 bool
Chris@308 1305 SVFileReader::readPluginForTransform(const QXmlAttributes &attributes)
Chris@308 1306 {
Chris@308 1307 if (m_currentTransformIsNewStyle) {
Chris@308 1308 // Not needed, we have the transform element instead
Chris@72 1309 return true;
Chris@72 1310 }
Chris@72 1311
Chris@45 1312 QString configurationXml = "<plugin";
Chris@308 1313
Chris@45 1314 for (int i = 0; i < attributes.length(); ++i) {
Chris@45 1315 configurationXml += QString(" %1=\"%2\"")
Chris@45 1316 .arg(attributes.qName(i))
Chris@45 1317 .arg(XmlExportable::encodeEntities(attributes.value(i)));
Chris@45 1318 }
Chris@45 1319
Chris@45 1320 configurationXml += "/>";
Chris@45 1321
Chris@308 1322 TransformFactory::getInstance()->
Chris@308 1323 setParametersFromPluginConfigurationXml(m_currentTransform,
Chris@308 1324 configurationXml);
Chris@308 1325 return true;
Chris@308 1326 }
Chris@308 1327
Chris@308 1328 bool
Chris@308 1329 SVFileReader::readPluginForPlayback(const QXmlAttributes &attributes)
Chris@308 1330 {
Chris@308 1331 // Obsolete but supported for compatibility
Chris@308 1332
Chris@308 1333 QString ident = attributes.value("identifier");
Chris@308 1334 if (ident == "sample_player") {
Chris@309 1335 QString clipId = attributes.value("program");
Chris@309 1336 if (clipId != "") m_currentPlayParameters->setPlayClipId(clipId);
Chris@45 1337 }
Chris@45 1338
Chris@45 1339 return true;
Chris@45 1340 }
Chris@45 1341
Chris@45 1342 bool
Chris@72 1343 SVFileReader::readTransform(const QXmlAttributes &attributes)
Chris@72 1344 {
Chris@72 1345 if (m_currentDerivedModelId < 0) {
Chris@293 1346 cerr << "WARNING: SV-XML: Transform found outside derivation" << endl;
Chris@72 1347 return false;
Chris@72 1348 }
Chris@72 1349
Chris@82 1350 m_currentTransform = Transform();
Chris@72 1351 m_currentTransform.setFromXmlAttributes(attributes);
Chris@72 1352 return true;
Chris@72 1353 }
Chris@72 1354
Chris@72 1355 bool
Chris@72 1356 SVFileReader::readParameter(const QXmlAttributes &attributes)
Chris@72 1357 {
Chris@72 1358 if (m_currentDerivedModelId < 0) {
Chris@293 1359 cerr << "WARNING: SV-XML: Parameter found outside derivation" << endl;
Chris@72 1360 return false;
Chris@72 1361 }
Chris@72 1362
Chris@72 1363 QString name = attributes.value("name");
Chris@72 1364 if (name == "") {
Chris@293 1365 cerr << "WARNING: SV-XML: Ignoring nameless transform parameter"
Chris@293 1366 << endl;
Chris@72 1367 return false;
Chris@72 1368 }
Chris@72 1369
Chris@72 1370 float value = attributes.value("value").trimmed().toFloat();
Chris@72 1371
Chris@72 1372 m_currentTransform.setParameter(name, value);
Chris@72 1373 return true;
Chris@72 1374 }
Chris@72 1375
Chris@72 1376 bool
Chris@45 1377 SVFileReader::readSelection(const QXmlAttributes &attributes)
Chris@45 1378 {
Chris@45 1379 bool ok;
Chris@45 1380
Chris@45 1381 READ_MANDATORY(int, start, toInt);
Chris@45 1382 READ_MANDATORY(int, end, toInt);
Chris@45 1383
Chris@45 1384 m_paneCallback.addSelection(start, end);
Chris@45 1385
Chris@45 1386 return true;
Chris@45 1387 }
Chris@45 1388
Chris@45 1389 bool
Chris@45 1390 SVFileReader::readMeasurement(const QXmlAttributes &attributes)
Chris@45 1391 {
Chris@233 1392 SVDEBUG << "SVFileReader::readMeasurement: inLayer "
Chris@229 1393 << m_inLayer << ", layer " << m_currentLayer << endl;
Chris@45 1394
Chris@45 1395 if (!m_inLayer) {
Chris@293 1396 cerr << "WARNING: SV-XML: Measurement found outside layer" << endl;
Chris@45 1397 return false;
Chris@45 1398 }
Chris@45 1399
Chris@45 1400 m_currentLayer->addMeasurementRect(attributes);
Chris@45 1401 return true;
Chris@45 1402 }
Chris@45 1403
Chris@45 1404 SVFileReaderPaneCallback::~SVFileReaderPaneCallback()
Chris@45 1405 {
Chris@45 1406 }
Chris@45 1407
Chris@140 1408
Chris@140 1409 class SVFileIdentifier : public QXmlDefaultHandler
Chris@140 1410 {
Chris@140 1411 public:
Chris@140 1412 SVFileIdentifier() :
Chris@140 1413 m_inSv(false),
Chris@140 1414 m_inData(false),
Chris@140 1415 m_type(SVFileReader::UnknownFileType)
Chris@140 1416 { }
Chris@140 1417 virtual ~SVFileIdentifier() { }
Chris@140 1418
Chris@140 1419 void parse(QXmlInputSource &source) {
Chris@140 1420 QXmlSimpleReader reader;
Chris@140 1421 reader.setContentHandler(this);
Chris@140 1422 reader.setErrorHandler(this);
Chris@140 1423 reader.parse(source);
Chris@140 1424 }
Chris@140 1425
Chris@140 1426 SVFileReader::FileType getType() const { return m_type; }
Chris@140 1427
Chris@140 1428 virtual bool startElement(const QString &,
Chris@140 1429 const QString &,
Chris@140 1430 const QString &qName,
Chris@140 1431 const QXmlAttributes& atts)
Chris@140 1432 {
Chris@140 1433 QString name = qName.toLower();
Chris@140 1434
Chris@140 1435 // SV session files have an sv element containing a data
Chris@140 1436 // element containing a model element with mainModel="true".
Chris@140 1437
Chris@140 1438 // If the sv element is present but the rest does not satisfy,
Chris@140 1439 // then it's (probably) an SV layer file.
Chris@140 1440
Chris@140 1441 // Otherwise, it's of unknown type.
Chris@140 1442
Chris@140 1443 if (name == "sv") {
Chris@140 1444 m_inSv = true;
Chris@140 1445 if (m_type == SVFileReader::UnknownFileType) {
Chris@140 1446 m_type = SVFileReader::SVLayerFile;
Chris@140 1447 }
Chris@140 1448 return true;
Chris@140 1449 } else if (name == "data") {
Chris@140 1450 if (!m_inSv) return true;
Chris@140 1451 m_inData = true;
Chris@140 1452 } else if (name == "model") {
Chris@140 1453 if (!m_inData) return true;
Chris@140 1454 if (atts.value("mainModel").trimmed() == "true") {
Chris@140 1455 if (m_type == SVFileReader::SVLayerFile) {
Chris@140 1456 m_type = SVFileReader::SVSessionFile;
Chris@140 1457 return false; // done
Chris@140 1458 }
Chris@140 1459 }
Chris@140 1460 }
Chris@140 1461 return true;
Chris@140 1462 }
Chris@140 1463
Chris@140 1464 virtual bool endElement(const QString &,
Chris@140 1465 const QString &,
Chris@140 1466 const QString &qName)
Chris@140 1467 {
Chris@140 1468 QString name = qName.toLower();
Chris@140 1469
Chris@140 1470 if (name == "sv") {
Chris@140 1471 if (m_inSv) {
Chris@140 1472 m_inSv = false;
Chris@140 1473 return false; // done
Chris@140 1474 }
Chris@140 1475 } else if (name == "data") {
Chris@140 1476 if (m_inData) {
Chris@140 1477 m_inData = false;
Chris@140 1478 return false; // also done, nothing after the first
Chris@140 1479 // data element is of use here
Chris@140 1480 }
Chris@140 1481 }
Chris@140 1482 return true;
Chris@140 1483 }
Chris@140 1484
Chris@140 1485 private:
Chris@140 1486 bool m_inSv;
Chris@140 1487 bool m_inData;
Chris@140 1488 SVFileReader::FileType m_type;
Chris@140 1489 };
Chris@140 1490
Chris@140 1491
Chris@140 1492 SVFileReader::FileType
Chris@140 1493 SVFileReader::identifyXmlFile(QString path)
Chris@140 1494 {
Chris@140 1495 QFile file(path);
Chris@140 1496 SVFileIdentifier identifier;
Chris@140 1497 QXmlInputSource source(&file);
Chris@140 1498 identifier.parse(source);
Chris@140 1499 return identifier.getType();
Chris@140 1500 }
Chris@140 1501
Chris@140 1502
Chris@140 1503