/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#include <QWidget>
#include <QFile>
#include <QRegExp>
#include <QCursor>
#include <QDir>
#include <QString>
#include <QDomElement>
#include <QDrag>
#include <QMimeData>

#include "oodrawimp.h"

#include "scconfig.h"

#include "color.h"
#include "commonstrings.h"
#include "customfdialog.h"
#include "fileunzip.h"
#include "fpointarray.h"
#include "menumanager.h"
#include "pageitem.h"
#include "pluginmanager.h"
#include "prefscontext.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "prefstable.h"
#include "propertiespalette.h"
#include "scclocale.h"
#include "sccolorengine.h"
#include "scmimedata.h"
#include "scraction.h"
#include "scribusXml.h"
#include "scribuscore.h"
#include "scribusdoc.h"
#include "selection.h"
#include "serializer.h"
#include "stylestack.h"
#include "undomanager.h"
#include "util.h"
#include "util_icon.h"
#include "util_math.h"


using namespace std;

int oodrawimp_getPluginAPIVersion()
{
	return PLUGIN_API_VERSION;
}

ScPlugin* oodrawimp_getPlugin()
{
	OODrawImportPlugin* plug = new OODrawImportPlugin();
	Q_CHECK_PTR(plug);
	return plug;
}

void oodrawimp_freePlugin(ScPlugin* plugin)
{
	OODrawImportPlugin* plug = dynamic_cast<OODrawImportPlugin*>(plugin);
	Q_ASSERT(plug);
	delete plug;
}

OODrawImportPlugin::OODrawImportPlugin() :
	LoadSavePlugin(),
	importAction(new ScrAction(ScrAction::DLL, "", QKeySequence(), this))
{
	// Set action info in languageChange, so we only have to do
	// it in one place. This includes registering file formats.
	languageChange();
}
/*
void OODrawImportPlugin::addToMainWindowMenu(ScribusMainWindow *mw)
{
	// Then hook up the action
	importAction->setEnabled(true);
	connect( importAction, SIGNAL(triggered()), SLOT(import()) );
	mw->scrMenuMgr->addMenuItem(importAction, "FileImport");
}
*/
OODrawImportPlugin::~OODrawImportPlugin()
{
	unregisterAll();
	// note: importAction is automatically deleted by Qt
};

void OODrawImportPlugin::languageChange()
{
	importAction->setText( tr("Import &OpenOffice.org Draw..."));
	// (Re)register file formats
	unregisterAll();
	registerFormats();
}

const QString OODrawImportPlugin::fullTrName() const
{
	return QObject::tr("OpenOffice.org Draw Importer");
}

const ScActionPlugin::AboutData* OODrawImportPlugin::getAboutData() const
{
	AboutData* about = new AboutData;
	about->authors = "Franz Schmid <franz@scribus.info>";
	about->shortDescription = tr("Imports OpenOffice.org Draw Files");
	about->description = tr("Imports most OpenOffice.org Draw files into the current document, converting their vector data into Scribus objects.");
	about->license = "GPL";
	Q_CHECK_PTR(about);
	return about;
}

void OODrawImportPlugin::deleteAboutData(const AboutData* about) const
{
	Q_ASSERT(about);
	delete about;
}

void OODrawImportPlugin::registerFormats()
{
	QString odtName = tr("OpenDocument 1.0 Draw", "Import/export format name");
	FileFormat odtformat(this);
	odtformat.trName = odtName; // Human readable name
	odtformat.formatId = FORMATID_ODGIMPORT;
	odtformat.filter = odtName + " (*.odg *.ODG)"; // QFileDialog filter
	odtformat.nameMatch = QRegExp("\\.odg$", Qt::CaseInsensitive);
	odtformat.load = true;
	odtformat.save = false;
	odtformat.mimeTypes = QStringList("application/vnd.oasis.opendocument.graphics"); // MIME types
	odtformat.priority = 64; // Priority
	registerFormat(odtformat);

	QString sxdName = tr("OpenOffice.org 1.x Draw", "Import/export format name");
	FileFormat sxdformat(this);
	sxdformat.trName = sxdName; // Human readable name
	sxdformat.formatId = FORMATID_SXDIMPORT;
	sxdformat.filter = sxdName + " (*.sxd *.SXD)"; // QFileDialog filter
	sxdformat.nameMatch = QRegExp("\\.sxd$", Qt::CaseInsensitive);
	sxdformat.load = true;
	sxdformat.save = false;
	sxdformat.mimeTypes = QStringList("application/vnd.sun.xml.draw"); // MIME types
	sxdformat.priority = 64; // Priority
	registerFormat(sxdformat);
}

bool OODrawImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
{
	// TODO: try to identify .sxd / .odt files
	return true;
}

bool OODrawImportPlugin::loadFile(const QString & fileName, const FileFormat &, int flags, int /*index*/)
{
	// For this plugin, right now "load" and "import" are the same thing
	return import(fileName, flags);
}

bool OODrawImportPlugin::import(QString fileName, int flags)
{
	if (!checkFlags(flags))
		return false;
	if (fileName.isEmpty())
	{
		flags |= lfInteractive;
		PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("OODrawImport");
		QString wdir = prefs->get("wdir", ".");
		CustomFDialog diaf(ScCore->primaryMainWindow(), wdir, QObject::tr("Open"), QObject::tr("OpenOffice.org Draw (*.sxd *.odg);;All Files (*)"));
		if (diaf.exec())
		{
			fileName = diaf.selectedFile();
			prefs->set("wdir", fileName.left(fileName.lastIndexOf("/")));
		}
		else
			return true;
	}
	m_Doc=ScCore->primaryMainWindow()->doc;
	UndoTransaction* activeTransaction = NULL;
	bool emptyDoc = (m_Doc == NULL);
	bool hasCurrentPage = (m_Doc && m_Doc->currentPage());
	TransactionSettings trSettings;
	trSettings.targetName   = hasCurrentPage ? m_Doc->currentPage()->getUName() : "";
	trSettings.targetPixmap = Um::IImageFrame;
	trSettings.actionName   = Um::ImportOOoDraw;
	trSettings.description  = fileName;
	trSettings.actionPixmap = Um::IImportOOoDraw;
	OODPlug dia(m_Doc);
	if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
		UndoManager::instance()->setUndoEnabled(false);
	if (UndoManager::undoEnabled())
		activeTransaction = new UndoTransaction(UndoManager::instance()->beginTransaction(trSettings));
	bool importDone = dia.import(fileName, trSettings, flags);
	if (activeTransaction)
	{
		activeTransaction->commit();
		delete activeTransaction;
		activeTransaction = NULL;
	}
	if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
		UndoManager::instance()->setUndoEnabled(true);
	if (dia.importCanceled)
	{
		if ((!importDone) || (dia.importFailed))
			QMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, tr("The file could not be imported"), 1, 0, 0);
		else if (dia.unsupported)
			QMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, tr("This file contains some unsupported features"), 1, 0, 0);
	}
	return importDone;
}

OODPlug::OODPlug(ScribusDoc* doc)
{
	m_Doc=doc;
	unsupported = false;
	interactive = false;
	importFailed = false;
	importCanceled = true;
	importedColors.clear();
	tmpSel=new Selection(this, false);
}

bool OODPlug::import(QString fileName, const TransactionSettings& trSettings, int flags )
{
	bool importDone = false;
	interactive = (flags & LoadSavePlugin::lfInteractive);
	QByteArray f, f2, f3;
	if ( !QFile::exists(fileName) )
		return false;
// 	m_styles.setAutoDelete( true );
	FileUnzip* fun = new FileUnzip(fileName);
	stylePath   = fun->getFile("styles.xml");
	contentPath = fun->getFile("content.xml");
	metaPath = fun->getFile("meta.xml");
	delete fun;
	// Qt4 NULL -> isNull()
	if ((!stylePath.isNull()) && (!contentPath.isNull()))
	{
		HaveMeta = false;
		QString docname = fileName.right(fileName.length() - fileName.lastIndexOf("/") - 1);
		docname = docname.left(docname.lastIndexOf("."));
		loadRawText(stylePath, f);
		if(!inpStyles.setContent(f))
			return false;
		loadRawText(contentPath, f2);
		if(!inpContents.setContent(f2))
			return false;
		QFile::remove(stylePath);
		QFile::remove(contentPath);
		HaveMeta = false;
		if (!metaPath.isEmpty())
		{
			loadRawText(metaPath, f3);
			HaveMeta = inpMeta.setContent(f3);
			QFile::remove(f3);
		}
	}
	else if ((stylePath.isNull()) && (!contentPath.isNull()))
	{
		QFile f2(contentPath);
		f2.remove();
	}
	else if ((!stylePath.isNull()) && (contentPath.isNull()))
	{
		QFile f1(stylePath);
		f1.remove();
	}
	QString CurDirP = QDir::currentPath();
	QFileInfo efp(fileName);
	QDir::setCurrent(efp.path());
	importDone = convert(trSettings, flags);
	QDir::setCurrent(CurDirP);
	return importDone;
}

bool OODPlug::convert(const TransactionSettings& trSettings, int flags)
{
	bool ret = false;
	bool isOODraw2 = false;
	QDomNode drawPagePNode;
	int PageCounter = 0;
	QList<PageItem*> Elements;
	createStyleMap( inpStyles );
	QDomElement docElem = inpContents.documentElement();
	QDomNode automaticStyles = docElem.namedItem( "office:automatic-styles" );
	if( !automaticStyles.isNull() )
		insertStyles( automaticStyles.toElement() );
	QDomNode body = docElem.namedItem( "office:body" );
	QDomNode drawPage = body.namedItem( "draw:page" );
	if ( drawPage.isNull() )
	{
		QDomNode offDraw = body.namedItem( "office:drawing" );
		drawPage = offDraw.namedItem( "draw:page" );
		if (drawPage.isNull())
		{
			QMessageBox::warning( m_Doc->scMW(), CommonStrings::trWarning, tr("This document does not seem to be an OpenOffice Draw file.") );
			return false;
		}
		else
		{
			isOODraw2 = true;
			drawPagePNode = body.namedItem( "office:drawing" );
		}
	}
	else 
		drawPagePNode = body;
	StyleStack::Mode mode = isOODraw2 ? StyleStack::OODraw2x : StyleStack::OODraw1x;
	m_styleStack.setMode( mode );
	QDomElement dp = drawPage.toElement();
	QDomElement *master = m_styles[dp.attribute( "draw:master-page-name" )];
	QDomElement *style = NULL;
	QDomElement properties;
	if (isOODraw2)
	{
		style = m_styles.value(master->attribute( "style:page-layout-name" ), NULL);
		if (style)
			properties = style->namedItem("style:page-layout-properties" ).toElement();
	}
	else
	{
		style = m_styles.value(master->attribute( "style:page-master-name" ), NULL);
		if (style)
			properties = style->namedItem( "style:properties" ).toElement();
	}
	double width = !properties.attribute( "fo:page-width" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-width" ) ) : 550.0;
	double height = !properties.attribute( "fo:page-height" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-height" ) ) : 841.0;
	if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
		m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
	else
	{
		if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
		{
			m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
			ScCore->primaryMainWindow()->HaveNewDoc();
			ret = true;
		}
	}
	if ((ret) || (!interactive))
	{
		if (width > height)
			m_Doc->PageOri = 1;
		else
			m_Doc->PageOri = 0;
		m_Doc->m_pageSize = "Custom";
		QDomNode mpg;
		QDomElement metaElem = inpMeta.documentElement();
		QDomElement mp = metaElem.namedItem( "office:meta" ).toElement();
		mpg = mp.namedItem( "dc:title" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setTitle(mpg.toElement().text());
		mpg = mp.namedItem( "meta:initial-creator" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setAuthor(mpg.toElement().text());
		mpg = mp.namedItem( "dc:description" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setComments(mpg.toElement().text());
		mpg = mp.namedItem( "dc:language" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setLangInfo(mpg.toElement().text());
		mpg = mp.namedItem( "meta:creation-date" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setDate(mpg.toElement().text());
		mpg = mp.namedItem( "dc:creator" );
		if (!mpg.isNull())
			m_Doc->documentInfo.setContrib(mpg.toElement().text());
		mpg = mp.namedItem( "meta:keywords" );
		if (!mpg.isNull())
		{
			QString Keys = "";
			for( QDomNode n = mpg.firstChild(); !n.isNull(); n = n.nextSibling() )
			{
				Keys += n.toElement().text()+", ";
			}
			if (Keys.length() > 2)
				m_Doc->documentInfo.setKeywords(Keys.left(Keys.length()-2));
		}
	}
	Elements.clear();
	m_Doc->view()->Deselect();
	m_Doc->setLoading(true);
	m_Doc->DoDrawing = false;
	m_Doc->view()->updatesOn(false);
	m_Doc->scMW()->setScriptRunning(true);
	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
	if (!m_Doc->PageColors.contains("Black"))
		m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
	for( QDomNode drawPag = drawPagePNode.firstChild(); !drawPag.isNull(); drawPag = drawPag.nextSibling() )
	{
		QDomElement dpg = drawPag.toElement();
		if (!interactive)
		{
			m_Doc->addPage(PageCounter);
			m_Doc->view()->addPage(PageCounter);
		}
		PageCounter++;
		m_styleStack.clear();
		fillStyleStack( dpg );
		QList<PageItem*> el = parseGroup( dpg );
		for (int ec = 0; ec < el.count(); ++ec)
			Elements.append(el.at(ec));
		if ((interactive) && (PageCounter == 1))
			break;
	}
	tmpSel->clear();
//	if ((Elements.count() > 1) && (interactive))
	if (Elements.count() == 0)
	{
		importFailed = true;
		if (importedColors.count() != 0)
		{
			for (int cd = 0; cd < importedColors.count(); cd++)
			{
				m_Doc->PageColors.remove(importedColors[cd]);
			}
		}
	}
	if (Elements.count() > 1)
	{
		bool isGroup = true;
		int firstElem = -1;
		if (Elements.at(0)->Groups.count() != 0)
			firstElem = Elements.at(0)->Groups.top();
		for (int bx = 0; bx < Elements.count(); ++bx)
		{
			PageItem* bxi = Elements.at(bx);
			if (bxi->Groups.count() != 0)
			{
				if (bxi->Groups.top() != firstElem)
					isGroup = false;
			}
			else
				isGroup = false;
		}
		if (!isGroup)
		{
			double minx = 99999.9;
			double miny = 99999.9;
			double maxx = -99999.9;
			double maxy = -99999.9;
			uint lowestItem = 999999;
			uint highestItem = 0;
			for (int a = 0; a < Elements.count(); ++a)
			{
				Elements.at(a)->Groups.push(m_Doc->GroupCounter);
				PageItem* currItem = Elements.at(a);
				lowestItem = qMin(lowestItem, currItem->ItemNr);
				highestItem = qMax(highestItem, currItem->ItemNr);
				double x1, x2, y1, y2;
				currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
				minx = qMin(minx, x1);
				miny = qMin(miny, y1);
				maxx = qMax(maxx, x2);
				maxy = qMax(maxy, y2);
			}
			double gx = minx;
			double gy = miny;
			double gw = maxx - minx;
			double gh = maxy - miny;
			PageItem *high = m_Doc->Items->at(highestItem);
			int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
			PageItem *neu = m_Doc->Items->takeAt(z);
			m_Doc->Items->insert(lowestItem, neu);
			neu->Groups.push(m_Doc->GroupCounter);
			neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
			neu->isGroupControl = true;
			neu->groupsLastItem = high;
			neu->setTextFlowMode(PageItem::TextFlowDisabled);
			for (int a = 0; a < m_Doc->Items->count(); ++a)
			{
				m_Doc->Items->at(a)->ItemNr = a;
			}
			Elements.prepend(neu);
			m_Doc->GroupCounter++;
		}
	}
	m_Doc->DoDrawing = true;
	m_Doc->scMW()->setScriptRunning(false);
	if (interactive)
		m_Doc->setLoading(false);
	qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
	if ((Elements.count() > 0) && (!ret) && (interactive))
	{
		if (flags & LoadSavePlugin::lfScripted)
		{
			bool loadF = m_Doc->isLoading();
			m_Doc->setLoading(false);
			m_Doc->changed();
			m_Doc->setLoading(loadF);
			m_Doc->m_Selection->delaySignalsOn();
			for (int dre=0; dre<Elements.count(); ++dre)
			{
 				m_Doc->m_Selection->addItem(Elements.at(dre), true);
			}
			m_Doc->m_Selection->delaySignalsOff();
	 		m_Doc->m_Selection->setGroupRect();
			m_Doc->view()->updatesOn(true);
			importCanceled = false;
		}
		else
		{
			m_Doc->DragP = true;
			m_Doc->DraggedElem = 0;
			m_Doc->DragElements.clear();
			m_Doc->m_Selection->delaySignalsOn();
			for (int dre=0; dre<Elements.count(); ++dre)
			{
				m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
				tmpSel->addItem(Elements.at(dre), true);
			}
			ScriXmlDoc *ss = new ScriXmlDoc();
			tmpSel->setGroupRect();
			//CB keep for reference conversion for now
			//Q3DragObject *dr = new Q3TextDrag(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel), m_Doc->view()->viewport());
			ScElemMimeData* md = new ScElemMimeData();
			md->setScribusElem(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel));
			delete ss;
/*#ifndef Q_WS_MAC*/
// see #2196, #2526
			m_Doc->itemSelection_DeleteItem(tmpSel);
/*#endif*/
			m_Doc->view()->updatesOn(true);
			m_Doc->m_Selection->delaySignalsOff();
			// We must copy the TransationSettings object as it is owned
			// by handleObjectImport method afterwards
			TransactionSettings* transacSettings = new TransactionSettings(trSettings);
			m_Doc->view()->handleObjectImport(md, transacSettings);
			m_Doc->DragP = false;
			m_Doc->DraggedElem = 0;
			m_Doc->DragElements.clear();
		}
	}
	else
	{
		bool loadF = m_Doc->isLoading();
		m_Doc->setLoading(false);
		m_Doc->changed();
		m_Doc->reformPages();
		m_Doc->view()->updatesOn(true);
		m_Doc->setLoading(loadF);
	}
	qApp->restoreOverrideCursor();
	return true;
}

QList<PageItem*> OODPlug::parseGroup(const QDomElement &e)
{
	OODrawStyle oostyle;
	FPointArray ImgClip;
	QList<PageItem*> elements, cElements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	storeObjectStyles(e);
	parseStyle(oostyle, e);
	QString drawID = e.attribute("draw:name");
	int zn = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None, true);
	PageItem *neu = m_Doc->Items->at(zn);
	for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		QDomElement b = n.toElement();
		if( b.isNull() )
			continue;
		QList<PageItem*> el = parseElement(b);
		for (int ec = 0; ec < el.count(); ++ec)
			cElements.append(el.at(ec));
	}
	if (cElements.count() < 2)
	{
		m_Doc->Items->takeAt(zn);
		delete neu;
		for (int a = 0; a < m_Doc->Items->count(); ++a)
		{
			m_Doc->Items->at(a)->ItemNr = a;
		}
		for (int gr = 0; gr < cElements.count(); ++gr)
		{
			elements.append(cElements.at(gr));
		}
	}
	else
	{
		double minx = 99999.9;
		double miny = 99999.9;
		double maxx = -99999.9;
		double maxy = -99999.9;
		elements.append(neu);
		for (int gr = 0; gr < cElements.count(); ++gr)
		{
			PageItem* currItem = cElements.at(gr);
			double x1, x2, y1, y2;
			currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
			minx = qMin(minx, x1);
			miny = qMin(miny, y1);
			maxx = qMax(maxx, x2);
			maxy = qMax(maxy, y2);
		}
		double gx = minx;
		double gy = miny;
		double gw = maxx - minx;
		double gh = maxy - miny;
		neu->setXYPos(gx, gy);
		neu->setWidthHeight(gw, gh);
		if (ImgClip.size() != 0)
			neu->PoLine = ImgClip.copy();
		else
			neu->SetRectFrame();
		ImgClip.resize(0);
		neu->Clip = FlattenPath(neu->PoLine, neu->Segments);
		neu->Groups.push(m_Doc->GroupCounter);
		neu->isGroupControl = true;
		neu->groupsLastItem = cElements.last();
		if( !e.attribute("id").isEmpty() )
			neu->setItemName(e.attribute("id"));
		else
			neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
//		neu->setFillTransparency(1 - gc->Opacity);
		for (int gr = 0; gr < cElements.count(); ++gr)
		{
			cElements.at(gr)->Groups.push(m_Doc->GroupCounter);
			elements.append(cElements.at(gr));
		}
		neu->setTextFlowMode(PageItem::TextFlowDisabled);
		m_Doc->GroupCounter++;
	}
	return elements;
}

QList<PageItem*> OODPlug::parseElement(const QDomElement &e)
{
	QList<PageItem*> GElements;
	QString STag = e.tagName();
	if ( STag == "draw:g" )
	{
		GElements = parseGroup(e);
		return GElements;
	}
	if ( STag == "draw:rect" )
		GElements = parseRect(e);
	else if ( STag == "draw:circle" || STag == "draw:ellipse" )
		GElements = parseEllipse(e);
	else if ( STag == "draw:line" )
		GElements = parseLine(e);
	else if ( STag == "draw:polygon" )
		GElements = parsePolygon(e);
	else if ( STag == "draw:polyline" )
		GElements = parsePolyline(e);
	else if( STag == "draw:path" )
		GElements = parsePath(e);
	else if ( STag == "draw:text-box" )
		GElements = parseTextBox(e);
	else if ( STag == "draw:frame" )
		GElements = parseFrame(e);
	else if ( STag == "draw:connector" )
		GElements = parseConnector(e);
	else
	{
		// warn if unsupported feature are encountered
		unsupported = true;
		qDebug("Not supported yet: %s", STag.toLocal8Bit().data());
	}
	return GElements;
}

QList<PageItem*> OODPlug::parseRect(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	double x = parseUnit(e.attribute("svg:x"));
	double y = parseUnit(e.attribute("svg:y")) ;
	double w = parseUnit(e.attribute("svg:width"));
	double h = parseUnit(e.attribute("svg:height"));
	double corner = parseUnit(e.attribute("draw:corner-radius"));
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX+x, BaseY+y, w, h, style.strokeWidth, style.fillColor, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	if (corner != 0)
	{
		ite->setCornerRadius(corner);
		ite->SetFrameRound();
		m_Doc->setRedrawBounding(ite);
	}
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parseEllipse(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	double x = parseUnit(e.attribute("svg:x"));
	double y = parseUnit(e.attribute("svg:y")) ;
	double w = parseUnit(e.attribute("svg:width"));
	double h = parseUnit(e.attribute("svg:height"));
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX+x, BaseY+y, w, h, style.strokeWidth, style.fillColor, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parseLine(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	double x1 = e.attribute( "svg:x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:x1" ) );
	double y1 = e.attribute( "svg:y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:y1" ) );
	double x2 = e.attribute( "svg:x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:x2" ) );
	double y2 = e.attribute( "svg:y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:y2" ) );
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, CommonStrings::None, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite->PoLine.resize(4);
	ite->PoLine.setPoint(0, FPoint(x1, y1));
	ite->PoLine.setPoint(1, FPoint(x1, y1));
	ite->PoLine.setPoint(2, FPoint(x2, y2));
	ite->PoLine.setPoint(3, FPoint(x2, y2));
	FPoint wh = getMaxClipF(&ite->PoLine);
	ite->setWidthHeight(wh.x(), wh.y());
	ite->ClipEdited = true;
	ite->FrameType = 3;
	if (!e.hasAttribute("draw:transform"))
	{
		ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
		m_Doc->AdjustItemSize(ite);
	}
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parsePolygon(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, style.fillColor, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite->PoLine.resize(0);
	appendPoints(&ite->PoLine, e, true);
	FPoint wh = getMaxClipF(&ite->PoLine);
	ite->setWidthHeight(wh.x(), wh.y());
	ite->ClipEdited = true;
	ite->FrameType = 3;
	if (!e.hasAttribute("draw:transform"))
	{
		ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
		m_Doc->AdjustItemSize(ite);
	}
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parsePolyline(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, CommonStrings::None, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite->PoLine.resize(0);
	appendPoints(&ite->PoLine, e, false);
	FPoint wh = getMaxClipF(&ite->PoLine);
	ite->setWidthHeight(wh.x(), wh.y());
	ite->ClipEdited = true;
	ite->FrameType = 3;
	if (!e.hasAttribute("draw:transform"))
	{
		ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
		m_Doc->AdjustItemSize(ite);
	}
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parsePath(const QDomElement &e)
{
	OODrawStyle style;
	FPointArray pArray;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	storeObjectStyles(e);
	parseStyle(style, e);
	PageItem::ItemType itype = parseSVG(e.attribute("svg:d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
	int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, style.fillColor, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite->PoLine.resize(0);
	ite->PoLine = pArray;
	if (ite->PoLine.size() < 4)
	{
// 		m_Doc->m_Selection->addItem(ite);
		tmpSel->addItem(ite);
// 		m_Doc->itemSelection_DeleteItem();
		m_Doc->itemSelection_DeleteItem(tmpSel);
	}
	else
	{
		QMatrix mat;
		double x = parseUnit(e.attribute("svg:x"));
		double y = parseUnit(e.attribute("svg:y")) ;
		double w = parseUnit(e.attribute("svg:width"));
		double h = parseUnit(e.attribute("svg:height"));
		double vx = 0;
		double vy = 0;
		double vw = 1;
		double vh = 1;
		parseViewBox(e, &vx, &vy, &vw, &vh);
		double sx = (vw != 0.0) ? (w / vw) : w;
		double sy = (vh != 0.0) ? (h / vh) : h;
		mat.translate(x, y);
		mat.scale(sx, sy);
		ite->PoLine.map(mat);
		FPoint wh = getMaxClipF(&ite->PoLine);
		ite->setWidthHeight(wh.x(), wh.y());
		ite->ClipEdited = true;
		ite->FrameType = 3;
		if (!e.hasAttribute("draw:transform"))
		{
			ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
			m_Doc->AdjustItemSize(ite);
		}
		ite = finishNodeParsing(e, ite, style);
		elements.append(ite);
	}
	return elements;
}

QList<PageItem*> OODPlug::parseTextBox(const QDomElement &e)
{
	OODrawStyle style;
	QList<PageItem*> elements;
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	double x = parseUnit(e.attribute("svg:x"));
	double y = parseUnit(e.attribute("svg:y")) ;
	double w = parseUnit(e.attribute("svg:width"));
	double h = parseUnit(e.attribute("svg:height"));
	storeObjectStyles(e);
	parseStyle(style, e);
	int z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, BaseX+x, BaseY+y, w, h+(h*0.1), style.strokeWidth, CommonStrings::None, style.strokeColor, true);
	PageItem* ite = m_Doc->Items->at(z);
	ite->setFillColor(style.fillColor);
	ite->setLineColor(style.strokeColor);
	ite = finishNodeParsing(e, ite, style);
	elements.append(ite);
	return elements;
}

QList<PageItem*> OODPlug::parseFrame(const QDomElement &e)
{
	OODrawStyle oostyle;
	QList<PageItem*> elements;
	QString drawID = e.attribute("draw:name");
	double BaseX = m_Doc->currentPage()->xOffset();
	double BaseY = m_Doc->currentPage()->yOffset();
	double x = parseUnit(e.attribute("svg:x"));
	double y = parseUnit(e.attribute("svg:y")) ;
	double w = parseUnit(e.attribute("svg:width"));
	double h = parseUnit(e.attribute("svg:height"));
	storeObjectStyles(e);
	parseStyle(oostyle, e);
	QDomNode n = e.firstChild();
	QString STag2 = n.toElement().tagName();
	if ( STag2 == "draw:text-box" )
	{
		int z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, BaseX+x, BaseY+y, w, h+(h*0.1), oostyle.strokeWidth, CommonStrings::None, oostyle.strokeColor, true);
		PageItem* ite = m_Doc->Items->at(z);
		ite->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
		ite->setFillTransparency(oostyle.fillTrans);
		ite->setLineTransparency(oostyle.strokeTrans);
		ite->setTextFlowMode(PageItem::TextFlowDisabled);
		if (!drawID.isEmpty())
			ite->setItemName(drawID);
		ite = parseTextP(n.toElement(), ite);
		elements.append(ite);
	}
	return elements;
}

QList<PageItem*> OODPlug::parseConnector(const QDomElement &e)
{
	QList<PageItem*> elements;
	if (e.hasAttribute("svg:x1") && e.hasAttribute("svg:x2") && e.hasAttribute("svg:y1") && e.hasAttribute("svg:y2"))
	{
		elements = parseLine(e);
	}
	else
	{
		unsupported = true;
		qDebug("an unsupported form of connector was found");
	}
	return elements;
}

void OODPlug::parseStyle(OODrawStyle& oostyle, const QDomElement &e)
{
	oostyle.haveGradient = false;
	oostyle.gradient.clearStops();
	if( m_styleStack.hasAttribute("draw:stroke") )
	{
		if( m_styleStack.attribute( "draw:stroke" ) == "none" )
			oostyle.strokeWidth = 0.0;
		else
		{
			if( m_styleStack.hasAttribute("svg:stroke-width"))
			{
				oostyle.strokeWidth = parseUnit(m_styleStack.attribute("svg:stroke-width"));
				if (oostyle.strokeWidth == 0)
					oostyle.strokeWidth = 1;
			}
			if( m_styleStack.hasAttribute("svg:stroke-color"))
				oostyle.strokeColor = parseColor(m_styleStack.attribute("svg:stroke-color"));
			if( m_styleStack.hasAttribute( "svg:stroke-opacity" ) )
				oostyle.strokeTrans = ScCLocale::toDoubleC(m_styleStack.attribute( "svg:stroke-opacity" ).remove( '%' )) / 100.0;
			if( m_styleStack.attribute( "draw:stroke" ) == "dash" )
			{
				QString style = m_styleStack.attribute( "draw:stroke-dash" );
				if( style == "Ultrafine Dashed")
					oostyle.dashes << 1.4 << 1.4;
				else if( style == "Fine Dashed" )
					oostyle.dashes << 14.4 << 14.4;
				else if( style == "Fine Dotted")
					oostyle.dashes << 13 << 13;
				else if( style == "Ultrafine 2 Dots 3 Dashes")
					oostyle.dashes << 1.45 << 3.6 << 1.45 << 3.6 << 7.2 << 3.6 << 7.2 << 3.6 << 7.2 << 3.6;
				else if( style == "Line with Fine Dots")
				{
					oostyle.dashes << 56.9 << 4.31;
					for (int dd = 0; dd < 10; ++ dd)
					{
						oostyle.dashes << 8.6 << 4.31;
					}
				}
				else if( style == "2 Dots 1 Dash" )
					oostyle.dashes << 2.8 << 5.75 << 2.8 << 5.75 << 5.75 << 5.75;
			}
		}
	}
	if( m_styleStack.hasAttribute( "draw:fill" ) )
	{
		QString fill = m_styleStack.attribute( "draw:fill" );
		if( fill == "solid" )
		{
			if( m_styleStack.hasAttribute( "draw:fill-color" ) )
				oostyle.fillColor = parseColor( m_styleStack.attribute("draw:fill-color"));
			if( m_styleStack.hasAttribute( "draw:transparency" ) )
				oostyle.fillTrans = ScCLocale::toDoubleC(m_styleStack.attribute( "draw:transparency" ).remove( '%' )) / 100.0;
		}
		else if( fill == "gradient" )
		{
			oostyle.haveGradient = true;
			oostyle.gradientAngle = 0;
			oostyle.gradient.clearStops();
			oostyle.gradient.setRepeatMethod( VGradient::none );
			QString style = m_styleStack.attribute( "draw:fill-gradient-name" );
			QDomElement* draw = m_draws[style];
			if( draw )
			{
				double border = 0.0;
				int shadeS = 100;
				int shadeE = 100;
				if( draw->hasAttribute( "draw:border" ) )
					border += ScCLocale::toDoubleC(draw->attribute( "draw:border" ).remove( '%' )) / 100.0;
				if( draw->hasAttribute( "draw:start-intensity" ) )
					shadeS = draw->attribute( "draw:start-intensity" ).remove( '%' ).toInt();
				if( draw->hasAttribute( "draw:end-intensity" ) )
					shadeE = draw->attribute( "draw:end-intensity" ).remove( '%' ).toInt();
				QString type = draw->attribute( "draw:style" );
				if( type == "linear" || type == "axial" )
				{
					oostyle.gradient.setType( VGradient::linear );
					oostyle.gradientAngle = ScCLocale::toDoubleC(draw->attribute( "draw:angle" )) / 10;
					oostyle.gradientType = 1;
				}
				else if( type == "radial" || type == "ellipsoid" )
				{
					if( draw->hasAttribute( "draw:cx" ) )
						oostyle.gradientPointX = ScCLocale::toDoubleC(draw->attribute( "draw:cx" ).remove( '%' )) / 100.0;
					else
						oostyle.gradientPointX = 0.5;
					if( draw->hasAttribute( "draw:cy" ) )
						oostyle.gradientPointY = ScCLocale::toDoubleC(draw->attribute( "draw:cy" ).remove( '%' )) / 100.0;
					else
						oostyle.gradientPointY = 0.5;
					oostyle.gradientType = 2;
				}
				QString c, c2;
				c = parseColor( draw->attribute( "draw:start-color" ) );
				c2 = parseColor( draw->attribute( "draw:end-color" ) );
				const ScColor& col1 = m_Doc->PageColors[c];
				const ScColor& col2 = m_Doc->PageColors[c2];
				if (((oostyle.gradientAngle > 90) && (oostyle.gradientAngle < 271)) || (oostyle.gradientType == 2))
				{
					const ScColor& col1 = m_Doc->PageColors[c];
					const ScColor& col2 = m_Doc->PageColors[c2];
					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col2, m_Doc, shadeE), 0.0, 0.5, 1, c2, shadeE );
					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col1, m_Doc, shadeS), 1.0 - border, 0.5, 1, c, shadeS );
				}
				else
				{
					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col1, m_Doc, shadeS), border, 0.5, 1, c, shadeS );
					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col2, m_Doc, shadeE), 1.0, 0.5, 1, c2, shadeE );
				}
			}
		}
	}
}

void OODPlug::parseCharStyle(CharStyle& style, const QDomElement &e)
{
	if ( m_styleStack.hasAttribute("fo:font-size") )
	{
		QString fs = m_styleStack.attribute("fo:font-size").remove( "pt" );
		int FontSize = (int) (ScCLocale::toFloatC(fs) * 10.0);
		style.setFontSize(FontSize);
	}
}

void OODPlug::parseParagraphStyle(ParagraphStyle& style, const QDomElement &e)
{
	if ( m_styleStack.hasAttribute("fo:text-align") )
	{
		QString attValue = m_styleStack.attribute("fo:text-align");
		if (attValue == "left")
			style.setAlignment(ParagraphStyle::Leftaligned);
		if (attValue == "center")
			style.setAlignment(ParagraphStyle::Centered);
		if (attValue == "right")
			style.setAlignment(ParagraphStyle::Rightaligned);
	}
	if ( m_styleStack.hasAttribute("fo:font-size") )
	{
		QString fs = m_styleStack.attribute("fo:font-size").remove( "pt" );
		int FontSize = (int) (ScCLocale::toFloatC(fs) * 10.0);
		style.charStyle().setFontSize(FontSize);
		style.setLineSpacing((FontSize + FontSize * 0.2) / 10.0);
	}
}

PageItem* OODPlug::parseTextP (const QDomElement& elm, PageItem* item)
{
	for ( QDomNode n = elm.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		if ( !n.hasAttributes() && !n.hasChildNodes() )
			continue;
		QDomElement e = n.toElement();
		if ( e.text().isEmpty() )
			continue;
		storeObjectStyles(e);
		item->itemText.insertChars(-1, SpecialChars::PARSEP);
		item = parseTextSpans(e, item);
	}
	return item;
}

PageItem* OODPlug::parseTextSpans(const QDomElement& elm, PageItem* item)
{
	bool firstSpan = true;
	for ( QDomNode n = elm.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QString chars;
		QDomElement e = n.toElement();
		if (n.isElement() && (e.tagName() == "text:span"))
		{
			chars = e.text().simplified();
			storeObjectStyles(e);
		}
		if (n.isText())
		{
			QDomText t = n.toText();
			chars = t.data().simplified();
		}
		if (chars.isEmpty())
			continue;
		int pos = item->itemText.length();
		if ( firstSpan && (m_styleStack.hasAttribute("fo:text-align") || m_styleStack.hasAttribute("fo:font-size")) )
		{
			ParagraphStyle newStyle;
			parseParagraphStyle(newStyle, n.isElement() ? e : elm);
			item->itemText.applyStyle(-1, newStyle);
		}
		item->itemText.insertChars( -2, chars);
		if ( !firstSpan && m_styleStack.hasAttribute("fo:font-size") )
		{
			CharStyle newStyle;
			parseCharStyle(newStyle, n.isElement() ? e : elm);
			item->itemText.applyCharStyle(pos, chars.length(), newStyle);
		}
		if (!item->asPolyLine() && !item->asTextFrame())
			item = m_Doc->convertItemTo(item, PageItem::TextFrame);
		firstSpan = false;
	}
	return item;
}

PageItem* OODPlug::finishNodeParsing(const QDomElement &elm, PageItem* item, OODrawStyle& oostyle)
{
	item->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
//	bool firstPa = false;
	QString drawID = elm.attribute("draw:name");
	item = parseTextP(elm, item);
	item->setFillTransparency(oostyle.fillTrans);
	item->setLineTransparency(oostyle.strokeTrans);
	if (oostyle.dashes.count() != 0)
		item->DashValues = oostyle.dashes;
	if (!drawID.isEmpty())
		item->setItemName(drawID);
	if (elm.hasAttribute("draw:transform"))
	{
		parseTransform(&item->PoLine, elm.attribute("draw:transform"));
		item->ClipEdited = true;
		item->FrameType = 3;
		FPoint wh = getMaxClipF(&item->PoLine);
		item->setWidthHeight(wh.x(), wh.y());
		item->Clip = FlattenPath(item->PoLine, item->Segments);
		m_Doc->AdjustItemSize(item);
	}
	item->OwnPage = m_Doc->OnPage(item);
	//ite->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
	item->setTextFlowMode(PageItem::TextFlowDisabled);
	if (oostyle.haveGradient)
	{
		item->GrType = 0;
		if (oostyle.gradient.Stops() > 1)
		{
			item->fill_gradient = oostyle.gradient;
			if (oostyle.gradientType == 1)
			{
				bool flipped = false;
				double gradientAngle(oostyle.gradientAngle);
				if ((gradientAngle == 0) || (gradientAngle == 180) || (gradientAngle == 90) || (gradientAngle == 270))
				{
					if ((gradientAngle == 0) || (gradientAngle == 180))
					{
						item->GrType = 2;
						item->GrStartX = item->width() / 2.0;
						item->GrStartY = 0;
						item->GrEndX = item->width() / 2.0;
						item->GrEndY = item->height();
					}
					else if ((gradientAngle == 90) || (gradientAngle == 270))
					{
						item->GrType = 1;
						item->GrStartX = 0;
						item->GrStartY = item->height() / 2.0;
						item->GrEndX = item->width();
						item->GrEndY = item->height() / 2.0;
					}
				}
				else
				{
					if ((gradientAngle > 90) && (gradientAngle < 270))
						gradientAngle -= 180;
					else if ((gradientAngle > 270) && (gradientAngle < 360))
					{
						gradientAngle = 360 - gradientAngle;
						flipped = true;
					}
					double xpos;
					xpos = (item->width() / 2) * tan(gradientAngle* M_PI / 180.0) * (item->height() / item->width()) + (item->width() / 2);
					if ((xpos < 0) || (xpos > item->width()))
					{
						xpos = (item->height() / 2)- (item->height() / 2) * tan(gradientAngle* M_PI / 180.0) * (item->height() / item->width());
						if (flipped)
						{
							item->GrEndX = item->width();
							item->GrEndY = item->height() - xpos;
							item->GrStartX = 0;
							item->GrStartY = xpos;
						}
						else
						{
							item->GrEndY = xpos;
							item->GrEndX = item->width();
							item->GrStartX = 0;
							item->GrStartY = item->height() - xpos;
						}
					}
					else
					{
						item->GrEndX = xpos;
						item->GrEndY = item->height();
						item->GrStartX = item->width() - xpos;
						item->GrStartY = 0;
					}
					if (flipped)
					{
						item->GrEndX = item->width() - xpos;
						item->GrEndY = item->height();
						item->GrStartX = xpos;
						item->GrStartY = 0;
					}
					item->GrType = 6;
				}
			}
			if (oostyle.gradientType == 2)
			{
				item->GrType = 7;
				item->GrStartX = item->width() * oostyle.gradientPointX;
				item->GrStartY = item->height()* oostyle.gradientPointY;
				if (item->width() >= item->height())
				{
					item->GrEndX = item->width();
					item->GrEndY = item->height() / 2.0;
				}
				else
				{
					item->GrEndX = item->width() / 2.0;
					item->GrEndY = item->height();
				}
				//m_Doc->view()->updateGradientVectors(ite);
				item->updateGradientVectors();
			}
		}
		else
		{
			QList<VColorStop*> cstops = oostyle.gradient.colorStops();
			item->setFillColor(cstops.at(0)->name);
			item->setFillShade(cstops.at(0)->shade);
		}
	}
	return item;
}

void OODPlug::createStyleMap( QDomDocument &docstyles )
{
	QDomElement styles = docstyles.documentElement();
	if( styles.isNull() )
		return;

	QDomNode fixedStyles = styles.namedItem( "office:styles" );
	if( !fixedStyles.isNull() )
	{
		insertDraws( fixedStyles.toElement() );
		insertStyles( fixedStyles.toElement() );
	}
	QDomNode automaticStyles = styles.namedItem( "office:automatic-styles" );
	if( !automaticStyles.isNull() )
		insertStyles( automaticStyles.toElement() );

	QDomNode masterStyles = styles.namedItem( "office:master-styles" );
	if( !masterStyles.isNull() )
		insertStyles( masterStyles.toElement() );
}

void OODPlug::insertDraws( const QDomElement& styles )
{
	for( QDomNode n = styles.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if( !e.hasAttribute( "draw:name" ) )
			continue;
		QString name = e.attribute( "draw:name" );
		m_draws.insert( name, new QDomElement( e ) );
	}
}

void OODPlug::insertStyles( const QDomElement& styles )
{
	for ( QDomNode n = styles.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if( !e.hasAttribute( "style:name" ) )
			continue;
		QString name = e.attribute( "style:name" );
		m_styles.insert( name, new QDomElement( e ) );
	}
}

void OODPlug::fillStyleStack( const QDomElement& object )
{
	if( object.hasAttribute( "presentation:style-name" ) )
		addStyles( m_styles.value(object.attribute( "presentation:style-name" ), NULL) );
	if( object.hasAttribute( "draw:style-name" ) )
		addStyles( m_styles.value(object.attribute( "draw:style-name" ), NULL) );
	if( object.hasAttribute( "draw:text-style-name" ) )
		addStyles( m_styles.value(object.attribute( "draw:text-style-name" ), NULL) );
	if( object.hasAttribute( "text:style-name" ) )
		addStyles( m_styles.value(object.attribute( "text:style-name" ), NULL) );
}

void OODPlug::addStyles( const QDomElement* style )
{
	if (style)
	{
		if( style->hasAttribute( "style:parent-style-name" ) )
			addStyles( m_styles.value(style->attribute( "style:parent-style-name" ), NULL) );
		m_styleStack.push( *style );
	}
}

void OODPlug::storeObjectStyles( const QDomElement& object )
{
	fillStyleStack( object );
}

double OODPlug::parseUnit(const QString &unit)
{
	QString unitval=unit;
	if (unit.isEmpty())
		return 0.0;
	if( unit.right( 2 ) == "pt" )
		unitval.replace( "pt", "" );
	else if( unit.right( 2 ) == "cm" )
		unitval.replace( "cm", "" );
	else if( unit.right( 2 ) == "mm" )
		unitval.replace( "mm" , "" );
	else if( unit.right( 2 ) == "in" )
		unitval.replace( "in", "" );
	else if( unit.right( 2 ) == "px" )
		unitval.replace( "px", "" );
	double value = ScCLocale::toDoubleC(unitval);
	if( unit.right( 2 ) == "pt" )
		value = value;
	else if( unit.right( 2 ) == "cm" )
		value = ( value / 2.54 ) * 72;
	else if( unit.right( 2 ) == "mm" )
		value = ( value / 25.4 ) * 72;
	else if( unit.right( 2 ) == "in" )
		value = value * 72;
	else if( unit.right( 2 ) == "px" )
		value = value;
	return value;
}

QColor OODPlug::parseColorN( const QString &rgbColor )
{
	int r, g, b;
	keywordToRGB( rgbColor, r, g, b );
	return QColor( r, g, b );
}

QString OODPlug::parseColor( const QString &s )
{
	QColor c;
	QString ret = CommonStrings::None;
	if( s.startsWith( "rgb(" ) )
	{
		QString parse = s.trimmed();
		QStringList colors = parse.split( ',', QString::SkipEmptyParts );
		QString r = colors[0].right( ( colors[0].length() - 4 ) );
		QString g = colors[1];
		QString b = colors[2].left( ( colors[2].length() - 1 ) );
		if( r.contains( "%" ) )
		{
			r = r.left( r.length() - 1 );
			r = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(r) ) / 100.0 ) ) );
		}
		if( g.contains( "%" ) )
		{
			g = g.left( g.length() - 1 );
			g = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(g) ) / 100.0 ) ) );
		}
		if( b.contains( "%" ) )
		{
			b = b.left( b.length() - 1 );
			b = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(b) ) / 100.0 ) ) );
		}
		c = QColor(r.toInt(), g.toInt(), b.toInt());
	}
	else
	{
		QString rgbColor = s.trimmed();
		if( rgbColor.startsWith( "#" ) )
			c.setNamedColor( rgbColor );
		else
			c = parseColorN( rgbColor );
	}
	ColorList::Iterator it;
	bool found = false;
	int r, g, b;
	QColor tmpR;
	for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
	{
		if (it.value().getColorModel() == colorModelRGB)
		{
			it.value().getRGB(&r, &g, &b);
			tmpR.setRgb(r, g, b);
			if (c == tmpR)
			{
				ret = it.key();
				found = true;
			}
		}
	}
	if (!found)
	{
		ScColor tmp;
		tmp.fromQColor(c);
		tmp.setSpotColor(false);
		tmp.setRegistrationColor(false);
		m_Doc->PageColors.insert("FromOODraw"+c.name(), tmp);
		importedColors.append("FromOODraw"+c.name());
		ret = "FromOODraw"+c.name();
	}
	return ret;
}

void OODPlug::parseTransform(FPointArray *composite, const QString &transform)
{
	double dx, dy;
	QMatrix result;
	QStringList subtransforms = transform.split(')', QString::SkipEmptyParts);
	QStringList::ConstIterator it = subtransforms.begin();
	QStringList::ConstIterator end = subtransforms.end();
	for (; it != end; ++it)
	{
		QStringList subtransform = (*it).split('(', QString::SkipEmptyParts);
		subtransform[0] = subtransform[0].trimmed().toLower();
		subtransform[1] = subtransform[1].simplified();
		QRegExp reg("[,( ]");
		QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
		if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
			subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
		if(subtransform[0] == "rotate")
		{
			result = QMatrix();
			result.rotate(-parseUnit(params[0]) * 180 / M_PI);
			composite->map(result);
		}
		else if(subtransform[0] == "translate")
		{
			if(params.count() == 2)
			{
				dx = parseUnit(params[0]);
				dy = parseUnit(params[1]);
			}
			else
			{
				dx = parseUnit(params[0]);
				dy =0.0;
			}
			result = QMatrix();
			result.translate(dx, dy);
			composite->map(result);
		}
		else if(subtransform[0] == "skewx")
		{
			result = QMatrix();
			result.shear(-tan(ScCLocale::toDoubleC(params[0])), 0.0);
			composite->map(result);
		}
		else if(subtransform[0] == "skewy")
		{
			result = QMatrix();
			result.shear(0.0, -tan(ScCLocale::toDoubleC(params[0])));
			composite->map(result);
		}
	}
}

void OODPlug::parseViewBox( const QDomElement& object, double *x, double *y, double *w, double *h )
{
	if( !object.attribute( "svg:viewBox" ).isEmpty() )
	{
		QString viewbox( object.attribute( "svg:viewBox" ) );
		QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
		*x = ScCLocale::toDoubleC(points[0]);
		*y = ScCLocale::toDoubleC(points[1]);
		*w = ScCLocale::toDoubleC(points[2]);
		*h = ScCLocale::toDoubleC(points[3]);
	}
}

void OODPlug::appendPoints(FPointArray *composite, const QDomElement& object, bool closePath)
{
	double x = parseUnit(object.attribute("svg:x"));
	double y = parseUnit(object.attribute("svg:y")) ;
	double w = parseUnit(object.attribute("svg:width"));
	double h = parseUnit(object.attribute("svg:height"));
	double vx = 0;
	double vy = 0;
	double vw = 1;
	double vh = 1;
	parseViewBox(object, &vx, &vy, &vw, &vh);
	double sx = (vw != 0.0) ? (w / vw) : w;
	double sy = (vh != 0.0) ? (h / vh) : h;
	QStringList ptList = object.attribute( "draw:points" ).split( ' ', QString::SkipEmptyParts );
	FPoint point, firstP;
	bool bFirst = true;
	for( QStringList::Iterator it = ptList.begin(); it != ptList.end(); ++it )
	{
		point = FPoint(ScCLocale::toDoubleC((*it).section( ',', 0, 0 )), ScCLocale::toDoubleC((*it).section( ',', 1, 1 )));
		if (bFirst)
		{
			composite->addPoint(point);
			composite->addPoint(point);
			firstP = point;
			bFirst = false;
		}
		else
		{
			composite->addPoint(point);
			composite->addPoint(point);
			composite->addPoint(point);
			composite->addPoint(point);
		}
    }
	if (closePath)
	{
		composite->addPoint(firstP);
		composite->addPoint(firstP);
	}
	QMatrix mat;
	mat.translate(x, y);
	mat.scale(sx, sy);
	composite->map(mat);
}

const char * OODPlug::getCoord( const char *ptr, double &number )
{
	int integer, exponent;
	double decimal, frac;
	int sign, expsign;

	exponent = 0;
	integer = 0;
	frac = 1.0;
	decimal = 0;
	sign = 1;
	expsign = 1;

	// read the sign
	if(*ptr == '+')
		ptr++;
	else if(*ptr == '-')
	{
		ptr++;
		sign = -1;
	}

	// read the integer part
	while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
		integer = (integer * 10) + *(ptr++) - '0';
	if(*ptr == '.') // read the decimals
	{
		ptr++;
		while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
			decimal += (*(ptr++) - '0') * (frac *= 0.1);
	}

	if(*ptr == 'e' || *ptr == 'E') // read the exponent part
	{
		ptr++;

		// read the sign of the exponent
		if(*ptr == '+')
			ptr++;
		else if(*ptr == '-')
		{
			ptr++;
			expsign = -1;
		}

		exponent = 0;
		while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
		{
			exponent *= 10;
			exponent += *ptr - '0';
			ptr++;
		}
	}
	number = integer + decimal;
	number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );

	// skip the following space
	if(*ptr == ' ')
		ptr++;

	return ptr;
}

bool OODPlug::parseSVG( const QString &s, FPointArray *ite )
{
	QString d = s;
	d = d.replace( QRegExp( "," ), " ");
	bool ret = false;
	if( !d.isEmpty() )
	{
		d = d.simplified();
		QByteArray data = d.toLatin1();
		const char *ptr = data.constData();
		const char *end = data.constData() + data.length() + 1;
		double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
		double px1, py1, px2, py2, px3, py3;
		bool relative;
		FirstM = true;
		char command = *(ptr++), lastCommand = ' ';
		subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
		while( ptr < end )
		{
			if( *ptr == ' ' )
				ptr++;
			relative = false;
			switch( command )
			{
			case 'm':
				relative = true;
			case 'M':
				{
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					WasM = true;
					subpathx = curx = relative ? curx + tox : tox;
					subpathy = cury = relative ? cury + toy : toy;
					svgMoveTo(curx, cury );
					break;
				}
			case 'l':
				relative = true;
			case 'L':
				{
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					curx = relative ? curx + tox : tox;
					cury = relative ? cury + toy : toy;
					svgLineTo(ite, curx, cury );
					break;
				}
			case 'h':
				{
					ptr = getCoord( ptr, tox );
					curx = curx + tox;
					svgLineTo(ite, curx, cury );
					break;
				}
			case 'H':
				{
					ptr = getCoord( ptr, tox );
					curx = tox;
					svgLineTo(ite, curx, cury );
					break;
				}
			case 'v':
				{
					ptr = getCoord( ptr, toy );
					cury = cury + toy;
					svgLineTo(ite, curx, cury );
					break;
				}
			case 'V':
				{
					ptr = getCoord( ptr, toy );
					cury = toy;
					svgLineTo(ite,  curx, cury );
					break;
				}
			case 'z':
			case 'Z':
				{
//					curx = subpathx;
//					cury = subpathy;
					svgClosePath(ite);
					break;
				}
			case 'c':
				relative = true;
			case 'C':
				{
					ptr = getCoord( ptr, x1 );
					ptr = getCoord( ptr, y1 );
					ptr = getCoord( ptr, x2 );
					ptr = getCoord( ptr, y2 );
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					px1 = relative ? curx + x1 : x1;
					py1 = relative ? cury + y1 : y1;
					px2 = relative ? curx + x2 : x2;
					py2 = relative ? cury + y2 : y2;
					px3 = relative ? curx + tox : tox;
					py3 = relative ? cury + toy : toy;
					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
					contrlx = relative ? curx + x2 : x2;
					contrly = relative ? cury + y2 : y2;
					curx = relative ? curx + tox : tox;
					cury = relative ? cury + toy : toy;
					break;
				}
			case 's':
				relative = true;
			case 'S':
				{
					ptr = getCoord( ptr, x2 );
					ptr = getCoord( ptr, y2 );
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					px1 = 2 * curx - contrlx;
					py1 = 2 * cury - contrly;
					px2 = relative ? curx + x2 : x2;
					py2 = relative ? cury + y2 : y2;
					px3 = relative ? curx + tox : tox;
					py3 = relative ? cury + toy : toy;
					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
					contrlx = relative ? curx + x2 : x2;
					contrly = relative ? cury + y2 : y2;
					curx = relative ? curx + tox : tox;
					cury = relative ? cury + toy : toy;
					break;
				}
			case 'q':
				relative = true;
			case 'Q':
				{
					ptr = getCoord( ptr, x1 );
					ptr = getCoord( ptr, y1 );
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
					py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
					px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
					py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
					px3 = relative ? curx + tox : tox;
					py3 = relative ? cury + toy : toy;
					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
					contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
					contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
					curx = relative ? curx + tox : tox;
					cury = relative ? cury + toy : toy;
					break;
				}
			case 't':
				relative = true;
			case 'T':
				{
					ptr = getCoord(ptr, tox);
					ptr = getCoord(ptr, toy);
					xc = 2 * curx - contrlx;
					yc = 2 * cury - contrly;
					px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
					py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
					px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
					py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
					px3 = relative ? curx + tox : tox;
					py3 = relative ? cury + toy : toy;
					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
					contrlx = xc;
					contrly = yc;
					curx = relative ? curx + tox : tox;
					cury = relative ? cury + toy : toy;
					break;
				}
			case 'a':
				relative = true;
			case 'A':
				{
					bool largeArc, sweep;
					double angle, rx, ry;
					ptr = getCoord( ptr, rx );
					ptr = getCoord( ptr, ry );
					ptr = getCoord( ptr, angle );
					ptr = getCoord( ptr, tox );
					largeArc = tox == 1;
					ptr = getCoord( ptr, tox );
					sweep = tox == 1;
					ptr = getCoord( ptr, tox );
					ptr = getCoord( ptr, toy );
					calculateArc(ite, relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
				}
			}
			lastCommand = command;
			if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
			{
				// there are still coords in this command
				if(command == 'M')
					command = 'L';
				else if(command == 'm')
					command = 'l';
			}
			else
				command = *(ptr++);

			if( lastCommand != 'C' && lastCommand != 'c' &&
			        lastCommand != 'S' && lastCommand != 's' &&
			        lastCommand != 'Q' && lastCommand != 'q' &&
			        lastCommand != 'T' && lastCommand != 't')
			{
				contrlx = curx;
				contrly = cury;
			}
		}
		if ((lastCommand != 'z') && (lastCommand != 'Z'))
			ret = true;
		if (ite->size() > 2)
		{
			if ((ite->point(0).x() == ite->point(ite->size()-2).x()) && (ite->point(0).y() == ite->point(ite->size()-2).y()))
				ret = false;
		}
	}
	return ret;
}

void OODPlug::calculateArc(FPointArray *ite, bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
{
	double sin_th, cos_th;
	double a00, a01, a10, a11;
	double x0, y0, x1, y1, xc, yc;
	double d, sfactor, sfactor_sq;
	double th0, th1, th_arc;
	int i, n_segs;
	sin_th = sin(angle * (M_PI / 180.0));
	cos_th = cos(angle * (M_PI / 180.0));
	double dx;
	if(!relative)
		dx = (curx - x) / 2.0;
	else
		dx = -x / 2.0;
	double dy;
	if(!relative)
		dy = (cury - y) / 2.0;
	else
		dy = -y / 2.0;
	double _x1 =  cos_th * dx + sin_th * dy;
	double _y1 = -sin_th * dx + cos_th * dy;
	double Pr1 = r1 * r1;
	double Pr2 = r2 * r2;
	double Px = _x1 * _x1;
	double Py = _y1 * _y1;
	double check = Px / Pr1 + Py / Pr2;
	if(check > 1)
	{
		r1 = r1 * sqrt(check);
		r2 = r2 * sqrt(check);
	}
	a00 = cos_th / r1;
	a01 = sin_th / r1;
	a10 = -sin_th / r2;
	a11 = cos_th / r2;
	x0 = a00 * curx + a01 * cury;
	y0 = a10 * curx + a11 * cury;
	if(!relative)
		x1 = a00 * x + a01 * y;
	else
		x1 = a00 * (curx + x) + a01 * (cury + y);
	if(!relative)
		y1 = a10 * x + a11 * y;
	else
		y1 = a10 * (curx + x) + a11 * (cury + y);
	d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
	sfactor_sq = 1.0 / d - 0.25;
	if(sfactor_sq < 0)
		sfactor_sq = 0;
	sfactor = sqrt(sfactor_sq);
	if(sweepFlag == largeArcFlag)
		sfactor = -sfactor;
	xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
	yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);

	th0 = atan2(y0 - yc, x0 - xc);
	th1 = atan2(y1 - yc, x1 - xc);
	th_arc = th1 - th0;
	if(th_arc < 0 && sweepFlag)
		th_arc += 2 * M_PI;
	else if(th_arc > 0 && !sweepFlag)
		th_arc -= 2 * M_PI;
	n_segs = static_cast<int>(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))));
	for(i = 0; i < n_segs; i++)
	{
		{
			double sin_th, cos_th;
			double a00, a01, a10, a11;
			double x1, y1, x2, y2, x3, y3;
			double t;
			double th_half;
			double _th0 = th0 + i * th_arc / n_segs;
			double _th1 = th0 + (i + 1) * th_arc / n_segs;
			sin_th = sin(angle * (M_PI / 180.0));
			cos_th = cos(angle * (M_PI / 180.0));
			a00 = cos_th * r1;
			a01 = -sin_th * r2;
			a10 = sin_th * r1;
			a11 = cos_th * r2;
			th_half = 0.5 * (_th1 - _th0);
			t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
			x1 = xc + cos(_th0) - t * sin(_th0);
			y1 = yc + sin(_th0) + t * cos(_th0);
			x3 = xc + cos(_th1);
			y3 = yc + sin(_th1);
			x2 = x3 + t * sin(_th1);
			y2 = y3 - t * cos(_th1);
			svgCurveToCubic(ite, a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 );
		}
	}
	if(!relative)
		curx = x;
	else
		curx += x;
	if(!relative)
		cury = y;
	else
		cury += y;
}

void OODPlug::svgMoveTo(double x1, double y1)
{
	CurrX = x1;
	CurrY = y1;
	StartX = x1;
	StartY = y1;
	PathLen = 0;
}

void OODPlug::svgLineTo(FPointArray *i, double x1, double y1)
{
	if ((!FirstM) && (WasM))
	{
		i->setMarker();
		PathLen += 4;
	}
	FirstM = false;
	WasM = false;
	if (i->size() > 3)
	{
		FPoint b1 = i->point(i->size()-4);
		FPoint b2 = i->point(i->size()-3);
		FPoint b3 = i->point(i->size()-2);
		FPoint b4 = i->point(i->size()-1);
		FPoint n1 = FPoint(CurrX, CurrY);
		FPoint n2 = FPoint(x1, y1);
		if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2))
			return;
	}
	i->addPoint(FPoint(CurrX, CurrY));
	i->addPoint(FPoint(CurrX, CurrY));
	i->addPoint(FPoint(x1, y1));
	i->addPoint(FPoint(x1, y1));
	CurrX = x1;
	CurrY = y1;
	PathLen += 4;
}

void OODPlug::svgCurveToCubic(FPointArray *i, double x1, double y1, double x2, double y2, double x3, double y3)
{
	if ((!FirstM) && (WasM))
	{
		i->setMarker();
		PathLen += 4;
	}
	FirstM = false;
	WasM = false;
	if (PathLen > 3)
	{
		FPoint b1 = i->point(i->size()-4);
		FPoint b2 = i->point(i->size()-3);
		FPoint b3 = i->point(i->size()-2);
		FPoint b4 = i->point(i->size()-1);
		FPoint n1 = FPoint(CurrX, CurrY);
		FPoint n2 = FPoint(x1, y1);
		FPoint n3 = FPoint(x3, y3);
		FPoint n4 = FPoint(x2, y2);
		if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4))
			return;
	}
	i->addPoint(FPoint(CurrX, CurrY));
	i->addPoint(FPoint(x1, y1));
	i->addPoint(FPoint(x3, y3));
	i->addPoint(FPoint(x2, y2));
	CurrX = x3;
	CurrY = y3;
	PathLen += 4;
}

void OODPlug::svgClosePath(FPointArray *i)
{
	if (PathLen > 2)
	{
		if ((PathLen == 4) || (i->point(i->size()-2).x() != StartX) || (i->point(i->size()-2).y() != StartY))
		{
			i->addPoint(i->point(i->size()-2));
			i->addPoint(i->point(i->size()-3));
			i->addPoint(FPoint(StartX, StartY));
			i->addPoint(FPoint(StartX, StartY));
		}
	}
}

OODPlug::~OODPlug()
{
	delete tmpSel;
	// it's probably needed as QHash() dos not support autocleaning
	m_styles.clear();
	m_draws.clear();
}
