svapp  1.9
SVFileReader.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "SVFileReader.h"
00017 
00018 #include "layer/Layer.h"
00019 #include "view/View.h"
00020 #include "base/PlayParameters.h"
00021 #include "base/PlayParameterRepository.h"
00022 #include "base/Preferences.h"
00023 
00024 #include "data/fileio/AudioFileReaderFactory.h"
00025 #include "data/fileio/FileSource.h"
00026 
00027 #include "data/fileio/FileFinder.h"
00028 
00029 #include "data/model/WaveFileModel.h"
00030 #include "data/model/EditableDenseThreeDimensionalModel.h"
00031 #include "data/model/SparseOneDimensionalModel.h"
00032 #include "data/model/SparseTimeValueModel.h"
00033 #include "data/model/NoteModel.h"
00034 #include "data/model/FlexiNoteModel.h"
00035 #include "data/model/RegionModel.h"
00036 #include "data/model/TextModel.h"
00037 #include "data/model/ImageModel.h"
00038 #include "data/model/AlignmentModel.h"
00039 
00040 #include "transform/TransformFactory.h"
00041 
00042 #include "view/Pane.h"
00043 
00044 #include "widgets/ProgressDialog.h"
00045 
00046 #include "Document.h"
00047 
00048 #include <QString>
00049 #include <QMessageBox>
00050 #include <QFileDialog>
00051 
00052 #include <iostream>
00053 
00054 SVFileReader::SVFileReader(Document *document,
00055                            SVFileReaderPaneCallback &callback,
00056                            QString location) :
00057     m_document(document),
00058     m_paneCallback(callback),
00059     m_location(location),
00060     m_currentPane(0),
00061     m_currentLayer(0),
00062     m_currentDataset(0),
00063     m_currentDerivedModel(0),
00064     m_currentDerivedModelId(-1),
00065     m_currentPlayParameters(0),
00066     m_currentTransformSource(0),
00067     m_currentTransformChannel(0),
00068     m_currentTransformIsNewStyle(true),
00069     m_datasetSeparator(" "),
00070     m_inRow(false),
00071     m_inLayer(false),
00072     m_inView(false),
00073     m_inData(false),
00074     m_inSelections(false),
00075     m_rowNumber(0),
00076     m_ok(false)
00077 {
00078 }
00079 
00080 void
00081 SVFileReader::parse(const QString &xmlData)
00082 {
00083     QXmlInputSource inputSource;
00084     inputSource.setData(xmlData);
00085     parse(inputSource);
00086 }
00087 
00088 void
00089 SVFileReader::parse(QXmlInputSource &inputSource)
00090 {
00091     QXmlSimpleReader reader;
00092     reader.setContentHandler(this);
00093     reader.setErrorHandler(this);
00094     m_ok = reader.parse(inputSource);
00095 }    
00096 
00097 bool
00098 SVFileReader::isOK()
00099 {
00100     return m_ok;
00101 }
00102         
00103 SVFileReader::~SVFileReader()
00104 {
00105     if (!m_awaitingDatasets.empty()) {
00106         cerr << "WARNING: SV-XML: File ended with "
00107                   << m_awaitingDatasets.size() << " unfilled model dataset(s)"
00108                   << endl;
00109     }
00110 
00111     std::set<Model *> unaddedModels;
00112 
00113     for (std::map<int, Model *>::iterator i = m_models.begin();
00114          i != m_models.end(); ++i) {
00115         if (m_addedModels.find(i->second) == m_addedModels.end()) {
00116             unaddedModels.insert(i->second);
00117         }
00118     }
00119 
00120     if (!unaddedModels.empty()) {
00121         cerr << "WARNING: SV-XML: File contained "
00122                   << unaddedModels.size() << " unused models"
00123                   << endl;
00124         while (!unaddedModels.empty()) {
00125             delete *unaddedModels.begin();
00126             unaddedModels.erase(unaddedModels.begin());
00127         }
00128     }   
00129 }
00130 
00131 bool
00132 SVFileReader::startElement(const QString &, const QString &,
00133                            const QString &qName,
00134                            const QXmlAttributes &attributes)
00135 {
00136     QString name = qName.toLower();
00137 
00138     bool ok = false;
00139 
00140     // Valid element names:
00141     //
00142     // sv
00143     // data
00144     // dataset
00145     // display
00146     // derivation
00147     // playparameters
00148     // layer
00149     // model
00150     // point
00151     // row
00152     // view
00153     // window
00154     // plugin
00155     // transform
00156     // selections
00157     // selection
00158     // measurement
00159 
00160     if (name == "sv") {
00161 
00162         // nothing needed
00163         ok = true;
00164 
00165     } else if (name == "data") {
00166 
00167         // nothing needed
00168         m_inData = true;
00169         ok = true;
00170 
00171     } else if (name == "display") {
00172 
00173         // nothing needed
00174         ok = true;
00175 
00176     } else if (name == "window") {
00177 
00178         ok = readWindow(attributes);
00179 
00180     } else if (name == "model") {
00181 
00182         ok = readModel(attributes);
00183     
00184     } else if (name == "dataset") {
00185         
00186         ok = readDatasetStart(attributes);
00187 
00188     } else if (name == "bin") {
00189         
00190         ok = addBinToDataset(attributes);
00191     
00192     } else if (name == "point") {
00193         
00194         ok = addPointToDataset(attributes);
00195 
00196     } else if (name == "row") {
00197 
00198         ok = addRowToDataset(attributes);
00199 
00200     } else if (name == "layer") {
00201 
00202         addUnaddedModels(); // all models must be specified before first layer
00203         ok = readLayer(attributes);
00204 
00205     } else if (name == "view") {
00206 
00207         m_inView = true;
00208         ok = readView(attributes);
00209 
00210     } else if (name == "derivation") {
00211 
00212         ok = readDerivation(attributes);
00213 
00214     } else if (name == "playparameters") {
00215         
00216         ok = readPlayParameters(attributes);
00217 
00218     } else if (name == "plugin") {
00219 
00220         ok = readPlugin(attributes);
00221 
00222     } else if (name == "selections") {
00223 
00224         m_inSelections = true;
00225         ok = true;
00226 
00227     } else if (name == "selection") {
00228 
00229         ok = readSelection(attributes);
00230 
00231     } else if (name == "measurement") {
00232 
00233         ok = readMeasurement(attributes);
00234 
00235     } else if (name == "transform") {
00236         
00237         ok = readTransform(attributes);
00238 
00239     } else if (name == "parameter") {
00240 
00241         ok = readParameter(attributes);
00242 
00243     } else {
00244         cerr << "WARNING: SV-XML: Unexpected element \""
00245                   << name << "\"" << endl;
00246     }
00247 
00248     if (!ok) {
00249         cerr << "WARNING: SV-XML: Failed to completely process element \""
00250                   << name << "\"" << endl;
00251     }
00252 
00253     return true;
00254 }
00255 
00256 bool
00257 SVFileReader::characters(const QString &text)
00258 {
00259     bool ok = false;
00260 
00261     if (m_inRow) {
00262         ok = readRowData(text);
00263         if (!ok) {
00264             cerr << "WARNING: SV-XML: Failed to read row data content for row " << m_rowNumber << endl;
00265         }
00266     }
00267 
00268     return true;
00269 }
00270 
00271 bool
00272 SVFileReader::endElement(const QString &, const QString &,
00273                          const QString &qName)
00274 {
00275     QString name = qName.toLower();
00276 
00277     if (name == "dataset") {
00278 
00279         if (m_currentDataset) {
00280             
00281             bool foundInAwaiting = false;
00282 
00283             for (std::map<int, int>::iterator i = m_awaitingDatasets.begin();
00284                  i != m_awaitingDatasets.end(); ++i) {
00285                 if (haveModel(i->second) &&
00286                     m_models[i->second] == m_currentDataset) {
00287                     m_awaitingDatasets.erase(i);
00288                     foundInAwaiting = true;
00289                     break;
00290                 }
00291             }
00292 
00293             if (!foundInAwaiting) {
00294                 cerr << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl;
00295             }
00296         }
00297 
00298         m_currentDataset = 0;
00299 
00300     } else if (name == "data") {
00301 
00302         addUnaddedModels();
00303         m_inData = false;
00304 
00305     } else if (name == "derivation") {
00306 
00307         if (!m_currentDerivedModel) {
00308             if (m_currentDerivedModelId < 0) {
00309                 cerr << "WARNING: SV-XML: Bad derivation output model id "
00310                           << m_currentDerivedModelId << endl;
00311             } else if (haveModel(m_currentDerivedModelId)) {
00312                 cerr << "WARNING: SV-XML: Derivation has existing model "
00313                           << m_currentDerivedModelId
00314                           << " as target, not regenerating" << endl;
00315             } else {
00316                 QString message;
00317                 m_currentDerivedModel = m_models[m_currentDerivedModelId] =
00318                     m_document->addDerivedModel
00319                     (m_currentTransform,
00320                      ModelTransformer::Input(m_currentTransformSource,
00321                                              m_currentTransformChannel),
00322                      message);
00323                 if (!m_currentDerivedModel) {
00324                     emit modelRegenerationFailed(tr("(derived model in SV-XML)"),
00325                                                  m_currentTransform.getIdentifier(),
00326                                                  message);
00327                 } else if (message != "") {
00328                     emit modelRegenerationWarning(tr("(derived model in SV-XML)"),
00329                                                   m_currentTransform.getIdentifier(),
00330                                                   message);
00331                 }                    
00332             }
00333         } else {
00334             m_document->addAlreadyDerivedModel
00335                 (m_currentTransform,
00336                  ModelTransformer::Input(m_currentTransformSource,
00337                                          m_currentTransformChannel),
00338                  m_currentDerivedModel);
00339         }
00340 
00341         m_addedModels.insert(m_currentDerivedModel);
00342         m_currentDerivedModel = 0;
00343         m_currentDerivedModelId = -1;
00344         m_currentTransformSource = 0;
00345         m_currentTransform = Transform();
00346         m_currentTransformChannel = -1;
00347 
00348     } else if (name == "row") {
00349         m_inRow = false;
00350     } else if (name == "layer") {
00351         m_inLayer = false;
00352     } else if (name == "view") {
00353         m_inView = false;
00354     } else if (name == "selections") {
00355         m_inSelections = false;
00356     } else if (name == "playparameters") {
00357         m_currentPlayParameters = 0;
00358     }
00359 
00360     return true;
00361 }
00362 
00363 bool
00364 SVFileReader::error(const QXmlParseException &exception)
00365 {
00366     m_errorString =
00367         QString("ERROR: SV-XML: %1 at line %2, column %3")
00368         .arg(exception.message())
00369         .arg(exception.lineNumber())
00370         .arg(exception.columnNumber());
00371     cerr << m_errorString << endl;
00372     return QXmlDefaultHandler::error(exception);
00373 }
00374 
00375 bool
00376 SVFileReader::fatalError(const QXmlParseException &exception)
00377 {
00378     m_errorString =
00379         QString("FATAL ERROR: SV-XML: %1 at line %2, column %3")
00380         .arg(exception.message())
00381         .arg(exception.lineNumber())
00382         .arg(exception.columnNumber());
00383     cerr << m_errorString << endl;
00384     return QXmlDefaultHandler::fatalError(exception);
00385 }
00386 
00387 
00388 #define READ_MANDATORY(TYPE, NAME, CONVERSION)                \
00389     TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \
00390     if (!ok) { \
00391         cerr << "WARNING: SV-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << endl; \
00392         return false; \
00393     }
00394 
00395 bool
00396 SVFileReader::readWindow(const QXmlAttributes &attributes)
00397 {
00398     bool ok = false;
00399 
00400     READ_MANDATORY(int, width, toInt);
00401     READ_MANDATORY(int, height, toInt);
00402 
00403     m_paneCallback.setWindowSize(width, height);
00404     return true;
00405 }
00406 
00407 void
00408 SVFileReader::addUnaddedModels()
00409 {
00410     std::set<Model *> unaddedModels;
00411     
00412     for (std::map<int, Model *>::iterator i = m_models.begin();
00413          i != m_models.end(); ++i) {
00414         if (m_addedModels.find(i->second) == m_addedModels.end()) {
00415             unaddedModels.insert(i->second);
00416         }
00417     }
00418     
00419     for (std::set<Model *>::iterator i = unaddedModels.begin();
00420          i != unaddedModels.end(); ++i) {
00421         Model *model = *i;
00422         // don't want to add these models, because their lifespans
00423         // are entirely dictated by the models that "own" them even
00424         // though they were read independently from the .sv file.
00425         // (pity we don't have a nicer way)
00426         if (!dynamic_cast<PathModel *>(model) &&
00427             !dynamic_cast<AlignmentModel *>(model)) {
00428             m_document->addImportedModel(model);
00429         }
00430         // but we add all models here, so they don't get deleted
00431         // when the file loader is destroyed
00432         m_addedModels.insert(model);
00433     }
00434 }
00435 
00436 bool
00437 SVFileReader::readModel(const QXmlAttributes &attributes)
00438 {
00439     bool ok = false;
00440 
00441     READ_MANDATORY(int, id, toInt);
00442 
00443     if (haveModel(id)) {
00444         cerr << "WARNING: SV-XML: Ignoring duplicate model id " << id
00445                   << endl;
00446         return false;
00447     }
00448 
00449     QString name = attributes.value("name");
00450 
00451     SVDEBUG << "SVFileReader::readModel: model name \"" << name << "\"" << endl;
00452 
00453     READ_MANDATORY(int, sampleRate, toInt);
00454 
00455     QString type = attributes.value("type").trimmed();
00456     bool isMainModel = (attributes.value("mainModel").trimmed() == "true");
00457 
00458     if (type == "wavefile") {
00459         
00460         WaveFileModel *model = 0;
00461         FileFinder *ff = FileFinder::getInstance();
00462         QString originalPath = attributes.value("file");
00463         QString path = ff->find(FileFinder::AudioFile,
00464                                 originalPath, m_location);
00465 
00466         SVDEBUG << "Wave file originalPath = " << originalPath << ", path = "
00467                   << path << endl;
00468 
00469         ProgressDialog dialog(tr("Opening file or URL..."), true, 2000);
00470         FileSource file(path, &dialog);
00471         file.waitForStatus();
00472 
00473         if (!file.isOK()) {
00474             cerr << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: " << file.getErrorString() << endl;
00475         } else if (!file.isAvailable()) {
00476             cerr << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: Source unavailable" << endl;
00477         } else {
00478 
00479             file.waitForData();
00480 
00481             int rate = sampleRate;
00482 
00483             if (Preferences::getInstance()->getFixedSampleRate() != 0) {
00484                 rate = Preferences::getInstance()->getFixedSampleRate();
00485             } else if (rate == 0 &&
00486                        !isMainModel &&
00487                        Preferences::getInstance()->getResampleOnLoad()) {
00488                 WaveFileModel *mm = m_document->getMainModel();
00489                 if (mm) rate = mm->getSampleRate();
00490             }
00491 
00492             model = new WaveFileModel(file, rate);
00493             if (!model->isOK()) {
00494                 delete model;
00495                 model = 0;
00496             }
00497         }
00498 
00499         if (!model) return false;
00500 
00501         model->setObjectName(name);
00502         m_models[id] = model;
00503         if (isMainModel) {
00504             m_document->setMainModel(model);
00505             m_addedModels.insert(model);
00506         }
00507         // Derived models will be added when their derivation
00508         // is found.
00509 
00510         return true;
00511 
00512     } else if (type == "dense") {
00513         
00514         READ_MANDATORY(int, dimensions, toInt);
00515                     
00516         // Currently the only dense model we support here is the dense
00517         // 3d model.  Dense time-value models are always file-backed
00518         // waveform data, at this point, and they come in as wavefile
00519         // models.
00520         
00521         if (dimensions == 3) {
00522             
00523             READ_MANDATORY(int, windowSize, toInt);
00524             READ_MANDATORY(int, yBinCount, toInt);
00525             
00526             EditableDenseThreeDimensionalModel *model =
00527                 new EditableDenseThreeDimensionalModel
00528                 (sampleRate, windowSize, yBinCount,
00529                  EditableDenseThreeDimensionalModel::NoCompression);
00530             
00531             float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
00532             if (ok) model->setMinimumLevel(minimum);
00533             
00534             float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
00535             if (ok) model->setMaximumLevel(maximum);
00536 
00537             int dataset = attributes.value("dataset").trimmed().toInt(&ok);
00538             if (ok) m_awaitingDatasets[dataset] = id;
00539 
00540             int startFrame = attributes.value("startFrame").trimmed().toInt(&ok);
00541             if (ok) model->setStartFrame(startFrame);
00542 
00543             model->setObjectName(name);
00544             m_models[id] = model;
00545             return true;
00546 
00547         } else {
00548 
00549             cerr << "WARNING: SV-XML: Unexpected dense model dimension ("
00550                       << dimensions << ")" << endl;
00551         }
00552     } else if (type == "sparse") {
00553 
00554         READ_MANDATORY(int, dimensions, toInt);
00555                   
00556         if (dimensions == 1) {
00557             
00558             READ_MANDATORY(int, resolution, toInt);
00559 
00560             if (attributes.value("subtype") == "image") {
00561 
00562                 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
00563                 ImageModel *model = new ImageModel(sampleRate, resolution,
00564                                                    notifyOnAdd);
00565                 model->setObjectName(name);
00566                 m_models[id] = model;
00567 
00568             } else {
00569 
00570                 SparseOneDimensionalModel *model = new SparseOneDimensionalModel
00571                     (sampleRate, resolution);
00572                 model->setObjectName(name);
00573                 m_models[id] = model;
00574             }
00575 
00576             int dataset = attributes.value("dataset").trimmed().toInt(&ok);
00577             if (ok) m_awaitingDatasets[dataset] = id;
00578 
00579             return true;
00580 
00581         } else if (dimensions == 2 || dimensions == 3) {
00582             
00583             READ_MANDATORY(int, resolution, toInt);
00584 
00585             bool haveMinMax = true;
00586             float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
00587             if (!ok) haveMinMax = false;
00588             float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
00589             if (!ok) haveMinMax = false;
00590 
00591             float valueQuantization =
00592                 attributes.value("valueQuantization").trimmed().toFloat(&ok);
00593 
00594             bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
00595 
00596             QString units = attributes.value("units");
00597 
00598             if (dimensions == 2) {
00599                 if (attributes.value("subtype") == "text") {
00600                     TextModel *model = new TextModel
00601                         (sampleRate, resolution, notifyOnAdd);
00602                     model->setObjectName(name);
00603                     m_models[id] = model;
00604                 } else if (attributes.value("subtype") == "path") {
00605                     PathModel *model = new PathModel
00606                         (sampleRate, resolution, notifyOnAdd);
00607                     model->setObjectName(name);
00608                     m_models[id] = model;
00609                 } else {
00610                     SparseTimeValueModel *model;
00611                     if (haveMinMax) {
00612                         model = new SparseTimeValueModel
00613                             (sampleRate, resolution, minimum, maximum, notifyOnAdd);
00614                     } else {
00615                         model = new SparseTimeValueModel
00616                             (sampleRate, resolution, notifyOnAdd);
00617                     }
00618                     model->setScaleUnits(units);
00619                     model->setObjectName(name);
00620                     m_models[id] = model;
00621                 }
00622             } else {
00623                 if (attributes.value("subtype") == "region") {
00624                     RegionModel *model;
00625                     if (haveMinMax) {
00626                         model = new RegionModel
00627                             (sampleRate, resolution, minimum, maximum, notifyOnAdd);
00628                     } else {
00629                         model = new RegionModel
00630                             (sampleRate, resolution, notifyOnAdd);
00631                     }
00632                     model->setValueQuantization(valueQuantization);
00633                     model->setScaleUnits(units);
00634                     model->setObjectName(name);
00635                     m_models[id] = model;
00636                 } else if (attributes.value("subtype") == "flexinote") {
00637                     FlexiNoteModel *model;
00638                     if (haveMinMax) {
00639                         model = new FlexiNoteModel
00640                             (sampleRate, resolution, minimum, maximum, notifyOnAdd);
00641                     } else {
00642                         model = new FlexiNoteModel
00643                             (sampleRate, resolution, notifyOnAdd);
00644                     }
00645                     model->setValueQuantization(valueQuantization);
00646                     model->setScaleUnits(units);
00647                     model->setObjectName(name);
00648                     m_models[id] = model;
00649                 } else {
00650                     // note models written out by SV 1.3 and earlier
00651                     // have no subtype, so we can't test that
00652                     NoteModel *model;
00653                     if (haveMinMax) {
00654                         model = new NoteModel
00655                             (sampleRate, resolution, minimum, maximum, notifyOnAdd);
00656                     } else {
00657                         model = new NoteModel
00658                             (sampleRate, resolution, notifyOnAdd);
00659                     }
00660                     model->setValueQuantization(valueQuantization);
00661                     model->setScaleUnits(units);
00662                     model->setObjectName(name);
00663                     m_models[id] = model;
00664                 }
00665             }
00666 
00667             int dataset = attributes.value("dataset").trimmed().toInt(&ok);
00668             if (ok) m_awaitingDatasets[dataset] = id;
00669 
00670             return true;
00671 
00672         } else {
00673 
00674             cerr << "WARNING: SV-XML: Unexpected sparse model dimension ("
00675                       << dimensions << ")" << endl;
00676         }
00677 
00678     } else if (type == "alignment") {
00679 
00680         READ_MANDATORY(int, reference, toInt);
00681         READ_MANDATORY(int, aligned, toInt);
00682         READ_MANDATORY(int, path, toInt);
00683 
00684         Model *refModel = 0, *alignedModel = 0, *pathModel = 0;
00685 
00686         if (m_models.find(reference) != m_models.end()) {
00687             refModel = m_models[reference];
00688         } else {
00689             cerr << "WARNING: SV-XML: Unknown reference model id "
00690                       << reference << " in alignment model id " << id
00691                       << endl;
00692         }
00693 
00694         if (m_models.find(aligned) != m_models.end()) {
00695             alignedModel = m_models[aligned];
00696         } else {
00697             cerr << "WARNING: SV-XML: Unknown aligned model id "
00698                       << aligned << " in alignment model id " << id
00699                       << endl;
00700         }
00701 
00702         if (m_models.find(path) != m_models.end()) {
00703             pathModel = m_models[path];
00704         } else {
00705             cerr << "WARNING: SV-XML: Unknown path model id "
00706                       << path << " in alignment model id " << id
00707                       << endl;
00708         }
00709 
00710         if (refModel && alignedModel && pathModel) {
00711             AlignmentModel *model = new AlignmentModel
00712                 (refModel, alignedModel, 0, 0);
00713             PathModel *pm = dynamic_cast<PathModel *>(pathModel);
00714             if (!pm) {
00715                 cerr << "WARNING: SV-XML: Model id " << path
00716                           << " referenced as path for alignment " << id
00717                           << " is not a path model" << endl;
00718             } else {
00719                 model->setPath(pm);
00720                 pm->setCompletion(100);
00721             }
00722             model->setObjectName(name);
00723             m_models[id] = model;
00724             alignedModel->setAlignment(model);
00725             return true;
00726         }
00727         
00728     } else {
00729 
00730         cerr << "WARNING: SV-XML: Unexpected model type \""
00731                   << type << "\" for model id " << id << endl;
00732     }
00733 
00734     return false;
00735 }
00736 
00737 bool
00738 SVFileReader::readView(const QXmlAttributes &attributes)
00739 {
00740     QString type = attributes.value("type");
00741     m_currentPane = 0;
00742     
00743     if (type != "pane") {
00744         cerr << "WARNING: SV-XML: Unexpected view type \""
00745                   << type << "\"" << endl;
00746         return false;
00747     }
00748 
00749     m_currentPane = m_paneCallback.addPane();
00750 
00751     cerr << "SVFileReader::addPane: pane is " << m_currentPane << endl;
00752 
00753     if (!m_currentPane) {
00754         cerr << "WARNING: SV-XML: Internal error: Failed to add pane!"
00755                   << endl;
00756         return false;
00757     }
00758 
00759     bool ok = false;
00760 
00761     View *view = m_currentPane;
00762 
00763     // The view properties first
00764 
00765     READ_MANDATORY(int, centre, toInt);
00766     READ_MANDATORY(int, zoom, toInt);
00767     READ_MANDATORY(int, followPan, toInt);
00768     READ_MANDATORY(int, followZoom, toInt);
00769     QString tracking = attributes.value("tracking");
00770 
00771     // Specify the follow modes before we set the actual values
00772     view->setFollowGlobalPan(followPan);
00773     view->setFollowGlobalZoom(followZoom);
00774     view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
00775                             tracking == "page" ? PlaybackScrollPageWithCentre :
00776                             tracking == "daw" ? PlaybackScrollPage
00777                             : PlaybackIgnore);
00778 
00779     // Then set these values
00780     view->setCentreFrame(centre);
00781     view->setZoomLevel(zoom);
00782 
00783     // And pane properties
00784     READ_MANDATORY(int, centreLineVisible, toInt);
00785     m_currentPane->setCentreLineVisible(centreLineVisible);
00786 
00787     int height = attributes.value("height").toInt(&ok);
00788     if (ok) {
00789         m_currentPane->resize(m_currentPane->width(), height);
00790     }
00791 
00792     return true;
00793 }
00794 
00795 bool
00796 SVFileReader::readLayer(const QXmlAttributes &attributes)
00797 {
00798     QString type = attributes.value("type");
00799 
00800     int id;
00801     bool ok = false;
00802     id = attributes.value("id").trimmed().toInt(&ok);
00803 
00804     if (!ok) {
00805         cerr << "WARNING: SV-XML: No layer id for layer of type \""
00806                   << type
00807                   << "\"" << endl;
00808         return false;
00809     }
00810 
00811     Layer *layer = 0;
00812     bool isNewLayer = false;
00813 
00814     // Layers are expected to be defined in layer elements in the data
00815     // section, and referred to in layer elements in the view
00816     // sections.  So if we're in the data section, we expect this
00817     // layer not to exist already; if we're in the view section, we
00818     // expect it to exist.
00819 
00820     if (m_inData) {
00821 
00822         if (m_layers.find(id) != m_layers.end()) {
00823             cerr << "WARNING: SV-XML: Ignoring duplicate layer id " << id
00824                       << " in data section" << endl;
00825             return false;
00826         }
00827 
00828         layer = m_layers[id] = m_document->createLayer
00829             (LayerFactory::getInstance()->getLayerTypeForName(type));
00830 
00831         if (layer) {
00832             m_layers[id] = layer;
00833             isNewLayer = true;
00834         }
00835 
00836     } else {
00837 
00838         if (!m_currentPane) {
00839             cerr << "WARNING: SV-XML: No current pane for layer " << id
00840                       << " in view section" << endl;
00841             return false;
00842         }
00843 
00844         if (m_layers.find(id) != m_layers.end()) {
00845             
00846             layer = m_layers[id];
00847         
00848         } else {
00849             cerr << "WARNING: SV-XML: Layer id " << id 
00850                       << " in view section has not been defined -- defining it here"
00851                       << endl;
00852 
00853             layer = m_document->createLayer
00854                 (LayerFactory::getInstance()->getLayerTypeForName(type));
00855 
00856             if (layer) {
00857                 m_layers[id] = layer;
00858                 isNewLayer = true;
00859             }
00860         }
00861     }
00862             
00863     if (!layer) {
00864         cerr << "WARNING: SV-XML: Failed to add layer of type \""
00865                   << type
00866                   << "\"" << endl;
00867         return false;
00868     }
00869 
00870     if (isNewLayer) {
00871 
00872         QString name = attributes.value("name");
00873         layer->setObjectName(name);
00874 
00875         QString presentationName = attributes.value("presentationName");
00876         layer->setPresentationName(presentationName);
00877 
00878         int modelId;
00879         bool modelOk = false;
00880         modelId = attributes.value("model").trimmed().toInt(&modelOk);
00881 
00882         if (modelOk) {
00883             if (haveModel(modelId)) {
00884                 Model *model = m_models[modelId];
00885                 m_document->setModel(layer, model);
00886             } else {
00887                 cerr << "WARNING: SV-XML: Unknown model id " << modelId
00888                           << " in layer definition" << endl;
00889             }
00890         }
00891 
00892         layer->setProperties(attributes);
00893     }
00894 
00895     if (!m_inData && m_currentPane) {
00896 
00897         QString visible = attributes.value("visible");
00898         bool dormant = (visible == "false");
00899 
00900         // We need to do this both before and after adding the layer
00901         // to the view -- we need it to be dormant if appropriate
00902         // before it's actually added to the view so that any property
00903         // box gets the right state when it's added, but the add layer
00904         // command sets dormant to false because it assumes it may be
00905         // restoring a previously dormant layer, so we need to set it
00906         // again afterwards too.  Hm
00907         layer->setLayerDormant(m_currentPane, dormant);
00908 
00909         m_document->addLayerToView(m_currentPane, layer);
00910 
00911         layer->setLayerDormant(m_currentPane, dormant);
00912     }
00913 
00914     m_currentLayer = layer;
00915     m_inLayer = true;
00916 
00917     return true;
00918 }
00919 
00920 bool
00921 SVFileReader::readDatasetStart(const QXmlAttributes &attributes)
00922 {
00923     bool ok = false;
00924 
00925     READ_MANDATORY(int, id, toInt);
00926     READ_MANDATORY(int, dimensions, toInt);
00927     
00928     if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) {
00929         cerr << "WARNING: SV-XML: Unwanted dataset " << id << endl;
00930         return false;
00931     }
00932     
00933     int modelId = m_awaitingDatasets[id];
00934     
00935     Model *model = 0;
00936     if (haveModel(modelId)) {
00937         model = m_models[modelId];
00938     } else {
00939         cerr << "WARNING: SV-XML: Internal error: Unknown model " << modelId
00940                   << " expecting dataset " << id << endl;
00941         return false;
00942     }
00943 
00944     bool good = false;
00945 
00946     switch (dimensions) {
00947     case 1:
00948         if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true;
00949         else if (dynamic_cast<ImageModel *>(model)) good = true;
00950         break;
00951 
00952     case 2:
00953         if (dynamic_cast<SparseTimeValueModel *>(model)) good = true;
00954         else if (dynamic_cast<TextModel *>(model)) good = true;
00955         else if (dynamic_cast<PathModel *>(model)) good = true;
00956         break;
00957 
00958     case 3:
00959         if (dynamic_cast<NoteModel *>(model)) good = true;
00960         else if (dynamic_cast<FlexiNoteModel *>(model)) good = true;
00961         else if (dynamic_cast<RegionModel *>(model)) good = true;
00962         else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) {
00963             m_datasetSeparator = attributes.value("separator");
00964             good = true;
00965         }
00966         break;
00967     }
00968 
00969     if (!good) {
00970         cerr << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl;
00971         m_currentDataset = 0;
00972         return false;
00973     }
00974 
00975     m_currentDataset = model;
00976     return true;
00977 }
00978 
00979 bool
00980 SVFileReader::addPointToDataset(const QXmlAttributes &attributes)
00981 {
00982     bool ok = false;
00983 
00984     READ_MANDATORY(int, frame, toInt);
00985 
00986 //    SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl;
00987 
00988     SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
00989         (m_currentDataset);
00990 
00991     if (sodm) {
00992 //        cerr << "Current dataset is a sparse one dimensional model" << endl;
00993         QString label = attributes.value("label");
00994         sodm->addPoint(SparseOneDimensionalModel::Point(frame, label));
00995         return true;
00996     }
00997 
00998     SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>
00999         (m_currentDataset);
01000 
01001     if (stvm) {
01002         cerr << "Current dataset is a sparse time-value model" << endl;
01003         float value = 0.0;
01004         value = attributes.value("value").trimmed().toFloat(&ok);
01005         QString label = attributes.value("label");
01006         stvm->addPoint(SparseTimeValueModel::Point(frame, value, label));
01007         return ok;
01008     }
01009         
01010     NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset);
01011 
01012     if (nm) {
01013         cerr << "Current dataset is a note model" << endl;
01014         float value = 0.0;
01015         value = attributes.value("value").trimmed().toFloat(&ok);
01016         int duration = 0;
01017         duration = attributes.value("duration").trimmed().toInt(&ok);
01018         QString label = attributes.value("label");
01019         float level = attributes.value("level").trimmed().toFloat(&ok);
01020         if (!ok) { // level is optional
01021             level = 1.f;
01022             ok = true;
01023         }
01024         nm->addPoint(NoteModel::Point(frame, value, duration, level, label));
01025         return ok;
01026     }
01027 
01028     FlexiNoteModel *fnm = dynamic_cast<FlexiNoteModel *>(m_currentDataset);
01029 
01030     if (fnm) {
01031         cerr << "Current dataset is a flexinote model" << endl;
01032         float value = 0.0;
01033         value = attributes.value("value").trimmed().toFloat(&ok);
01034         int duration = 0;
01035         duration = attributes.value("duration").trimmed().toInt(&ok);
01036         QString label = attributes.value("label");
01037         float level = attributes.value("level").trimmed().toFloat(&ok);
01038         if (!ok) { // level is optional
01039             level = 1.f;
01040             ok = true;
01041         }
01042         fnm->addPoint(FlexiNoteModel::Point(frame, value, duration, level, label));
01043         return ok;
01044     }
01045 
01046     RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset);
01047 
01048     if (rm) {
01049         cerr << "Current dataset is a region model" << endl;
01050         float value = 0.0;
01051         value = attributes.value("value").trimmed().toFloat(&ok);
01052         int duration = 0;
01053         duration = attributes.value("duration").trimmed().toInt(&ok);
01054         QString label = attributes.value("label");
01055         rm->addPoint(RegionModel::Point(frame, value, duration, label));
01056         return ok;
01057     }
01058 
01059     TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset);
01060 
01061     if (tm) {
01062 //        cerr << "Current dataset is a text model" << endl;
01063         float height = 0.0;
01064         height = attributes.value("height").trimmed().toFloat(&ok);
01065         QString label = attributes.value("label");
01066 //        SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl;
01067         tm->addPoint(TextModel::Point(frame, height, label));
01068         return ok;
01069     }
01070 
01071     PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset);
01072 
01073     if (pm) {
01074 //        cerr << "Current dataset is a path model" << endl;
01075         int mapframe = attributes.value("mapframe").trimmed().toInt(&ok);
01076 //        SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl;
01077         pm->addPoint(PathModel::Point(frame, mapframe));
01078         return ok;
01079     }
01080 
01081     ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset);
01082 
01083     if (im) {
01084 //        cerr << "Current dataset is an image model" << endl;
01085         QString image = attributes.value("image");
01086         QString label = attributes.value("label");
01087 //        SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl;
01088         im->addPoint(ImageModel::Point(frame, image, label));
01089         return ok;
01090     }
01091 
01092     cerr << "WARNING: SV-XML: Point element found in non-point dataset" << endl;
01093 
01094     return false;
01095 }
01096 
01097 bool
01098 SVFileReader::addBinToDataset(const QXmlAttributes &attributes)
01099 {
01100     EditableDenseThreeDimensionalModel *dtdm = 
01101         dynamic_cast<EditableDenseThreeDimensionalModel *>
01102         (m_currentDataset);
01103 
01104     if (dtdm) {
01105 
01106         bool ok = false;
01107         int n = attributes.value("number").trimmed().toInt(&ok);
01108         if (!ok) {
01109             cerr << "WARNING: SV-XML: Missing or invalid bin number"
01110                       << endl;
01111             return false;
01112         }
01113 
01114         QString name = attributes.value("name");
01115 
01116         dtdm->setBinName(n, name);
01117         return true;
01118     }
01119 
01120     cerr << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl;
01121 
01122     return false;
01123 }
01124 
01125 
01126 bool
01127 SVFileReader::addRowToDataset(const QXmlAttributes &attributes)
01128 {
01129     m_inRow = false;
01130 
01131     bool ok = false;
01132     m_rowNumber = attributes.value("n").trimmed().toInt(&ok);
01133     if (!ok) {
01134         cerr << "WARNING: SV-XML: Missing or invalid row number"
01135                   << endl;
01136         return false;
01137     }
01138     
01139     m_inRow = true;
01140 
01141 //    cerr << "SV-XML: In row " << m_rowNumber << endl;
01142     
01143     return true;
01144 }
01145 
01146 bool
01147 SVFileReader::readRowData(const QString &text)
01148 {
01149     EditableDenseThreeDimensionalModel *dtdm =
01150         dynamic_cast<EditableDenseThreeDimensionalModel *>
01151         (m_currentDataset);
01152 
01153     bool warned = false;
01154 
01155     if (dtdm) {
01156         QStringList data = text.split(m_datasetSeparator);
01157 
01158         DenseThreeDimensionalModel::Column values;
01159 
01160         for (QStringList::iterator i = data.begin(); i != data.end(); ++i) {
01161 
01162             if (values.size() == (int)dtdm->getHeight()) {
01163                 if (!warned) {
01164                     cerr << "WARNING: SV-XML: Too many y-bins in 3-D dataset row "
01165                               << m_rowNumber << endl;
01166                     warned = true;
01167                 }
01168             }
01169 
01170             bool ok;
01171             float value = i->toFloat(&ok);
01172             if (!ok) {
01173                 cerr << "WARNING: SV-XML: Bad floating-point value "
01174                           << i->toLocal8Bit().data()
01175                           << " in row data" << endl;
01176             } else {
01177                 values.push_back(value);
01178             }
01179         }
01180 
01181         dtdm->setColumn(m_rowNumber, values);
01182         return true;
01183     }
01184 
01185     cerr << "WARNING: SV-XML: Row data found in non-row dataset" << endl;
01186 
01187     return false;
01188 }
01189 
01190 bool
01191 SVFileReader::readDerivation(const QXmlAttributes &attributes)
01192 {
01193     int modelId = 0;
01194     bool modelOk = false;
01195     modelId = attributes.value("model").trimmed().toInt(&modelOk);
01196 
01197     if (!modelOk) {
01198         cerr << "WARNING: SV-XML: No model id specified for derivation" << endl;
01199         return false;
01200     }
01201 
01202     if (haveModel(modelId)) {
01203         m_currentDerivedModel = m_models[modelId];
01204     } else {
01205         // we'll regenerate the model when the derivation element ends
01206         m_currentDerivedModel = 0;
01207     }
01208     
01209     m_currentDerivedModelId = modelId;
01210     
01211     int sourceId = 0;
01212     bool sourceOk = false;
01213     sourceId = attributes.value("source").trimmed().toInt(&sourceOk);
01214 
01215     if (sourceOk && haveModel(sourceId)) {
01216         m_currentTransformSource = m_models[sourceId];
01217     } else {
01218         m_currentTransformSource = m_document->getMainModel();
01219     }
01220 
01221     m_currentTransform = Transform();
01222 
01223     bool ok = false;
01224     int channel = attributes.value("channel").trimmed().toInt(&ok);
01225     if (ok) m_currentTransformChannel = channel;
01226     else m_currentTransformChannel = -1;
01227 
01228     QString type = attributes.value("type");
01229 
01230     if (type == "transform") {
01231         m_currentTransformIsNewStyle = true;
01232         return true;
01233     } else {
01234         m_currentTransformIsNewStyle = false;
01235         SVDEBUG << "NOTE: SV-XML: Reading old-style derivation element"
01236                   << endl;
01237     }
01238 
01239     QString transformId = attributes.value("transform");
01240 
01241     m_currentTransform.setIdentifier(transformId);
01242 
01243     int stepSize = attributes.value("stepSize").trimmed().toInt(&ok);
01244     if (ok) m_currentTransform.setStepSize(stepSize);
01245 
01246     int blockSize = attributes.value("blockSize").trimmed().toInt(&ok);
01247     if (ok) m_currentTransform.setBlockSize(blockSize);
01248 
01249     int windowType = attributes.value("windowType").trimmed().toInt(&ok);
01250     if (ok) m_currentTransform.setWindowType(WindowType(windowType));
01251 
01252     if (!m_currentTransformSource) return true;
01253 
01254     QString startFrameStr = attributes.value("startFrame");
01255     QString durationStr = attributes.value("duration");
01256 
01257     int startFrame = 0;
01258     int duration = 0;
01259 
01260     if (startFrameStr != "") {
01261         startFrame = startFrameStr.trimmed().toInt(&ok);
01262         if (!ok) startFrame = 0;
01263     }
01264     if (durationStr != "") {
01265         duration = durationStr.trimmed().toInt(&ok);
01266         if (!ok) duration = 0;
01267     }
01268 
01269     m_currentTransform.setStartTime
01270         (RealTime::frame2RealTime
01271          (startFrame, m_currentTransformSource->getSampleRate()));
01272 
01273     m_currentTransform.setDuration
01274         (RealTime::frame2RealTime
01275          (duration, m_currentTransformSource->getSampleRate()));
01276 
01277     return true;
01278 }
01279 
01280 bool
01281 SVFileReader::readPlayParameters(const QXmlAttributes &attributes)
01282 {
01283     m_currentPlayParameters = 0;
01284 
01285     int modelId = 0;
01286     bool modelOk = false;
01287     modelId = attributes.value("model").trimmed().toInt(&modelOk);
01288 
01289     if (!modelOk) {
01290         cerr << "WARNING: SV-XML: No model id specified for play parameters" << endl;
01291         return false;
01292     }
01293 
01294     if (haveModel(modelId)) {
01295 
01296         bool ok = false;
01297 
01298         PlayParameters *parameters = PlayParameterRepository::getInstance()->
01299             getPlayParameters(m_models[modelId]);
01300 
01301         if (!parameters) {
01302             cerr << "WARNING: SV-XML: Play parameters for model "
01303                       << modelId
01304                       << " not found - has model been added to document?"
01305                       << endl;
01306             return false;
01307         }
01308         
01309         bool muted = (attributes.value("mute").trimmed() == "true");
01310         parameters->setPlayMuted(muted);
01311         
01312         float pan = attributes.value("pan").toFloat(&ok);
01313         if (ok) parameters->setPlayPan(pan);
01314         
01315         float gain = attributes.value("gain").toFloat(&ok);
01316         if (ok) parameters->setPlayGain(gain);
01317         
01318         QString clipId = attributes.value("clipId");
01319         if (clipId != "") parameters->setPlayClipId(clipId);
01320         
01321         m_currentPlayParameters = parameters;
01322 
01323 //        cerr << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl;
01324 
01325     } else {
01326 
01327         cerr << "WARNING: SV-XML: Unknown model " << modelId
01328                   << " for play parameters" << endl;
01329         return false;
01330     }
01331 
01332     return true;
01333 }
01334 
01335 bool
01336 SVFileReader::readPlugin(const QXmlAttributes &attributes)
01337 {
01338     if (m_currentDerivedModelId >= 0) {
01339         return readPluginForTransform(attributes);
01340     } else if (m_currentPlayParameters) {
01341         return readPluginForPlayback(attributes);
01342     } else {
01343         cerr << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl;
01344         return false;
01345     }
01346 }
01347 
01348 bool
01349 SVFileReader::readPluginForTransform(const QXmlAttributes &attributes)
01350 {
01351     if (m_currentTransformIsNewStyle) {
01352         // Not needed, we have the transform element instead
01353         return true;
01354     }
01355 
01356     QString configurationXml = "<plugin";
01357 
01358     for (int i = 0; i < attributes.length(); ++i) {
01359         configurationXml += QString(" %1=\"%2\"")
01360             .arg(attributes.qName(i))
01361             .arg(XmlExportable::encodeEntities(attributes.value(i)));
01362     }
01363 
01364     configurationXml += "/>";
01365 
01366     TransformFactory::getInstance()->
01367         setParametersFromPluginConfigurationXml(m_currentTransform,
01368                                                 configurationXml);
01369     return true;
01370 }
01371 
01372 bool
01373 SVFileReader::readPluginForPlayback(const QXmlAttributes &attributes)
01374 {
01375     // Obsolete but supported for compatibility
01376 
01377     QString ident = attributes.value("identifier");
01378     if (ident == "sample_player") {
01379         QString clipId = attributes.value("program");
01380         if (clipId != "") m_currentPlayParameters->setPlayClipId(clipId);
01381     }
01382 
01383     return true;
01384 }
01385 
01386 bool
01387 SVFileReader::readTransform(const QXmlAttributes &attributes)
01388 {
01389     if (m_currentDerivedModelId < 0) {
01390         cerr << "WARNING: SV-XML: Transform found outside derivation" << endl;
01391         return false;
01392     }
01393 
01394     m_currentTransform = Transform();
01395     m_currentTransform.setFromXmlAttributes(attributes);
01396     return true;
01397 }
01398 
01399 bool
01400 SVFileReader::readParameter(const QXmlAttributes &attributes)
01401 {
01402     if (m_currentDerivedModelId < 0) {
01403         cerr << "WARNING: SV-XML: Parameter found outside derivation" << endl;
01404         return false;
01405     }
01406 
01407     QString name = attributes.value("name");
01408     if (name == "") {
01409         cerr << "WARNING: SV-XML: Ignoring nameless transform parameter"
01410                   << endl;
01411         return false;
01412     }
01413 
01414     float value = attributes.value("value").trimmed().toFloat();
01415 
01416     m_currentTransform.setParameter(name, value);
01417     return true;
01418 }
01419 
01420 bool
01421 SVFileReader::readSelection(const QXmlAttributes &attributes)
01422 {
01423     bool ok;
01424 
01425     READ_MANDATORY(int, start, toInt);
01426     READ_MANDATORY(int, end, toInt);
01427 
01428     m_paneCallback.addSelection(start, end);
01429 
01430     return true;
01431 }
01432 
01433 bool
01434 SVFileReader::readMeasurement(const QXmlAttributes &attributes)
01435 {
01436     SVDEBUG << "SVFileReader::readMeasurement: inLayer "
01437               << m_inLayer << ", layer " << m_currentLayer << endl;
01438 
01439     if (!m_inLayer) {
01440         cerr << "WARNING: SV-XML: Measurement found outside layer" << endl;
01441         return false;
01442     }
01443 
01444     m_currentLayer->addMeasurementRect(attributes);
01445     return true;
01446 }
01447 
01448 SVFileReaderPaneCallback::~SVFileReaderPaneCallback()
01449 {
01450 }
01451 
01452 
01453 class SVFileIdentifier : public QXmlDefaultHandler
01454 {
01455 public:
01456     SVFileIdentifier() :
01457         m_inSv(false),
01458         m_inData(false),
01459         m_type(SVFileReader::UnknownFileType)
01460     { }
01461     virtual ~SVFileIdentifier() { }
01462 
01463     void parse(QXmlInputSource &source) {
01464         QXmlSimpleReader reader;
01465         reader.setContentHandler(this);
01466         reader.setErrorHandler(this);
01467         reader.parse(source);
01468     }
01469 
01470     SVFileReader::FileType getType() const { return m_type; }
01471 
01472     virtual bool startElement(const QString &,
01473                               const QString &,
01474                               const QString &qName,
01475                               const QXmlAttributes& atts)
01476     {
01477         QString name = qName.toLower();
01478 
01479         // SV session files have an sv element containing a data
01480         // element containing a model element with mainModel="true".
01481 
01482         // If the sv element is present but the rest does not satisfy,
01483         // then it's (probably) an SV layer file.
01484 
01485         // Otherwise, it's of unknown type.
01486 
01487         if (name == "sv") {
01488             m_inSv = true;
01489             if (m_type == SVFileReader::UnknownFileType) {
01490                 m_type = SVFileReader::SVLayerFile;
01491             }
01492             return true;
01493         } else if (name == "data") {
01494             if (!m_inSv) return true;
01495             m_inData = true;
01496         } else if (name == "model") {
01497             if (!m_inData) return true;
01498             if (atts.value("mainModel").trimmed() == "true") {
01499                 if (m_type == SVFileReader::SVLayerFile) {
01500                     m_type = SVFileReader::SVSessionFile;
01501                     return false; // done
01502                 }
01503             }
01504         }
01505         return true;
01506     }
01507 
01508     virtual bool endElement(const QString &,
01509                             const QString &,
01510                             const QString &qName)
01511     {
01512         QString name = qName.toLower();
01513 
01514         if (name == "sv") {
01515             if (m_inSv) {
01516                 m_inSv = false;
01517                 return false; // done
01518             }
01519         } else if (name == "data") {
01520             if (m_inData) {
01521                 m_inData = false;
01522                 return false; // also done, nothing after the first
01523                               // data element is of use here
01524             }
01525         }
01526         return true;
01527     }
01528 
01529 private:
01530     bool m_inSv;
01531     bool m_inData;
01532     SVFileReader::FileType m_type;
01533 };
01534 
01535 
01536 SVFileReader::FileType
01537 SVFileReader::identifyXmlFile(QString path)
01538 {
01539     QFile file(path);
01540     SVFileIdentifier identifier;
01541     QXmlInputSource source(&file);
01542     identifier.parse(source);
01543     return identifier.getType();
01544 }
01545 
01546     
01547