totally new collada exporter (WARNING: it has some known bugs!)

This commit is contained in:
granzuglia 2008-01-30 08:33:32 +00:00
parent 72feef8f72
commit 2e24725d5b
5 changed files with 2034 additions and 0 deletions

1001
wrap/dae/colladaformat.h Normal file

File diff suppressed because it is too large Load Diff

254
wrap/dae/meshaccessors.h Normal file
View File

@ -0,0 +1,254 @@
#ifndef _MESH_ACCESSORS_H
#define _MESH_ACCESSORS_H
template<typename POINTTYPE>
struct CoordNumber
{
public:
static unsigned int coord()
{
return 0;
}
};
template<>
struct CoordNumber<vcg::Point2f>
{
public:
static unsigned int coord()
{
return 2;
}
};
template<>
struct CoordNumber<vcg::Point3f>
{
public:
static unsigned int coord()
{
return 3;
}
};
template<>
struct CoordNumber<vcg::Point4f>
{
public:
static unsigned int coord()
{
return 4;
}
};
namespace MeshAccessors
{
template<typename MESHTYPE>
class VertexAccessor
{
public:
typedef typename MESHTYPE::ConstVertexIterator ConstIterator;
typedef typename MESHTYPE::VertexIterator Iterator;
VertexAccessor(MESHTYPE& m)
:_m(m)
{
}
ConstIterator begin() const
{
return _m.vert.begin();
}
ConstIterator end() const
{
return _m.vert.end();
}
Iterator begin()
{
return _m.vert.begin();
}
Iterator end()
{
return _m.vert.end();
}
MESHTYPE& _m;
};
template<typename MESHTYPE>
class VertexPositionAccessor : public VertexAccessor<MESHTYPE>
{
public:
VertexPositionAccessor(MESHTYPE& m)
:VertexAccessor<MESHTYPE>(m)
{
}
template<typename VERTEXTYPE>
typename const VERTEXTYPE::CoordType operator()(VERTEXTYPE& v) const
{
return v.P();
}
};
template<typename MESHTYPE>
class VertexNormalAccessor : public VertexAccessor<MESHTYPE>
{
public:
VertexNormalAccessor(MESHTYPE& m)
:VertexAccessor<MESHTYPE>(m)
{
}
template<typename VERTEXTYPE>
typename const VERTEXTYPE::NormalType operator()(VERTEXTYPE& v) const
{
return v.N();
}
};
template<typename MESHTYPE>
class VertexTextureCoordinateAccessor : public VertexAccessor<MESHTYPE>
{
public:
VertexTextureCoordinateAccessor(MESHTYPE& m)
:VertexAccessor<MESHTYPE>(m)
{
}
template<typename VERTEXTYPE>
typename const VERTEXTYPE::TexCoordType operator()(VERTEXTYPE& v) const
{
return v.T();
}
};
template<typename MESHTYPE>
class PolygonAccessor
{
public:
typedef typename MESHTYPE::ConstFaceIterator ConstIterator;
typedef typename MESHTYPE::FaceIterator Iterator;
PolygonAccessor(MESHTYPE& m)
:_m(m)
{
}
ConstIterator begin() const
{
return _m.face.begin();
}
ConstIterator end() const
{
return _m.face.end();
}
Iterator begin()
{
return _m.face.begin();
}
Iterator end()
{
return _m.face.end();
}
MESHTYPE& _m;
};
template<typename MESHTYPE>
class PolygonPositionAccessor : public PolygonAccessor<MESHTYPE>
{
public:
PolygonPositionAccessor<MESHTYPE>(MESHTYPE& m)
:PolygonAccessor(m)
{
}
template<typename POLYGONTYPE>
typename const POLYGONTYPE::CoordType operator()(POLYGONTYPE& p,const unsigned int index) const
{
return p.V(i)->P();
}
};
template<typename MESHTYPE>
class PolygonNormalAccessor : public PolygonAccessor<MESHTYPE>
{
public:
PolygonNormalAccessor(MESHTYPE& m)
:PolygonAccessor<MESHTYPE>(m)
{
}
template<typename POLYGONTYPE>
typename const POLYGONTYPE::NormalType operator()(const POLYGONTYPE& p) const
{
POLYGONTYPE::NormalType r = p.cN();
return r.Normalize();
}
};
template<typename MESHTYPE>
class PolygonWedgeTextureCoordinateAccessor : public PolygonAccessor<MESHTYPE>
{
public:
template<typename POLYGONTYPE>
typename const POLYGONTYPE::TexCoordType operator()(POLYGONTYPE& p,const unsigned int index) const
{
return p.cWT(index);
}
PolygonWedgeTextureCoordinateAccessor(MESHTYPE& m)
:PolygonAccessor<MESHTYPE>(m)
{
}
};
} //MeshAccessors
template<typename MESHTYPE,typename ACCESSOR>
struct AccessorInfo
{
AccessorInfo(const MESHTYPE& m)
:_a(m)
{
}
ACCESSOR _a;
};
template<typename MESHTYPE,typename ACCESSOR>
struct AccessorComponentNumberInfo : public AccessorInfo<MESHTYPE,ACCESSOR>
{
AccessorComponentNumberInfo(const MESHTYPE& m)
:AccessorInfo(m)
{
}
unsigned int _return_value_component_number;
};
template<typename MESHTYPE,typename ACCESSOR>
struct AccessorPolygonEdgeNumberInfo : public AccessorInfo<MESHTYPE,ACCESSOR>
{
AccessorPolygonEdgeNumberInfo(const MESHTYPE& m)
:AccessorInfo(m)
{
}
unsigned int _edge_number;
};
#endif

530
wrap/dae/util_dae.h Normal file
View File

@ -0,0 +1,530 @@
#ifndef __VCGLIB_UTILDAE
#define __VCGLIB_UTILDAE
#include <wrap/io_trimesh/additionalinfo.h>
#include <vcg/complex/trimesh/update/normal.h>
#include <vcg/complex/trimesh/allocate.h>
#include <wrap/io_trimesh/io_mask.h>
#include<QtXml/QDomDocument>
#include<QtCore/QFile>
#include <QtXml/QXmlStreamWriter>
#include <QtCore/QStringList>
#include<vcg/space/point3.h>
#include<vcg/space/texcoord2.h>
#include<vcg/space/color4.h>
#include<vcg/space/texcoord2.h>
#include <wrap/callback.h>
#include <vector>
#include <vcg/simplex/vertex/with/vn.h>
#include <vcg/simplex/edge/edge.h>
#include <wrap/gl/glu_tesselator.h>
namespace vcg {
namespace tri {
namespace io {
class InfoDAE
{
public:
InfoDAE()
{
doc = NULL;
}
~InfoDAE()
{
delete doc;
}
QDomDocument* doc;
};
class AdditionalInfoDAE : public AdditionalInfo
{
public:
vcg::tri::io::InfoDAE* dae;
std::vector<QString> texturefile;
AdditionalInfoDAE()
:AdditionalInfo()
{
mask = 0;
numvert = 0;
numface = 0;
}
~AdditionalInfoDAE()
{
delete dae;
texturefile.clear();
}
};
class UtilDAE
{
public:
enum DAEError
{
E_NOERROR, // 0
E_CANTOPEN, // 1
E_NOGEOMETRYLIBRARY, // 2
E_NOMESH, // 3
E_NOVERTEXPOSITION, // 4
E_NO3DVERTEXPOSITION, // 5
E_NO3DSCENE, // 6
E_INCOMPATIBLECOLLADA141FORMAT, //7
E_UNREFERENCEBLEDCOLLADAATTRIBUTE, // 8
E_NOPOLYGONALMESH, //9
E_CANTSAVE //10
};
template<typename VERTEX_TYPE>
class MyPolygon
{
public:
typedef VERTEX_TYPE BaseVertexType;
int _nvert;
std::vector<VERTEX_TYPE*> _pv;
std::vector< vcg::TexCoord2<float> > _txc;
MyPolygon(int n)
:_nvert(n),_pv(_nvert),_txc(_nvert)
{
}
};
template<typename POLYGONAL_TYPE>
class PolygonalMesh
{
public:
typedef POLYGONAL_TYPE FaceType;
enum PERWEDGEATTRIBUTETYPE {NONE = 0,NORMAL = 1,MULTITEXTURECOORD = 2,MULTICOLOR = 4};
typedef typename FaceType::BaseVertexType VertexType;
typedef VertexType* VertexPointer;
typedef typename std::vector<VertexType>::iterator VertexIterator;
typedef typename std::vector<FaceType>::iterator PolygonIterator;
vcg::Box3<float> bbox;
std::vector<VertexType> vert;
std::vector<FaceType> _pols;
void generatePointsVector(std::vector<std::vector<vcg::Point3f> >& v)
{
for(typename PolygonalMesh::PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
{
v.push_back(std::vector<vcg::Point3f>());
for(typename std::vector<VertexPointer>::iterator itv = itp->_pv.begin();itv != itp->_pv.end();++itv)
{
v[v.size() - 1].push_back((*itv)->P());
}
}
}
void usePerWedgeAttributes(PERWEDGEATTRIBUTETYPE att,const unsigned int multitexture = 1,const unsigned int multicolor = 1)
{
if (att != NONE)
{
for(PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
{
if (att & MULTICOLOR) itp->usePerWedgeColor(multicolor);
if (att & MULTITEXTURECOORD) itp->usePerWedgeMultiTexture(multitexture);
if (att & NORMAL) itp->usePerWedgeNormal();
}
}
}
template<class TRIMESH>
void triangulate(TRIMESH& mesh)
{
std::vector<std::vector<vcg::Point3f> > pl;
mesh.vert.resize(vert.size());
int multicoor = 0;
//PolygonalMesh's points has been copied in TriangularMesh
for(size_t jj = 0;jj < mesh.vert.size();++jj)
mesh.vert[jj].P() = vert[jj].P();
bool texen = mesh.face.IsWedgeTexEnabled();
unsigned int totaltri = 0;
for(size_t ii = 0;ii < _pols.size();++ii)
totaltri += _pols[ii]._nvert - 2;
mesh.face.resize(totaltri);
//transform the polygonal mesh in a vector<vector<Point>>
generatePointsVector(pl);
int trioff = 0;
//foreach Polygon
for(size_t ii = 0;ii < pl.size();++ii)
{
std::vector<int> tx;
std::vector<std::vector<vcg::Point3f> > pl2(1);
pl2[0] = pl[ii];
vcg::glu_tesselator::tesselate(pl2,tx);
size_t ntri = tx.size() / 3;
assert(tx.size() % 3 == 0);
int polvert = 0;
//foreach triangle
for(size_t tr = 0;tr < ntri;++tr)
{
//typename TRIMESH::FaceType& f = mesh.face[tr];
//typename TRIMESH::FaceType& f = mesh.face[tr];
for(unsigned int tt = 0;tt < 3; ++tt)
{
mesh.face[trioff + tr].V(tt) = &(mesh.vert[_pols[ii]._pv[tx[3 * tr + tt]] - &(vert[0])]);
//vcg::Point3f ppp = mesh.face[tr].V(tt)->P();
if (texen)
{
/* f.WT(multicoor).U() = _pols[ii]._txc[polvert].U();
f.WT(multicoor).V() = _pols[ii]._txc[polvert].V();
f.WT(multicoor).N() = _pols[ii]._txc[polvert].N();*/
}
polvert = (polvert + 1) % _pols[ii]._nvert;
}
//mesh.face.push_back(f);
}
trioff += ntri;
}
assert(trioff == totaltri);
}
};
static const char *ErrorMsg(int error)
{
static const char * dae_error_msg[] =
{
"No errors",
"Can't open file",
"File without a geometry library",
"There isn't mesh in file",
"The meshes in file haven't the vertex position attribute",
"The importer assumes that the OpenMeshType uses a 3D point for the vertex position",
"There isn't any scene in Collada file",
"The input file is not compatible with COLLADA 1.41 standard format",
"Collada file is trying to referece an attribute that is not in the file",
"This version of Collada Importer support only triangular and polygonal mesh file"
};
if(error>9 || error<0) return "Unknown error";
else return dae_error_msg[error];
};
protected:
inline static void referenceToANodeAttribute(const QDomNode n,const QString& attr,QString& url_st)
{
url_st = n.toElement().attribute(attr);
int sz = url_st.size() - 1;
url_st = url_st.right(sz);
assert(url_st.size() != 0);
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomNodeList& ndl,const QString& attrname,const QString& attrvalue)
{
int ndl_size = ndl.size();
assert(ndl_size != 0);
int ind = 0;
while(ind < ndl_size)
{
QString st = ndl.at(ind).toElement().attribute(attrname);
if (st == attrvalue)
return ndl.at(ind);
++ind;
}
return QDomNode();
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomNode n,const QString& tag,const QString& attrname,const QString& attrvalue)
{
return findNodeBySpecificAttributeValue(n.toElement().elementsByTagName(tag),attrname,attrvalue);
}
inline static QDomNode findNodeBySpecificAttributeValue(const QDomDocument n,const QString& tag,const QString& attrname,const QString& attrvalue)
{
return findNodeBySpecificAttributeValue(n.elementsByTagName(tag),attrname,attrvalue);
}
inline static bool isThereTag(const QDomNodeList& list)
{
return ((list.size() > 0) ? true : false);
}
inline static bool isThereTag(const QDomNode n,const QString& tagname)
{
return isThereTag(n.toElement().elementsByTagName(tagname));
}
inline static bool isThereTag(const QDomDocument n,const QString& tagname)
{
return isThereTag(n.elementsByTagName(tagname));
}
inline static QDomNode attributeSourcePerSimplex(const QDomNode n,const QDomDocument startpoint,const QString& sem)
{
QDomNodeList vertattr = n.toElement().elementsByTagName("input");
for(int ind = 0;ind < vertattr.size();++ind)
{
if (vertattr.at(ind).toElement().attribute("semantic") == sem)
{
QString url;
referenceToANodeAttribute(vertattr.at(ind),"source",url);
return findNodeBySpecificAttributeValue(startpoint,"source","id",url);
}
}
return QDomNode();
}
inline static void valueStringList(QStringList& res,const QDomNode srcnode,const QString& tag)
{
QDomNodeList list = srcnode.toElement().elementsByTagName(tag);
assert(list.size() == 1);
QString nd = list.at(0).firstChild().nodeValue();
res = nd.split(" ");
if (res.last() == "")
res.removeLast();
}
/*inline static bool removeChildNode(QDomNodeList*/
inline static bool removeChildNodeList(QDomNodeList& nodelst,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
{
for(int jj = 0;jj < nodelst.size();++jj)
{
removeChildNode(nodelst.at(jj),tag,attribname,attribvalue);
}
return true;
}
inline static bool removeChildNode(QDomNode node,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
{
QDomNodeList clst = node.childNodes();
for(int ii = 0;ii < clst.size();++ii)
{
QDomNode oldchild = node.childNodes().at(ii);
if (tag != "")
{
if ((attribname != "") && (attribvalue != ""))
{
if (clst.at(ii).toElement().attribute(attribname) == attribvalue)
node.removeChild(oldchild);
}
else
{
QString nm = clst.at(ii).nodeName();
if (clst.at(ii).nodeName() == tag)
{
node.removeChild(oldchild);
}
}
}
else node.removeChild(oldchild);
}
return true;
}
static void ParseRotationMatrix(vcg::Matrix44f& m,const std::vector<QDomNode>& t)
{
vcg::Matrix44f tmp;
tmp.SetIdentity();
for(unsigned int ii = 0;ii < t.size();++ii)
{
QString rt = t[ii].firstChild().nodeValue();
QStringList rtl = rt.split(" ");
if (rtl.last() == "") rtl.removeLast();
assert(rtl.size() == 4);
tmp.SetRotate(rtl.at(3).toFloat(),vcg::Point3f(rtl.at(0).toFloat(),rtl.at(1).toFloat(),rtl.at(2).toFloat()));
tmp *= tmp;
}
m = m * tmp;
}
static void AddTranslation(vcg::Matrix44f& m,const QDomNode t)
{
QDomNode tr = t.firstChild();
QString coord = tr.nodeValue();
QStringList coordlist = coord.split(" ");
if (coordlist.last() == "")
coordlist.removeLast();
assert(coordlist.size() == 3);
m[0][0] = 1.0f;
m[1][1] = 1.0f;
m[2][2] = 1.0f;
m[3][3] = 1.0f;
m[0][3] = coordlist.at(0).toFloat();
m[1][3] = coordlist.at(1).toFloat();
m[2][3] = coordlist.at(2).toFloat();
}
static void TransfMatrix(const QDomNode parentnode,const QDomNode presentnode,vcg::Matrix44f& m)
{
if (presentnode == parentnode) return;
else
{
QDomNode par = presentnode.parentNode();
std::vector<QDomNode> rotlist;
QDomNode trans;
for(int ch = 0;ch < par.childNodes().size();++ch)
{
if (par.childNodes().at(ch).nodeName() == "rotate")
rotlist.push_back(par.childNodes().at(ch));
else if (par.childNodes().at(ch).nodeName() == "translate")
{
trans = par.childNodes().at(ch);
}
}
vcg::Matrix44f tmp;
tmp.SetIdentity();
if (!trans.isNull()) AddTranslation(tmp,trans);
ParseRotationMatrix(tmp,rotlist);
m = m * tmp;
TransfMatrix(parentnode,par,m);
}
}
inline static int findOffSetForASingleSimplex(QDomNode node)
{
QDomNodeList wedatts = node.toElement().elementsByTagName("input");
int max = 0;
if (wedatts.size() == 0) return -1;
else
{
for(int ii = 0;ii < wedatts.size();++ii)
{
int tmp = wedatts.at(ii).toElement().attribute("offset").toInt();
if (tmp > max) max = tmp;
}
}
return max + 1;
}
inline static int findStringListAttribute(QStringList& list,const QDomNode node,const QDomNode poly,const QDomDocument startpoint,const char* token)
{
int offset;
if (!node.isNull())
{
offset = node.toElement().attribute("offset").toInt();
QDomNode st = attributeSourcePerSimplex(poly,startpoint,token);
valueStringList(list,st,"float_array");
}
return offset;
}
inline static QDomNode textureFinder(const QString& textname,const QDomDocument doc)
{
//visual_scene -> instance_material
QDomNodeList vis_scn = doc.elementsByTagName("library_visual_scenes");
if (vis_scn.size() != 1)
return QDomNode();
QDomNode symb = findNodeBySpecificAttributeValue(vis_scn.at(0),QString("instance_material"),QString("symbol"),textname);
if (symb.isNull())
return QDomNode();
QString tar = symb.toElement().attribute("target");
if (tar.isNull())
return QDomNode();
tar = tar.remove('#');
//library_material -> material -> instance_effect
QDomNodeList lib_mat = doc.elementsByTagName("library_materials");
if (lib_mat.size() != 1)
return QDomNode();
QDomNode material = findNodeBySpecificAttributeValue(lib_mat.at(0),QString("material"),QString("id"),tar);
if (material.isNull())
return QDomNode();
QDomNodeList in_eff = material.toElement().elementsByTagName("instance_effect");
if (vis_scn.size() == 0)
return QDomNode();
QString url = in_eff.at(0).toElement().attribute("url");
if ((url.isNull()) || (url == ""))
return QDomNode();
url = url.remove('#');
//library_effects -> effect -> instance_effect
QDomNodeList lib_eff = doc.elementsByTagName("library_effects");
if (lib_eff.size() != 1)
return QDomNode();
QDomNode effect = findNodeBySpecificAttributeValue(lib_eff.at(0),QString("effect"),QString("id"),url);
if (effect.isNull())
return QDomNode();
QDomNodeList init_from = effect.toElement().elementsByTagName("init_from");
if (init_from.size() == 0)
return QDomNode();
QString img_id = init_from.at(0).toElement().text();
if ((img_id.isNull()) || (img_id == ""))
return QDomNode();
//library_images -> image
QDomNodeList lib_img = doc.elementsByTagName("library_images");
if (lib_img.size() != 1)
return QDomNode();
QDomNode img = findNodeBySpecificAttributeValue(lib_img.at(0),QString("image"),QString("id"),img_id);
if (img.isNull())
return QDomNode();
return img;
}
static int indexTextureByImgNode(const QDomDocument doc,const QDomNode node)
{
QDomNodeList libim = doc.elementsByTagName(QString("library_images"));
if (libim.size() != 1)
return -1;
QDomNodeList imgs = libim.at(0).toElement().elementsByTagName("image");
int ii = 0;
bool found = false;
while((ii < imgs.size()) && (!found))
{
if (imgs.at(ii) == node)
found = true;
else ++ii;
}
if (found)
return ii;
else
return -1;
}
struct WedgeAttribute
{
QDomNode wnsrc;
QStringList wn;
int offnm;
QDomNode wtsrc;
QStringList wt;
int stride;
int offtx;
QDomNode wcsrc;
QStringList wc;
int offcl;
};
};
}
}
}
#endif

View File

@ -0,0 +1,55 @@
#include <wrap/dae/xmldocumentmanaging.h>
#include <cassert>
XMLNode::XMLNode(XMLTag* tag)
:_tag(tag)
{
}
XMLNode::~XMLNode()
{
delete _tag;
}
XMLLeafNode::XMLLeafNode(XMLLeafTag* leaftag)
:XMLNode(leaftag)
{
}
XMLLeafNode::~XMLLeafNode()
{
}
void XMLLeafNode::applyProcedure(Visitor& v)
{
v(*this);
}
XMLInteriorNode::XMLInteriorNode(XMLTag* tag)
:XMLNode(tag)
{
}
XMLNode* XMLInteriorNode::son(int ii)
{
assert((ii > 0) && (ii < _sons.size()));
return _sons[ii];
}
QVector< XMLNode* > XMLInteriorNode::sons()
{
return _sons;
}
XMLInteriorNode::~XMLInteriorNode()
{
for(QVector< XMLNode* >::iterator it = _sons.begin();it != _sons.end();++it)
delete (*it);
}
void XMLInteriorNode::applyProcedure(Visitor& v)
{
v(*this);
}

View File

@ -0,0 +1,194 @@
#ifndef _XML_DOCUMENT_MANAGING_H
#define _XML_DOCUMENT_MANAGING_H
#include <vector>
#include <set>
#include <QtXml/QDomDocument>
#include<QtCore/QFile>
#include<QtCore/QVector>
#include <QtXml/QXmlStreamWriter>
#include <QtCore/QString>
class XMLTag
{
public:
typedef std::pair<QString,QString> TagAttribute;
typedef QVector<TagAttribute> TagAttributes;
QString _tagname;
TagAttributes _attributes;
XMLTag(const QString& tagname = QString(),const TagAttributes& attr = TagAttributes())
:_tagname(tagname),_attributes(attr)
{
}
virtual ~XMLTag()
{
}
};
class XMLLeafTag : public XMLTag
{
public:
QVector<QString> _text;
XMLLeafTag(const QString& tagname = QString(),const QVector<QString>& text = QVector<QString>())
:XMLTag(tagname),_text(text)
{
}
virtual ~XMLLeafTag()
{
}
};
class XMLDocumentWriter;
class Visitor;
class XMLNode
{
public:
XMLNode(XMLTag* tag);
virtual ~XMLNode();
virtual void applyProcedure(Visitor& v) = 0;
XMLTag* _tag;
};
class XMLInteriorNode : public XMLNode
{
public:
XMLInteriorNode(XMLTag* tag);
XMLNode* son(int ii);
QVector< XMLNode* > sons();
void applyProcedure(Visitor& v);
~XMLInteriorNode();
QVector< XMLNode* > _sons;
};
class XMLLeafNode : public XMLNode
{
public:
XMLLeafNode(XMLLeafTag* leaftag);
void applyProcedure(Visitor& v);
virtual ~XMLLeafNode();
};
class XMLDocument
{
public:
XMLDocument(XMLInteriorNode* root)
:_root(root)
{
}
~XMLDocument()
{
delete (_root);
}
XMLInteriorNode* _root;
};
class Visitor
{
public:
virtual void operator()(XMLLeafNode& leaf) = 0;
virtual void operator()(XMLInteriorNode& intnode) = 0;
};
class XMLDocumentWriter : public Visitor
{
private:
QXmlStreamWriter _stream;
QFile _file;
bool _error;
void writeText(XMLLeafNode& node)
{
XMLLeafTag* leaftag = static_cast<XMLLeafTag*>(node._tag);
for(QVector<QString>::iterator it = leaftag->_text.begin();it != leaftag->_text.end();++it)
{
QString tmp = "";
if (it != leaftag->_text.begin())
tmp = QString(" ");
_stream.writeCharacters(tmp + *it);
}
}
void writeAttributes(XMLNode& node)
{
QXmlStreamAttributes attr;
for(XMLTag::TagAttributes::iterator it = node._tag->_attributes.begin();it != node._tag->_attributes.end();++it)
attr.append(it->first,it->second);
_stream.writeAttributes(attr);
}
void recursiveStep(XMLInteriorNode& intnode)
{
QVector< XMLNode* > sons = intnode.sons();
for(QVector< XMLNode* >::iterator its = sons.begin();its != sons.end();++its)
(*its)->applyProcedure(*this);
}
public:
void operator()(XMLLeafNode& node)
{
_stream.writeStartElement(node._tag->_tagname);
writeAttributes(node);
writeText(node);
_stream.writeEndElement();
}
void operator()(XMLInteriorNode& intnode)
{
_stream.writeStartElement(intnode._tag->_tagname);
writeAttributes(intnode);
recursiveStep(intnode);
_stream.writeEndElement();
}
void operator()(XMLDocument& doc)
{
_stream.writeStartDocument();
operator()(*(doc._root));
_stream.writeEndDocument();
}
void write(XMLDocument& doc)
{
(*this)(doc);
}
bool isReliable() const
{
return !_error;
}
XMLDocumentWriter(const char* filename,const bool autoformatting = true)
:_stream(),_file(filename),_error(false)
{
if (!_file.open(QIODevice::WriteOnly | QIODevice::Text))
_error = true;
_stream.setDevice(&_file);
_stream.setAutoFormatting(autoformatting);
}
~XMLDocumentWriter()
{
_file.close();
}
};
#endif