view sv/document/ESFileReader.cpp @ 19:2a6f70f97395

add - EasaierSessionManager - Easaier menus - Interval model
author lbajardsilogic
date Mon, 14 May 2007 13:13:59 +0000
parents
children 74d1b3bda5a3
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 <QString>
#include <QMessageBox>
#include <QFileDialog>
#include <QUrl>

#include <iostream>

#include "ESFileReader.h"

#include "layer/Layer.h"
#include "view/View.h"
#include "base/PlayParameters.h"
#include "base/PlayParameterRepository.h"
#include "base/TempDirectory.h"
#include "data/fileio/AudioFileReaderFactory.h"
#include "data/model/WaveFileModel.h"
#include "data/model/DenseThreeDimensionalModel.h"
#include "data/model/SparseOneDimensionalModel.h"
#include "data/model/SparseTimeValueModel.h"
#include "data/model/NoteModel.h"
#include "data/model/TextModel.h"
#include "view/Pane.h"
#include "document/Document.h"


ESFileReader::ESFileReader(Document *document,
			   ESFileReaderPaneCallback &callback) : QXmlDefaultHandler(),
    m_document(document),
    m_paneCallback(callback),
    m_currentPane(0),
    m_inView(false),
    m_inData(false),
    m_ok(false)
{}

void
ESFileReader::parse(const QString &xmlData)
{
    QXmlInputSource inputSource;
    inputSource.setData(xmlData);
    parse(inputSource);
}

void
ESFileReader::parse(QXmlInputSource &inputSource)
{
    QXmlSimpleReader reader;
    reader.setContentHandler(this);
    reader.setErrorHandler(this);
    m_ok = reader.parse(inputSource);
}    

bool
ESFileReader::isOK()
{
    return m_ok;
}
	
ESFileReader::~ESFileReader()
{}

bool
ESFileReader::startElement(const QString &, const QString &,
			   const QString &qName,
			   const QXmlAttributes &attributes)
{
    QString name = qName.toLower();

    bool ok = false;

    // Valid element names:
    //
    // easaiersession
    // data
	// easaierresources
	// audio
    // display
	// window
	// view
	// layer

    if (name == "easaiersession") {
		// nothing needed
		ok = true;

    } else if (name == "data") {
		// nothing needed
		m_inData = true;
		ok = true;

    } else if (name == "easaierresources") {
		// nothing needed
		ok = true;

    } else if (name == "audio") {
		QString filename = attributes.value("value");
		m_document->setAudioSourceInfoFileName(filename);

    } else if (name == "display") {
		// nothing needed
		ok = true;

    } else if (name == "window") {
		ok = readWindow(attributes);

    } else if (name == "view") {
		m_inView = true;
		ok = readView(attributes);

    } else if (name == "layer") {
        ok = readLayer(attributes);

    } 

    if (!ok) {
	std::cerr << "WARNING: Easaier Session-XML: Failed to completely process element \""
		  << name.toLocal8Bit().data() << "\"" << std::endl;
    }

    return true;
}

bool
ESFileReader::characters(const QString &text)
{
    return true;
}

bool
ESFileReader::endElement(const QString &, const QString &,
			 const QString &qName)
{
    QString name = qName.toLower();

    if (name == "data") {

        m_inData = false;

    } else if (name == "view") {
		m_inView = false;
    } 

    return true;
}

bool
ESFileReader::error(const QXmlParseException &exception)
{
    m_errorString =
	QString("ERROR: Easaier Session-XML: %1 at line %2, column %3")
	.arg(exception.message())
	.arg(exception.lineNumber())
	.arg(exception.columnNumber());
    std::cerr << m_errorString.toLocal8Bit().data() << std::endl;
    return QXmlDefaultHandler::error(exception);
}

bool
ESFileReader::fatalError(const QXmlParseException &exception)
{
    m_errorString =
	QString("FATAL ERROR: Easaier Session-XML: %1 at line %2, column %3")
	.arg(exception.message())
	.arg(exception.lineNumber())
	.arg(exception.columnNumber());
    std::cerr << m_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: Easaier Session-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << std::endl; \
	return false; \
    }

bool
ESFileReader::readWindow(const QXmlAttributes &attributes)
{
    bool ok = false;

    READ_MANDATORY(int, width, toInt);
    READ_MANDATORY(int, height, toInt);

    m_paneCallback.setWindowSize(width, height);
    return true;
}

bool
ESFileReader::readView(const QXmlAttributes &attributes)
{
    QString type = attributes.value("type");
    m_currentPane = 0;
    
    if (type != "pane") {
	std::cerr << "WARNING: Easaier session-XML: Unexpected view type \""
		  << type.toLocal8Bit().data() << "\"" << std::endl;
	return false;
    }

	m_currentPane = m_paneCallback.addPane();

    if (!m_currentPane) {
	std::cerr << "WARNING: Easaier session-XML: Internal error: Failed to add pane!"
		  << std::endl;
	return false;
    }

    bool ok = false;

    View *view = m_currentPane;

    // The view properties first

    READ_MANDATORY(size_t, centre, toUInt);
    READ_MANDATORY(size_t, zoom, toUInt);
    READ_MANDATORY(int, followPan, toInt);
    READ_MANDATORY(int, followZoom, toInt);
    QString tracking = attributes.value("tracking");

    // Specify the follow modes before we set the actual values
    view->setFollowGlobalPan(followPan);
    view->setFollowGlobalZoom(followZoom);
	view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
			    tracking == "page" ? PlaybackScrollPage
			    : PlaybackIgnore);

    // Then set these values
    view->setCentreFrame(centre);
    view->setZoomLevel(zoom);

    // And pane properties
    READ_MANDATORY(int, centreLineVisible, toInt);
    m_currentPane->setCentreLineVisible(centreLineVisible);

    int height = attributes.value("height").toInt(&ok);
    if (ok) {
	m_currentPane->resize(m_currentPane->width(), height);
    }

    return true;
}

bool
ESFileReader::readLayer(const QXmlAttributes &attributes)
{
    QString type = attributes.value("type");

    int id;
    bool ok = false;
    id = attributes.value("id").trimmed().toInt(&ok);

    if (!ok) {
	std::cerr << "WARNING: Easaier session-XML: No layer id for layer of type \""
		  << type.toLocal8Bit().data()
		  << "\"" << std::endl;
	return false;
    }

    Layer *layer = 0;
    bool isNewLayer = false;

    // Layers are expected to be defined in layer elements in the data
    // section, and referred to in layer elements in the view
    // sections.  So if we're in the data section, we expect this
    // layer not to exist already; if we're in the view section, we
    // expect it to exist.

    if (m_inData) {

	if (m_layers.find(id) != m_layers.end()) {
	    std::cerr << "WARNING: Easaier session-XML: Ignoring duplicate layer id " << id
		      << " in data section" << std::endl;
	    return false;
	}

	layer = m_layers[id] = m_document->createLayer
	    (LayerFactory::getInstance()->getLayerTypeForName(type));

	if (layer) {
	    m_layers[id] = layer;
	    isNewLayer = true;
	}

    } else {

	if (!m_currentPane) {
	    std::cerr << "WARNING: Easaier session-XML: No current pane for layer " << id
		      << " in view section" << std::endl;
	    return false;
	}

	if (m_layers.find(id) != m_layers.end()) {
	    
	    layer = m_layers[id];
	
	} else {
	   layer = m_document->createLayer(LayerFactory::getInstance()->getLayerTypeForName(type));

	    if (layer) {
		m_layers[id] = layer;
		isNewLayer = true;
	    }
	}
    }
	    
    if (!layer) {
	std::cerr << "WARNING: Easaier session-XML: Failed to add layer of type \""
		  << type.toLocal8Bit().data()
		  << "\"" << std::endl;
	return false;
    }

    if (isNewLayer) {

		QString name = attributes.value("name");
		layer->setObjectName(name);

		QString modelName = attributes.value("model");
		int modelId = attributes.value("modelId").toInt();

		layer->setModelName(modelName);
		layer->setModelId(modelId);

		layer->setProperties(attributes);
    }

    if (!m_inData && m_currentPane) {
		m_document->addLayerToView(m_currentPane, layer);
    }

    return true;
}