view data/fileio/ModelReader.cpp @ 240:e006f4a57f86

add labels in plotter widget fix some bugs in the graphical equalizer
author benoitrigolleau
date Tue, 11 Mar 2008 13:53:59 +0000
parents 4eb9c7e4acf6
children 2ea04b3f9141
line wrap: on
line source
/* -*- 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);

			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;
			m_model->setObjectName(m_modelName);
			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;
			m_model->setObjectName(m_modelName);
			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;
		    }
			m_model->setObjectName(m_modelName);
			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;
		m_model->setObjectName(m_modelName);
		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<EditableDenseThreeDimensionalModel *>(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)
{
    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_modelName = name;
	m_layer->setObjectName(name);

	return true;
}