diff data/fileio/ModelReader.cpp @ 15:11e298cdb9e7

add - EasaierSessionManager - Easaier menus - Interval model
author lbajardsilogic
date Mon, 14 May 2007 13:10:49 +0000
parents
children 4eb9c7e4acf6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/ModelReader.cpp	Mon May 14 13:10:49 2007 +0000
@@ -0,0 +1,551 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*	Sound Access	
+		EASAIER client application.	
+		Silogic 2007. Laure Bajard. 
+	
+	This program is free software; you can redistribute it and/or    
+	modify it under the terms of the GNU General Public License as    
+	published by the Free Software Foundation; either version 2 of the    
+	License, or (at your option) any later version.  See the file    
+	COPYING included with this distribution for more information.
+*/
+
+#include "ModelReader.h"
+
+#include "document/Document.h"
+#include "layer/Layer.h"
+
+#include "data/model/EditableDenseThreeDimensionalModel.h"
+#include "data/model/SparseOneDimensionalModel.h"
+#include "data/model/SparseTimeValueModel.h"
+#include "data/model/NoteModel.h"
+#include "data/model/TextModel.h"
+#include "data/model/IntervalModel.h"
+#include "view/Pane.h"
+
+#include <iostream>
+
+ModelReader::ModelReader(Document *document, Layer * layer, Pane * pane) : 
+	m_document(document),
+	m_layer(layer),
+	m_pane(pane)
+{}
+
+bool ModelReader::parse(const QString & filename)
+{
+	ModelHandler handler(m_document, m_layer, m_pane);
+    QXmlSimpleReader reader;
+    reader.setContentHandler(&handler);
+    reader.setErrorHandler(&handler);
+
+	QFile file(filename);
+
+    if (!file.open(QFile::ReadOnly | QFile::Text)) {
+        return false;
+    }
+
+    QXmlInputSource xmlInputSource(&file);
+    if (reader.parse(xmlInputSource))
+	{
+		return true;
+	}
+	
+	return false;
+}
+
+ModelHandler::ModelHandler(Document *document, Layer * layer, Pane* pane) : QXmlDefaultHandler(),
+	m_document(document),
+	m_layer(layer),
+	m_pane(pane),
+    m_model(0),
+    m_datasetSeparator(" "),
+    m_inData(false),
+	m_inRow(false),
+    m_rowNumber(0)
+{}
+
+bool ModelHandler::startElement(const QString &namespaceURI, const QString &localName,
+						  const QString &qName, const QXmlAttributes &attributes)
+{
+	
+    QString name = qName.toLower();
+
+    bool ok = false;
+
+    // Valid element names:
+    //
+    // easaier
+    // data
+    // dataset
+    // model
+    // point
+    // row
+	// interval
+    
+    if (name == "easaier") {
+
+		// nothing needed
+		ok = true;
+
+    } else if (name == "data") {
+
+		m_inData = true;
+		if (m_layer == 0)
+		{
+			ok = readLayer(attributes);
+		} else {
+			ok = true;
+		}
+
+    } else if (name == "model") {
+
+		ok = readModel(attributes);
+    
+    } else if (name == "dataset") {
+	
+		ok = readDatasetStart(attributes);
+
+    } else if (name == "bin") {
+	
+		ok = addBinToDataset(attributes);
+    
+    } else if (name == "point") {
+	
+		ok = addPointToDataset(attributes);
+
+    } else if (name == "row") {
+
+		ok = addRowToDataset(attributes);
+
+    } else if (name == "interval") {
+	
+		ok = addIntervalToDataset(attributes);
+
+    } 
+
+    if (!ok) {
+		std::cerr << "WARNING: ModelReader-XML: Failed to completely process element \""
+		  << name.toLocal8Bit().data() << "\"" << std::endl;
+    }
+
+    return true;
+}
+
+bool ModelHandler::endElement(const QString &namespaceURI, const QString &localName,
+						const QString &qName)
+{
+	QString name = qName.toLower();
+
+    if (name == "dataset") 
+	{
+		if ((m_model) && (m_layer))
+		{
+			m_document->addImportedModel(m_model);
+			m_document->setModel(m_layer, m_model);
+		}
+    } 
+	else if (name == "data") 
+	{
+        m_inData = false;
+		if (m_pane && m_layer)
+		{
+			m_document->addLayerToView(m_pane, m_layer);
+		}
+    } 
+	else if (name == "row") 
+	{
+		m_inRow = false;
+    } 
+
+    return true;
+}
+
+bool ModelHandler::characters(const QString &str)
+{
+	bool ok = false;
+
+    if (m_inRow) {
+		ok = readRowData(str);
+		if (!ok) {
+			std::cerr << "WARNING: ModelReader-XML: Failed to read row data content for row " << m_rowNumber << std::endl;
+		}
+    }
+
+    return true;
+}
+
+bool ModelHandler::error(const QXmlParseException &exception)
+{
+	QString errorString;
+	errorString += QString("ERROR: ModelReader-XML: %1 at line %2, column %3")
+	.arg(exception.message())
+	.arg(exception.lineNumber())
+	.arg(exception.columnNumber());
+    std::cerr << errorString.toLocal8Bit().data() << std::endl;
+    return QXmlDefaultHandler::error(exception);
+}
+
+bool ModelHandler::fatalError(const QXmlParseException &exception)
+{
+	QString errorString;
+	errorString += QString("FATAL ERROR: ModelReader-XML: %1 at line %2, column %3")
+	.arg(exception.message())
+	.arg(exception.lineNumber())
+	.arg(exception.columnNumber());
+    std::cerr << errorString.toLocal8Bit().data() << std::endl;
+    return QXmlDefaultHandler::fatalError(exception);
+}
+
+#define READ_MANDATORY(TYPE, NAME, CONVERSION)		      \
+    TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \
+    if (!ok) { \
+	std::cerr << "WARNING: ModelReader-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << std::endl; \
+	return false; \
+    }
+
+bool ModelHandler::readModel(const QXmlAttributes &attributes)
+{
+    bool ok = false;
+
+    READ_MANDATORY(int, id, toInt);
+
+    QString name = attributes.value("name");
+
+	if (m_layer->getModelName() == "")
+	{
+		m_layer->setModelName(name);
+		m_layer->setModelId(id);
+	}
+
+    READ_MANDATORY(int, sampleRate, toInt);
+
+    QString type = attributes.value("type").trimmed();
+    bool mainModel = (attributes.value("mainModel").trimmed() == "true");
+    
+    if (type == "dense") 
+	{
+	
+		READ_MANDATORY(int, dimensions, toInt);
+			    
+		// Currently the only dense model we support here
+		// is the dense 3d model.  Dense time-value models
+		// are always file-backed waveform data, at this
+		// point, and they come in as the wavefile model
+		// type above.
+		
+		if (dimensions == 3) 
+		{
+	    
+			READ_MANDATORY(int, windowSize, toInt);
+			READ_MANDATORY(int, yBinCount, toInt);
+
+			//DenseThreeDimensionalModel *model =
+			//new DenseThreeDimensionalModel(sampleRate, windowSize, yBinCount);
+		    
+			EditableDenseThreeDimensionalModel *model =
+			new EditableDenseThreeDimensionalModel(sampleRate, windowSize, yBinCount);
+
+			float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
+			if (ok) model->setMinimumLevel(minimum);
+		    
+			float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
+			if (ok) model->setMaximumLevel(maximum);
+
+			m_model = model;
+			return true;
+
+		} else 
+		{
+			std::cerr << "WARNING: ModelReader-XML: Unexpected dense model dimension ("
+				  << dimensions << ")" << std::endl;
+		}
+    } else if (type == "sparse") 
+	{
+		READ_MANDATORY(int, dimensions, toInt);
+		  
+		if (dimensions == 1) 
+		{
+		    
+			READ_MANDATORY(int, resolution, toInt);
+			SparseOneDimensionalModel *model = new SparseOneDimensionalModel(sampleRate, resolution);
+			m_model = model;
+
+			return true;
+
+		} else if (dimensions == 2 || dimensions == 3) 
+		{	    
+			READ_MANDATORY(int, resolution, toInt);
+
+			float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
+			float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
+			float valueQuantization = attributes.value("valueQuantization").trimmed().toFloat(&ok);
+
+			bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
+
+            QString units = attributes.value("units");
+
+		    if (dimensions == 2) 
+			{
+				if (attributes.value("subtype") == "text") 
+				{
+					TextModel *model = new TextModel(sampleRate, resolution, notifyOnAdd);
+					m_model = model;
+				} else 
+				{
+					SparseTimeValueModel *model = new SparseTimeValueModel(sampleRate, resolution, minimum, maximum, notifyOnAdd);
+					model->setScaleUnits(units);
+					m_model = model;
+				}
+			} else 
+			{
+				NoteModel *model = new NoteModel(sampleRate, resolution, minimum, maximum, notifyOnAdd);
+				model->setValueQuantization(valueQuantization);
+				model->setScaleUnits(units);
+				m_model = model;
+		    }
+			return true;
+
+		} else 
+		{
+			std::cerr << "WARNING: ModelReader-XML: Unexpected sparse model dimension ("
+				  << dimensions << ")" << std::endl;
+		}
+    } else if (type == "interval") 
+	{
+		READ_MANDATORY(int, dimensions, toInt);
+		READ_MANDATORY(int, resolution, toInt);
+		bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
+		
+		IntervalModel * model = new IntervalModel(sampleRate, resolution, notifyOnAdd);
+		m_model = model;
+		return true;
+
+	} else
+	{
+		std::cerr << "WARNING: ModelReader-XML: Unexpected model type \""
+			  << type.toLocal8Bit().data() << "\" for model id" << id << std::endl;
+	} 
+
+    return false;
+}
+
+bool ModelHandler::readDatasetStart(const QXmlAttributes &attributes)
+{
+    bool ok = false;
+
+    READ_MANDATORY(int, id, toInt);
+    READ_MANDATORY(int, dimensions, toInt);
+    
+    Model *model = m_model;
+
+    bool good = false;
+
+    switch (dimensions) {
+		case 1:
+			if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true;
+			break;
+
+		case 2:
+			if (dynamic_cast<SparseTimeValueModel *>(model)) good = true;
+			else if (dynamic_cast<TextModel *>(model)) good = true;
+			break;
+
+		case 3:
+			if (dynamic_cast<NoteModel *>(model)) good = true;
+			else if (dynamic_cast<DenseThreeDimensionalModel *>(model)) {
+				m_datasetSeparator = attributes.value("separator");
+				good = true;
+			}
+			else if (dynamic_cast<IntervalModel *>(model)) good = true;
+			break;
+
+		default:
+			break;
+    }
+
+    if (!good) {
+		std::cerr << "WARNING: ModelReader-XML: Model id " << /*modelId <<*/ " has wrong number of dimensions for " << dimensions << "-D dataset " << id << std::endl;
+		m_model = 0;
+		return false;
+    }
+
+    return true;
+}
+
+bool ModelHandler::addPointToDataset(const QXmlAttributes &attributes)
+{
+    bool ok = false;
+
+    READ_MANDATORY(int, frame, toInt);
+
+    SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>	(m_model);
+
+    if (sodm) 
+	{
+		QString label = attributes.value("label");
+		sodm->addPoint(SparseOneDimensionalModel::Point(frame, label));
+		return true;
+    }
+
+    SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *> (m_model);
+
+    if (stvm) 
+	{
+		float value = 0.0;
+		value = attributes.value("value").trimmed().toFloat(&ok);
+		QString label = attributes.value("label");
+		stvm->addPoint(SparseTimeValueModel::Point(frame, value, label));
+		return ok;
+    }
+	
+    NoteModel *nm = dynamic_cast<NoteModel *>(m_model);
+
+    if (nm) 
+	{
+		float value = 0.0;
+		value = attributes.value("value").trimmed().toFloat(&ok);
+		float duration = 0.0;
+		duration = attributes.value("duration").trimmed().toFloat(&ok);
+		QString label = attributes.value("label");
+		nm->addPoint(NoteModel::Point(frame, value, duration, label));
+		return ok;
+    }
+
+    TextModel *tm = dynamic_cast<TextModel *>(m_model);
+
+    if (tm) 
+	{
+		float height = 0.0;
+		height = attributes.value("height").trimmed().toFloat(&ok);
+		QString label = attributes.value("label");
+		tm->addPoint(TextModel::Point(frame, height, label));
+		return ok;
+    }
+
+	std::cerr << "WARNING: ModelReader-XML: Point element found in non-point dataset" << std::endl;
+
+    return false;
+}
+
+bool ModelHandler::addBinToDataset(const QXmlAttributes &attributes)
+{
+    //DenseThreeDimensionalModel *dtdm = dynamic_cast<DenseThreeDimensionalModel *> (m_model);
+	EditableDenseThreeDimensionalModel *dtdm = dynamic_cast<EditableDenseThreeDimensionalModel *>(m_model);
+
+    if (dtdm) {
+
+	bool ok = false;
+	int n = attributes.value("number").trimmed().toInt(&ok);
+	if (!ok) {
+	    std::cerr << "WARNING: ModelReader-XML: Missing or invalid bin number"
+		      << std::endl;
+	    return false;
+	}
+
+	QString name = attributes.value("name");
+
+	dtdm->setBinName(n, name);
+	return true;
+    }
+
+    std::cerr << "WARNING: ModelReader-XML: Bin definition found in incompatible dataset" << std::endl;
+
+    return false;
+}
+
+
+bool ModelHandler::addRowToDataset(const QXmlAttributes &attributes)
+{
+    m_inRow = false;
+
+    bool ok = false;
+    m_rowNumber = attributes.value("n").trimmed().toInt(&ok);
+    if (!ok) {
+		std::cerr << "WARNING: ModelReader-XML: Missing or invalid row number"
+			  << std::endl;
+		return false;
+    }
+    
+    m_inRow = true;
+    
+    return true;
+}
+
+bool ModelHandler::addIntervalToDataset(const QXmlAttributes &attributes)
+{
+    bool ok = false;
+
+    IntervalModel *im = dynamic_cast<IntervalModel*> (m_model);
+	if (im)
+	{
+		READ_MANDATORY(int, start, toInt);
+		READ_MANDATORY(int, end, toInt);
+		QString label = attributes.value("label");
+		float value = 0.0;
+		value = attributes.value("value").trimmed().toFloat(&ok);
+		im->addInterval(start, end, label, value);
+		ok = true;
+	}
+	return ok;
+}
+
+bool ModelHandler::readRowData(const QString &text)
+{
+	EditableDenseThreeDimensionalModel *dtdm = dynamic_cast<EditableDenseThreeDimensionalModel *>(m_model);
+
+    bool warned = false;
+
+    if (dtdm) {
+	QStringList data = text.split(m_datasetSeparator);
+
+	DenseThreeDimensionalModel::Column values;
+
+	for (QStringList::iterator i = data.begin(); i != data.end(); ++i) {
+
+	    if (values.size() == dtdm->getHeight()) {
+		if (!warned) {
+		    std::cerr << "WARNING: ModelReader-XML: Too many y-bins in 3-D dataset row "
+			      << m_rowNumber << std::endl;
+		    warned = true;
+		}
+	    }
+
+	    bool ok;
+	    float value = i->toFloat(&ok);
+	    if (!ok) {
+		std::cerr << "WARNING: ModelReader-XML: Bad floating-point value "
+			  << i->toLocal8Bit().data()
+			  << " in row data" << std::endl;
+	    } else {
+		values.push_back(value);
+	    }
+	}
+
+	dtdm->setColumn(m_rowNumber, values);
+	return true;
+    }
+
+    std::cerr << "WARNING: ModelReader-XML: Row data found in non-row dataset" << std::endl;
+
+    return false;
+}
+
+bool ModelHandler::readLayer(const QXmlAttributes &attributes)
+{
+	QString type = attributes.value("type");
+
+	m_layer = m_document->createLayer(LayerFactory::getInstance()->getLayerTypeForName(type));
+
+	if (!m_layer) {
+		std::cerr << "WARNING: modelreader-XML: Failed to add layer of type \""
+			  << type.toLocal8Bit().data()
+			  << "\"" << std::endl;
+		return false;
+    }
+
+	QString name = attributes.value("name");
+	m_layer->setObjectName(name);
+
+	return true;
+}
\ No newline at end of file