<commit_before>/* libwpg
 * Copyright (C) 2006 <NAME> (<EMAIL>)
 * Copyright (C) 2006 <NAME> (<EMAIL>)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02111-1301 USA
 *
 * For further information visit http://libwpg.sourceforge.net
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#include "OdgExporter.hxx"
#include "DocumentElement.hxx"
#include "DocumentHandler.hxx"
#include <locale.h>
#include <string>

OdgExporter::OdgExporter(DocumentHandler *pHandler, const bool isFlatXML):
	mpHandler(pHandler),
	mxFillRule(AlternatingFill),
	miGradientIndex(1),
	miDashIndex(1), 
	miGraphicsStyleIndex(1),
	mfWidth(0.0f),
	mfHeight(0.0f),
	mbIsFlatXML(isFlatXML)
{
}

OdgExporter::~OdgExporter()
{

	for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); iterBody++)
	{
		delete (*iterBody);
		(*iterBody) = NULL;
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
		iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); iterGraphicsAutomaticStyles++)
	{
		delete((*iterGraphicsAutomaticStyles));
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
		iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); iterGraphicsStrokeDashStyles++)
	{
		delete((*iterGraphicsStrokeDashStyles));
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
		iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); iterGraphicsGradientStyles++)
	{
		delete((*iterGraphicsGradientStyles));
	}
}

void OdgExporter::startGraphics(double width, double height)
{
	miGradientIndex = 1;
	miDashIndex = 1;
	miGraphicsStyleIndex = 1;
	mfWidth = width;
	mfHeight = height;

	mpHandler->startDocument();
	TagOpenElement tmpOfficeDocumentContent("office:document");
	tmpOfficeDocumentContent.addAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
	tmpOfficeDocumentContent.addAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
	tmpOfficeDocumentContent.addAttribute("office:version", "1.0");
	if (mbIsFlatXML)
		tmpOfficeDocumentContent.addAttribute("office:mimetype", "application/vnd.oasis.opendocument.graphics");	
	tmpOfficeDocumentContent.write(mpHandler);
	
	TagOpenElement("office:settings").write(mpHandler);
	
	TagOpenElement configItemSetOpenElement("config:config-item-set");
	configItemSetOpenElement.addAttribute("config:name", "ooo:view-settings");
	configItemSetOpenElement.write(mpHandler);
	
	TagOpenElement configItemOpenElement("config:config-item");

	configItemOpenElement.addAttribute("config:name", "VisibleAreaTop");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	mpHandler->characters("0");
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaLeft");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	mpHandler->characters("0");
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaWidth");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	WPXString sWidth; sWidth.sprintf("%li", (unsigned long)(2540 * width));
	mpHandler->characters(sWidth);
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaHeight");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	WPXString sHeight; sHeight.sprintf("%li", (unsigned long)(2540 * height));
	mpHandler->characters(sHeight);
	mpHandler->endElement("config:config-item");
	
	mpHandler->endElement("config:config-item-set");
	
	mpHandler->endElement("office:settings");
}

void OdgExporter::endGraphics()
{
	TagOpenElement("office:styles").write(mpHandler);

	for (std::vector<DocumentElement *>::const_iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
		iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); iterGraphicsStrokeDashStyles++)
	{
		(*iterGraphicsStrokeDashStyles)->write(mpHandler);
	}

	for (std::vector<DocumentElement *>::const_iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
		iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); iterGraphicsGradientStyles++)
	{
		(*iterGraphicsGradientStyles)->write(mpHandler);
	}
	
	mpHandler->endElement("office:styles");
	
	TagOpenElement("office:automatic-styles").write(mpHandler);

	// writing out the graphics automatic styles
	for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
		iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); iterGraphicsAutomaticStyles++)
	{
		(*iterGraphicsAutomaticStyles)->write(mpHandler);
	}

	TagOpenElement tmpStylePageLayoutOpenElement("style:page-layout");
	tmpStylePageLayoutOpenElement.addAttribute("style:name", "PM0");
	tmpStylePageLayoutOpenElement.write(mpHandler);

	TagOpenElement tmpStylePageLayoutPropertiesOpenElement("style:page-layout-properties");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-top", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-bottom", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-left", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-right", "0in");
	WPXString sValue;
	sValue = doubleToString(mfWidth); sValue.append("in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-width", sValue);
	sValue = doubleToString(mfHeight); sValue.append("in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-height", sValue);
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("style:print-orientation", "portrait");
	tmpStylePageLayoutPropertiesOpenElement.write(mpHandler);

	mpHandler->endElement("style:page-layout-properties");

	mpHandler->endElement("style:page-layout");

	TagOpenElement tmpStyleStyleOpenElement("style:style");
	tmpStyleStyleOpenElement.addAttribute("style:name", "dp1");
	tmpStyleStyleOpenElement.addAttribute("style:family", "drawing-page");
	tmpStyleStyleOpenElement.write(mpHandler);

	TagOpenElement tmpStyleDrawingPagePropertiesOpenElement("style:drawing-page-properties");
	// tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:background-size", "border");
	tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:fill", "none");
	tmpStyleDrawingPagePropertiesOpenElement.write(mpHandler);

	mpHandler->endElement("style:drawing-page-properties");

	mpHandler->endElement("style:style");
	
	mpHandler->endElement("office:automatic-styles");


	TagOpenElement("office:master-styles").write(mpHandler);

	TagOpenElement tmpStyleMasterPageOpenElement("style:master-page");
	tmpStyleMasterPageOpenElement.addAttribute("style:name", "Default");
	tmpStyleMasterPageOpenElement.addAttribute("style:page-layout-name", "PM0");
	tmpStyleMasterPageOpenElement.addAttribute("draw:style-name", "dp1");
	tmpStyleMasterPageOpenElement.write(mpHandler);

	mpHandler->endElement("style:master-page");

	mpHandler->endElement("office:master-styles");

	TagOpenElement("office:body").write(mpHandler);

	TagOpenElement("office:drawing").write(mpHandler);

	TagOpenElement tmpDrawPageOpenElement("draw:page");
	tmpDrawPageOpenElement.addAttribute("draw:name", "page1");
	tmpDrawPageOpenElement.addAttribute("draw:style-name", "dp1");
	tmpDrawPageOpenElement.addAttribute("draw:master-page-name", "Default");
	tmpDrawPageOpenElement.write(mpHandler);

	for (std::vector<DocumentElement *>::const_iterator bodyIter = mBodyElements.begin();
		bodyIter != mBodyElements.end(); bodyIter++)
	{
		(*bodyIter)->write(mpHandler);
	}	

	mpHandler->endElement("draw:page");
	mpHandler->endElement("office:drawing");
	mpHandler->endElement("office:body");
	mpHandler->endElement("office:document");

	mpHandler->endDocument();
}

void OdgExporter::setPen(const libwpg::WPGPen& pen)
{
	mxPen = pen;
}

void OdgExporter::setBrush(const libwpg::WPGBrush& brush)
{
	mxBrush = brush;
}

void OdgExporter::setFillRule(FillRule rule)
{
	mxFillRule = rule;
}

void OdgExporter::startLayer(unsigned int /* id */)
{
}

void OdgExporter::endLayer(unsigned int)
{
}

void OdgExporter::drawRectangle(const libwpg::WPGRect& rect, double rx, double /* ry */)
{
	writeGraphicsStyle();
	TagOpenElement *pDrawRectElement = new TagOpenElement("draw:rect");
	WPXString sValue;
	sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
	pDrawRectElement->addAttribute("draw:style-name", sValue);
	sValue = doubleToString(rect.x1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:x", sValue);
	sValue = doubleToString(rect.y1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:y", sValue);
	sValue = doubleToString(rect.x2-rect.x1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:width", sValue);
	sValue = doubleToString(rect.y2-rect.y1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:height", sValue);
	sValue = doubleToString(rx); sValue.append("in");
	// FIXME: what to do when rx != ry ?
	pDrawRectElement->addAttribute("draw:corner-radius", sValue);
	mBodyElements.push_back(pDrawRectElement);
	mBodyElements.push_back(new TagCloseElement("draw:rect"));	
}

void OdgExporter::drawEllipse(const libwpg::WPGPoint& center, double rx, double ry, double rotation, const libwpg::WPGPoint& from, const libwpg::WPGPoint& to)
{
	writeGraphicsStyle();
	TagOpenElement *pDrawEllipseElement = new TagOpenElement("draw:ellipse");
	WPXString sValue;
	sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
	pDrawEllipseElement->addAttribute("draw:style-name", sValue);
	sValue = doubleToString(center.x-rx); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:x", sValue);
	sValue = doubleToString(center.y-ry); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:y", sValue);
	sValue = doubleToString(2 * rx); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:width", sValue);
	sValue = doubleToString(2 * ry); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:height", sValue);
#if 0
	if (rotation != 0.0)
	{
		sValue = "translate("; sValue.append(doubleToString(-center.x)); sValue.append("in, "); sValue.append(doubleToString(-center.y)); sValue.append("in) ");
		sValue.append("rotate("); sValue.append(doubleToString(-rotation)); sValue.append(") ");
		sValue.append("translate("); sValue.append(doubleToString(center.x)); sValue.append("in, "); sValue.append(doubleToString(center.y)); sValue.append("in) ");
		pDrawEllipseElement->addAttribute("svg:transform", sValue);
	}
#endif
	mBodyElements.push_back(pDrawEllipseElement);
	mBodyElements.push_back(new TagCloseElement("draw:ellipse"));
}

void OdgExporter::drawPolyline(const libwpg::WPGPointArray& vertices)
{
	drawPolySomething(vertices, false);
}<commit_msg>get the rotated ellipses right in OpenOffice.org<commit_after>/* libwpg
 * Copyright (C) 2006 <NAME> (<EMAIL>)
 * Copyright (C) 2006 <NAME> (<EMAIL>)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02111-1301 USA
 *
 * For further information visit http://libwpg.sourceforge.net
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#include "OdgExporter.hxx"
#include "DocumentElement.hxx"
#include "DocumentHandler.hxx"
#include <locale.h>
#include <math.h>
#include <string>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

OdgExporter::OdgExporter(DocumentHandler *pHandler, const bool isFlatXML):
	mpHandler(pHandler),
	mxFillRule(AlternatingFill),
	miGradientIndex(1),
	miDashIndex(1), 
	miGraphicsStyleIndex(1),
	mfWidth(0.0f),
	mfHeight(0.0f),
	mbIsFlatXML(isFlatXML)
{
}

OdgExporter::~OdgExporter()
{

	for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); iterBody++)
	{
		delete (*iterBody);
		(*iterBody) = NULL;
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
		iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); iterGraphicsAutomaticStyles++)
	{
		delete((*iterGraphicsAutomaticStyles));
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
		iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); iterGraphicsStrokeDashStyles++)
	{
		delete((*iterGraphicsStrokeDashStyles));
	}

	for (std::vector<DocumentElement *>::iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
		iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); iterGraphicsGradientStyles++)
	{
		delete((*iterGraphicsGradientStyles));
	}
}

void OdgExporter::startGraphics(double width, double height)
{
	miGradientIndex = 1;
	miDashIndex = 1;
	miGraphicsStyleIndex = 1;
	mfWidth = width;
	mfHeight = height;

	mpHandler->startDocument();
	TagOpenElement tmpOfficeDocumentContent("office:document");
	tmpOfficeDocumentContent.addAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
	tmpOfficeDocumentContent.addAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
	tmpOfficeDocumentContent.addAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
	tmpOfficeDocumentContent.addAttribute("office:version", "1.0");
	if (mbIsFlatXML)
		tmpOfficeDocumentContent.addAttribute("office:mimetype", "application/vnd.oasis.opendocument.graphics");	
	tmpOfficeDocumentContent.write(mpHandler);
	
	TagOpenElement("office:settings").write(mpHandler);
	
	TagOpenElement configItemSetOpenElement("config:config-item-set");
	configItemSetOpenElement.addAttribute("config:name", "ooo:view-settings");
	configItemSetOpenElement.write(mpHandler);
	
	TagOpenElement configItemOpenElement("config:config-item");

	configItemOpenElement.addAttribute("config:name", "VisibleAreaTop");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	mpHandler->characters("0");
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaLeft");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	mpHandler->characters("0");
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaWidth");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	WPXString sWidth; sWidth.sprintf("%li", (unsigned long)(2540 * width));
	mpHandler->characters(sWidth);
	mpHandler->endElement("config:config-item");
	
	configItemOpenElement.addAttribute("config:name", "VisibleAreaHeight");
	configItemOpenElement.addAttribute("config:type", "int");
	configItemOpenElement.write(mpHandler);
	WPXString sHeight; sHeight.sprintf("%li", (unsigned long)(2540 * height));
	mpHandler->characters(sHeight);
	mpHandler->endElement("config:config-item");
	
	mpHandler->endElement("config:config-item-set");
	
	mpHandler->endElement("office:settings");
}

void OdgExporter::endGraphics()
{
	TagOpenElement("office:styles").write(mpHandler);

	for (std::vector<DocumentElement *>::const_iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
		iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); iterGraphicsStrokeDashStyles++)
	{
		(*iterGraphicsStrokeDashStyles)->write(mpHandler);
	}

	for (std::vector<DocumentElement *>::const_iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
		iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); iterGraphicsGradientStyles++)
	{
		(*iterGraphicsGradientStyles)->write(mpHandler);
	}
	
	mpHandler->endElement("office:styles");
	
	TagOpenElement("office:automatic-styles").write(mpHandler);

	// writing out the graphics automatic styles
	for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
		iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); iterGraphicsAutomaticStyles++)
	{
		(*iterGraphicsAutomaticStyles)->write(mpHandler);
	}

	TagOpenElement tmpStylePageLayoutOpenElement("style:page-layout");
	tmpStylePageLayoutOpenElement.addAttribute("style:name", "PM0");
	tmpStylePageLayoutOpenElement.write(mpHandler);

	TagOpenElement tmpStylePageLayoutPropertiesOpenElement("style:page-layout-properties");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-top", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-bottom", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-left", "0in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-right", "0in");
	WPXString sValue;
	sValue = doubleToString(mfWidth); sValue.append("in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-width", sValue);
	sValue = doubleToString(mfHeight); sValue.append("in");
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-height", sValue);
	tmpStylePageLayoutPropertiesOpenElement.addAttribute("style:print-orientation", "portrait");
	tmpStylePageLayoutPropertiesOpenElement.write(mpHandler);

	mpHandler->endElement("style:page-layout-properties");

	mpHandler->endElement("style:page-layout");

	TagOpenElement tmpStyleStyleOpenElement("style:style");
	tmpStyleStyleOpenElement.addAttribute("style:name", "dp1");
	tmpStyleStyleOpenElement.addAttribute("style:family", "drawing-page");
	tmpStyleStyleOpenElement.write(mpHandler);

	TagOpenElement tmpStyleDrawingPagePropertiesOpenElement("style:drawing-page-properties");
	// tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:background-size", "border");
	tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:fill", "none");
	tmpStyleDrawingPagePropertiesOpenElement.write(mpHandler);

	mpHandler->endElement("style:drawing-page-properties");

	mpHandler->endElement("style:style");
	
	mpHandler->endElement("office:automatic-styles");


	TagOpenElement("office:master-styles").write(mpHandler);

	TagOpenElement tmpStyleMasterPageOpenElement("style:master-page");
	tmpStyleMasterPageOpenElement.addAttribute("style:name", "Default");
	tmpStyleMasterPageOpenElement.addAttribute("style:page-layout-name", "PM0");
	tmpStyleMasterPageOpenElement.addAttribute("draw:style-name", "dp1");
	tmpStyleMasterPageOpenElement.write(mpHandler);

	mpHandler->endElement("style:master-page");

	mpHandler->endElement("office:master-styles");

	TagOpenElement("office:body").write(mpHandler);

	TagOpenElement("office:drawing").write(mpHandler);

	TagOpenElement tmpDrawPageOpenElement("draw:page");
	tmpDrawPageOpenElement.addAttribute("draw:name", "page1");
	tmpDrawPageOpenElement.addAttribute("draw:style-name", "dp1");
	tmpDrawPageOpenElement.addAttribute("draw:master-page-name", "Default");
	tmpDrawPageOpenElement.write(mpHandler);

	for (std::vector<DocumentElement *>::const_iterator bodyIter = mBodyElements.begin();
		bodyIter != mBodyElements.end(); bodyIter++)
	{
		(*bodyIter)->write(mpHandler);
	}	

	mpHandler->endElement("draw:page");
	mpHandler->endElement("office:drawing");
	mpHandler->endElement("office:body");
	mpHandler->endElement("office:document");

	mpHandler->endDocument();
}

void OdgExporter::setPen(const libwpg::WPGPen& pen)
{
	mxPen = pen;
}

void OdgExporter::setBrush(const libwpg::WPGBrush& brush)
{
	mxBrush = brush;
}

void OdgExporter::setFillRule(FillRule rule)
{
	mxFillRule = rule;
}

void OdgExporter::startLayer(unsigned int /* id */)
{
}

void OdgExporter::endLayer(unsigned int)
{
}

void OdgExporter::drawRectangle(const libwpg::WPGRect& rect, double rx, double /* ry */)
{
	writeGraphicsStyle();
	TagOpenElement *pDrawRectElement = new TagOpenElement("draw:rect");
	WPXString sValue;
	sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
	pDrawRectElement->addAttribute("draw:style-name", sValue);
	sValue = doubleToString(rect.x1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:x", sValue);
	sValue = doubleToString(rect.y1); sValue.append("in");
	pDrawRectElement->addAttribute("svg:y", sValue);
	sValue = doubleToString(rect.width()); sValue.append("in");
	pDrawRectElement->addAttribute("svg:width", sValue);
	sValue = doubleToString(rect.height()); sValue.append("in");
	pDrawRectElement->addAttribute("svg:height", sValue);
	sValue = doubleToString(rx); sValue.append("in");
	// FIXME: what to do when rx != ry ?
	pDrawRectElement->addAttribute("draw:corner-radius", sValue);
	mBodyElements.push_back(pDrawRectElement);
	mBodyElements.push_back(new TagCloseElement("draw:rect"));	
}

void OdgExporter::drawEllipse(const libwpg::WPGPoint& center, double rx, double ry, double rotation, const libwpg::WPGPoint& from, const libwpg::WPGPoint& to)
{
	writeGraphicsStyle();
	TagOpenElement *pDrawEllipseElement = new TagOpenElement("draw:ellipse");
	WPXString sValue;
	sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
	pDrawEllipseElement->addAttribute("draw:style-name", sValue);
	sValue = doubleToString(2 * rx); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:width", sValue);
	sValue = doubleToString(2 * ry); sValue.append("in");
	pDrawEllipseElement->addAttribute("svg:height", sValue);
	if (rotation != 0.0)
	{
		while(rotation < -180)
			rotation += 360;
		while(rotation > 180)
			rotation -= 360;
		double radrotation = rotation*M_PI/180.0;
		double deltax = sqrt(pow(rx, 2.0) + pow(ry, 2.0))*cos(atan(ry/rx) - radrotation ) - rx;
		double deltay = sqrt(pow(rx, 2.0) + pow(ry, 2.0))*sin(atan(ry/rx) - radrotation ) - ry;
		sValue = "rotate("; sValue.append(doubleToString(radrotation)); sValue.append(") ");
		sValue.append("translate("); sValue.append(doubleToString(center.x - rx - deltax)); sValue.append("in, "); sValue.append(doubleToString(center.y - ry - deltay)); sValue.append("in)");
		pDrawEllipseElement->addAttribute("svg:transform", sValue);
	}
	else
	{
		sValue = doubleToString(center.x-rx); sValue.append("in");
		pDrawEllipseElement->addAttribute("svg:x", sValue);
		sValue = doubleToString(center.y-ry); sValue.append("in");
		pDrawEllipseElement->addAttribute("svg:y", sValue);
	}
	mBodyElements.push_back(pDrawEllipseElement);
	mBodyElements.push_back(new TagCloseElement("draw:ellipse"));
}

void OdgExporter::drawPolyline(const libwpg::WPGPointArray& vertices)
{
	drawPolySomething(vertices, false);
}
{'fraction_non_alphanumeric': 0.1423818765099608, 'fraction_numerical': 0.008317161075686166, 'mean_word_length': 8.513941220798793, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 32}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '317370', 'n_tokens_mistral': 8164, 'n_tokens_neox': 7839, 'n_words': 1210}