/*
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.
*/
/***************************************************************************
							 -------------------
	begin                : Sun Sep 29 2013
	copyright            : (C) 2013 by Franz Schmid
	email                : Franz.Schmid@altmuehlnet.de
 ***************************************************************************/

#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
#define _USE_MATH_DEFINES
#endif

#include <cstdlib>
#include <climits>
#include <limits>

#include <QByteArray>
#include <QCursor>
#include <QDebug>
#include <QDrag>
#include <QFile>
#include <QList>
#include <QMimeData>
#include <QRegExp>
#include <QScopedPointer>
#include <QStack>
#include <QUrl>

#include "importviva.h"

#include "commonstrings.h"
#include "loadsaveplugin.h"
#include "pageitem_table.h"
#include "pagesize.h"
#include "prefscontext.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "prefstable.h"
#include "rawimage.h"
#include "scclocale.h"
#include "sccolorengine.h"
#include "scconfig.h"
#include "scmimedata.h"
#include "scpaths.h"
#include "scribusXml.h"
#include "scribuscore.h"
#include "scribusdoc.h"
#include "scribusview.h"
#include "sctextstream.h"
#include "selection.h"
#include "ui/customfdialog.h"
#include "ui/missing.h"
#include "ui/multiprogressdialog.h"
#include "ui/propertiespalette.h"
#include "undomanager.h"
#include "util.h"
#include "util_formats.h"
#include "util_math.h"

VivaPlug::VivaPlug(ScribusDoc* doc, int flags)
{
	tmpSel = new Selection(this, false);
	m_Doc = doc;
	importerFlags = flags;
	interactive = (flags & LoadSavePlugin::lfInteractive);
}

double VivaPlug::parseUnit(const QString &unit) const
{
	bool noUnit = false;
	QString unitval = unit;
	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", "");
	if (unitval == unit)
		noUnit = true;
	double value = ScCLocale::toDoubleC(unitval);
	if (unit.right(2) == "pt")
		{} /* value = value; */ //no change
	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 * 0.8;
	else if (noUnit)
		{} /* value = value; */ //no change
	return value;
}

QImage VivaPlug::readThumbnail(const QString& fName)
{
	QImage tmp;
	if (!QFile::exists(fName))
		return QImage();
	progressDialog = nullptr;
	QFileInfo fi(fName);
	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath() + "/"));
	docWidth = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
	docHeight = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
	m_Doc = new ScribusDoc();
	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
	m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
	m_Doc->addPage(0);
	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
	baseX = m_Doc->currentPage()->xOffset();
	baseY = m_Doc->currentPage()->yOffset();
	Elements.clear();
	m_Doc->setLoading(true);
	m_Doc->DoDrawing = false;
	m_Doc->scMW()->setScriptRunning(true);
	QString CurDirP = QDir::currentPath();
	QDir::setCurrent(fi.path());
	if (convert(fName))
	{
		tmpSel->clear();
		QDir::setCurrent(CurDirP);
		if (Elements.count() > 1)
			m_Doc->groupObjectsList(Elements);
		m_Doc->DoDrawing = true;
		m_Doc->m_Selection->delaySignalsOn();
		QImage tmpImage;
		if (!Elements.isEmpty())
		{
			tmpSel->addItems(Elements);
			tmpSel->setGroupRect();
			double xs = tmpSel->width();
			double ys = tmpSel->height();
			tmpImage = Elements.at(0)->DrawObj_toImage(500);
			tmpImage.setText("XSize", QString("%1").arg(xs));
			tmpImage.setText("YSize", QString("%1").arg(ys));
		}
		m_Doc->scMW()->setScriptRunning(false);
		m_Doc->setLoading(false);
		m_Doc->m_Selection->delaySignalsOff();
		delete m_Doc;
		m_Doc = nullptr;
		return tmpImage;
	}
	QDir::setCurrent(CurDirP);
	m_Doc->DoDrawing = true;
	m_Doc->scMW()->setScriptRunning(false);
	delete m_Doc;
	m_Doc = nullptr;
	return tmp;
}

bool VivaPlug::readColors(const QString& fileName, ColorList & colors)
{
	bool success = false;
	m_Doc = new ScribusDoc();
	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
	m_Doc->setPage(1, 1, 0, 0, 0, 0, 0, 0, false, false);
	m_Doc->addPage(0);
	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
	importedColors.clear();
	QByteArray f;
	loadRawText(fileName, f);
	if (designMapDom.setContent(f))
	{
		QDomElement docElem = designMapDom.documentElement();
		for (QDomNode drawPag = docElem.firstChild(); !drawPag.isNull(); drawPag = drawPag.nextSibling() )
		{
			QDomElement dpg = drawPag.toElement();
			if (dpg.tagName() == "vc:colors")
				parseColorsXML(dpg);
		}
	}
	if (!importedColors.isEmpty())
	{
		colors = m_Doc->PageColors;
		success = true;
	}
	delete m_Doc;
	m_Doc = nullptr;
	return success;
}

bool VivaPlug::importFile(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
{
	bool success = false;
	interactive = (flags & LoadSavePlugin::lfInteractive);
	importerFlags = flags;
	cancel = false;
	bool ret = false;
	hasLayers = false;
	firstLayer = true;
	firstPage = true;
	pagecount = 1;
	mpagecount = 0;
	QFileInfo fi(fNameIn);
	if (!ScCore->usingGUI())
	{
		interactive = false;
		showProgress = false;
	}
	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath() + "/"));
	if (showProgress)
	{
		ScribusMainWindow* mw = (m_Doc == nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
		progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
		QStringList barNames, barTexts;
		barNames << "GI";
		barTexts << tr("Analyzing File:");
		QList<bool> barsNumeric;
		barsNumeric << false;
		progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
		progressDialog->setOverallTotalSteps(3);
		progressDialog->setOverallProgress(0);
		progressDialog->setProgress("GI", 0);
		progressDialog->show();
		connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
		QApplication::processEvents();
	}
	else
		progressDialog = nullptr;
	if (progressDialog)
	{
		progressDialog->setOverallProgress(1);
		QApplication::processEvents();
	}
	/* Set default Page to size defined in Preferences */
	docWidth = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
	docHeight = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
	baseX = 0;
	baseY = 0;
	if (m_Doc && (!interactive || (flags & LoadSavePlugin::lfInsertPage)))
	{
		m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
		m_Doc->addPage(0);
		m_Doc->view()->addPage(0, true);
		baseX = 0;
		baseY = 0;
	}
	else if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
	{
		m_Doc = ScCore->primaryMainWindow()->doFileNew(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
		ScCore->primaryMainWindow()->HaveNewDoc();
		ret = true;
		baseX = 0;
		baseY = 0;
		baseX = m_Doc->currentPage()->xOffset();
		baseY = m_Doc->currentPage()->yOffset() + m_Doc->currentPage()->height() / 2.0;
	}
	if (!ret && interactive)
	{
		baseX = m_Doc->currentPage()->xOffset();
		baseY = m_Doc->currentPage()->yOffset() + m_Doc->currentPage()->height() / 2.0;
	}
	if (ret || !interactive)
	{
		if (docWidth > docHeight)
			m_Doc->setPageOrientation(1);
		else
			m_Doc->setPageOrientation(0);
		m_Doc->setPageSize("Custom");
	}
	Elements.clear();
	m_Doc->setLoading(true);
	m_Doc->DoDrawing = false;
	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
		m_Doc->view()->updatesOn(false);
	m_Doc->scMW()->setScriptRunning(true);
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	QString CurDirP = QDir::currentPath();
	QDir::setCurrent(fi.path());
	if (convert(fNameIn))
	{
		tmpSel->clear();
		QDir::setCurrent(CurDirP);
		if ((Elements.count() > 1) && (!(importerFlags & LoadSavePlugin::lfCreateDoc)))
			m_Doc->groupObjectsList(Elements);
		m_Doc->DoDrawing = true;
		m_Doc->scMW()->setScriptRunning(false);
		m_Doc->setLoading(false);
		QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
		if (!Elements.isEmpty() && !ret && interactive)
		{
			if (flags & LoadSavePlugin::lfScripted)
			{
				bool loadF = m_Doc->isLoading();
				m_Doc->setLoading(false);
				m_Doc->changed();
				m_Doc->setLoading(loadF);
				if (!(flags & LoadSavePlugin::lfLoadAsPattern))
				{
					m_Doc->m_Selection->delaySignalsOn();
					m_Doc->m_Selection->addItems(Elements);
					m_Doc->m_Selection->delaySignalsOff();
					m_Doc->m_Selection->setGroupRect();
					m_Doc->view()->updatesOn(true);
				}
			}
			else
			{
				m_Doc->DragP = true;
				m_Doc->DraggedElem = nullptr;
				m_Doc->DragElements.clear();
				m_Doc->m_Selection->delaySignalsOn();
				tmpSel->addItems(Elements);
				tmpSel->setGroupRect();
				ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
				m_Doc->itemSelection_DeleteItem(tmpSel);
				m_Doc->view()->updatesOn(true);
				m_Doc->m_Selection->delaySignalsOff();
				// We must copy the TransationSettings object as it is owned
				// by handleObjectImport method afterwards
				auto* transacSettings = new TransactionSettings(trSettings);
				m_Doc->view()->handleObjectImport(md, transacSettings);
				m_Doc->DragP = false;
				m_Doc->DraggedElem = nullptr;
				m_Doc->DragElements.clear();
			}
		}
		else
		{
			m_Doc->changed();
			m_Doc->reformPages();
			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
				m_Doc->view()->updatesOn(true);
		}
		success = true;
	}
	else
	{
		QDir::setCurrent(CurDirP);
		m_Doc->DoDrawing = true;
		m_Doc->scMW()->setScriptRunning(false);
		if (!(flags & LoadSavePlugin::lfLoadAsPattern))
			m_Doc->view()->updatesOn(true);
		QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
	}
	if (interactive)
		m_Doc->setLoading(false);
	//CB If we have a gui we must refresh it if we have used the progressbar
	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
	{
		if (showProgress && !interactive)
			m_Doc->view()->DrawNew();
	}
	QApplication::restoreOverrideCursor();
	return success;
}

VivaPlug::~VivaPlug()
{
	delete progressDialog;
	delete tmpSel;
}

bool VivaPlug::convert(const QString& fn)
{
	Coords.resize(0);
	Coords.svgInit();
	importedColors.clear();
	facingPages = false;
	if (progressDialog)
	{
		progressDialog->setOverallProgress(2);
		progressDialog->setLabel("GI", tr("Generating Items"));
		QApplication::processEvents();
	}
	bool retVal = true;
	importedColors.clear();
	storyMap.clear();
	QByteArray f;
	loadRawText(fn, f);
	if (designMapDom.setContent(f))
	{
		QDomElement docElem = designMapDom.documentElement();
		for (QDomNode drawPag = docElem.firstChild(); !drawPag.isNull(); drawPag = drawPag.nextSibling())
		{
			QDomElement dpg = drawPag.toElement();
			if (dpg.tagName() == "vd:settings")
				parseSettingsXML(dpg);
			else if (dpg.tagName() == "vc:colors")
				parseColorsXML(dpg);
			else if (dpg.tagName() == "vs:stylesheets")
				parseStylesheetsXML(dpg);
			else if (dpg.tagName() == "vd:preferences")
				parsePreferencesXML(dpg);
			else if (dpg.tagName() == "vd:layer")
				parseLayerXML(dpg);
			else if (dpg.tagName() == "vd:singleAliasPage")
				parseMasterSpreadXML(dpg);
			else if (dpg.tagName() == "vd:doubleAliasPage")
				parseMasterSpreadXML(dpg);
			else if (dpg.tagName() == "vd:spread")
				parseSpreadXML(dpg);
			else if (dpg.tagName() == "vd:textChains")
				parseTextChainsXML(dpg);
		}
	}
	if (progressDialog)
		progressDialog->close();
	return retVal;
}

void VivaPlug::parseSettingsXML(const QDomElement& grNode)
{
	if ((importerFlags & LoadSavePlugin::lfCreateDoc) == 0)
		return;

	topMargin = m_Doc->marginsVal().top();
	leftMargin = m_Doc->marginsVal().left();
	rightMargin = m_Doc->marginsVal().right();
	bottomMargin = m_Doc->marginsVal().bottom();
	double pgCols = m_Doc->PageSp;
	double pgGap = m_Doc->PageSpa;
	papersize = "Custom";
	QString paperOrien = "portrait";
	bool hasPageSize = false;
	for (QDomNode n = grNode.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if (e.tagName() == "vd:pageMargins")
		{
			topMargin = parseUnit(e.attribute("vd:top", "0"));
			leftMargin = parseUnit(e.attribute("vd:left", "0"));
			rightMargin = parseUnit(e.attribute("vd:right", "0"));
			bottomMargin = parseUnit(e.attribute("vd:bottom", "0"));
		}
		else if (e.tagName() == "vd:pageColumns")
		{
			pgCols = e.attribute("vd:count", "1").toInt();
			pgGap = parseUnit(e.attribute("vd:distance", "0"));
		}
		else if (e.tagName() == "vd:pageMode")
			facingPages = e.text() == "doublePage";
		else if (e.tagName() == "vd:pageFormat")
			papersize = e.text();
		else if (e.tagName() == "vd:pageOrientation")
			paperOrien = e.text();
		else if (e.tagName() == "vd:pageSize")
		{
			docWidth = parseUnit(e.attribute("vd:width", "0"));
			docHeight = parseUnit(e.attribute("vd:height", "0"));
			hasPageSize = true;
		}
	}
	PageSize ps(papersize);
	if (hasPageSize)
	{
		if (!paperOrien.startsWith("portrait"))
		{
			double tmp = docWidth;
			docWidth = docHeight;
			docHeight = tmp;
		}
	}
	else
	{
		if (paperOrien.startsWith("portrait"))
		{
			docWidth = ps.width();
			docHeight = ps.height();
		}
		else
		{
			docHeight = ps.width();
			docWidth = ps.height();
		}
	}
	m_Doc->setPage(docWidth, docHeight, topMargin, leftMargin, rightMargin, bottomMargin, pgCols, pgGap, false, facingPages);
	m_Doc->setPageSize(papersize);
	m_Doc->currentPage()->setSize(papersize);
	m_Doc->currentPage()->setInitialHeight(docHeight);
	m_Doc->currentPage()->setInitialWidth(docWidth);
	m_Doc->currentPage()->setHeight(docHeight);
	m_Doc->currentPage()->setWidth(docWidth);
	m_Doc->currentPage()->initialMargins.setTop(topMargin);
	m_Doc->currentPage()->initialMargins.setBottom(bottomMargin);
	m_Doc->currentPage()->initialMargins.setLeft(leftMargin);
	m_Doc->currentPage()->initialMargins.setRight(rightMargin);
	m_Doc->reformPages(true);
}

void VivaPlug::parseColorsXML(const QDomElement& grNode)
{
	for (QDomNode n = grNode.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if (e.tagName() == "vc:color")
		{
			QString colorName = e.attribute("vc:name");
			if (e.hasChildNodes())
			{
				bool seenSpot = false;
				bool seenRegC = false;
				ScColor tmp;
				for (QDomNode gr = e.firstChild(); !gr.isNull(); gr = gr.nextSibling() )
				{
					QDomElement grs = gr.toElement();
					if (grs.tagName() == "vc:rgb")
					{
						int r = grs.attribute("vc:red", "0").toInt();
						int g = grs.attribute("vc:green", "0").toInt();
						int b = grs.attribute("vc:blue", "0").toInt();
						tmp.setRgbColor(r, g, b);
						break;
					}
					if (grs.tagName() == "vc:cmyk")
					{
						int c = grs.attribute("vc:cyan", "0").toInt();
						int m = grs.attribute("vc:magenta", "0").toInt();
						int y = grs.attribute("vc:yellow", "0").toInt();
						int k = grs.attribute("vc:key", "0").toInt();
						tmp.setColor(c, m, y, k);
						break;
					}
					if (grs.tagName() == "vc:lab")
					{
						double L = grs.attribute("vc:l", "100").toDouble();
						double a = grs.attribute("vc:a", "0").toDouble();
						double b = grs.attribute("vc:b", "0").toDouble();
						tmp.setLabColor(L, a, b);
						break;
					}
					if (grs.tagName() == "vc:hsv")
					{
						int h = grs.attribute("vc:hue", "0").toInt();
						int s = grs.attribute("vc:saturation", "0").toInt();
						int v = grs.attribute("vc:value", "0").toInt();
						QColor qc;
						qc.setHsv(h, s, v);
						tmp.fromQColor(qc);
						tmp = ScColorEngine::convertToModel(tmp, m_Doc, colorModelRGB);
						break;
					}
					if (grs.tagName() == "vc:registrationColor")
					{
						seenRegC = true;
						int r = e.attribute("vc:red", "0").toInt();
						int g = e.attribute("vc:green", "0").toInt();
						int b = e.attribute("vc:blue", "0").toInt();
						tmp.setRgbColor(r, g, b);
						break;
					}
					if (grs.tagName() == "vc:spotColor")
						seenSpot = true;
				}
				tmp.setSpotColor(seenSpot);
				tmp.setRegistrationColor(seenRegC);
				QString fNam = m_Doc->PageColors.tryAddColor(colorName, tmp);
				if (fNam == colorName)
					importedColors.append(fNam);
				colorTranslate.insert(colorName, fNam);
			}
			else
			{
				int r = e.attribute("vc:red", "0").toInt();
				int g = e.attribute("vc:green", "0").toInt();
				int b = e.attribute("vc:blue", "0").toInt();
				ScColor tmp;
				tmp.setRgbColor(r, g, b);
				tmp.setSpotColor(false);
				tmp.setRegistrationColor(false);
				QString fNam = m_Doc->PageColors.tryAddColor(colorName, tmp);
				if (fNam == colorName)
					importedColors.append(fNam);
				colorTranslate.insert(colorName, fNam);
			}
		}
		else if (e.tagName() == "vc:gradient")
		{
			QString grName = e.attribute("vc:name");
			QString grSelf = grName;
			int grTyp = 6;
			if (e.attribute("vc:type") == "linear")
				grTyp =6;
			else if (e.attribute("vc:type") == "radial")
				grTyp = 7;
			else if (e.attribute("vc:type") == "rectangle")
				grTyp = 10;
			VGradient currentGradient(VGradient::linear);
			currentGradient.clearStops();
			for (QDomNode gr = e.firstChild(); !gr.isNull(); gr = gr.nextSibling())
			{
				QDomElement grs = gr.toElement();
				if ((grs.tagName() == "vc:firstColor") || (grs.tagName() == "vc:secondColor"))
				{
					QString stopName = grs.attribute("vc:name");
					int tint = 0;
					if (grs.attribute("vc:density") == "transparent")
						tint = 0;
					else
						tint = grs.attribute("vc:density").toInt();
					if (colorTranslate.contains(stopName))
						stopName = colorTranslate[stopName];
					else
						stopName = "Black";
					const ScColor& gradC = m_Doc->PageColors[stopName];
					if (grTyp == 6)
					{
						if (grs.tagName() == "vc:firstColor")
							currentGradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), 0.0, 0.5, 1.0, stopName, tint );
						else
							currentGradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), 1.0, 0.5, 1.0, stopName, tint );
					}
					else
					{
						if (grs.tagName() == "vc:firstColor")
							currentGradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), 1.0, 0.5, 1.0, stopName, tint );
						else
							currentGradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), 0.0, 0.5, 1.0, stopName, tint );
					}
				}
			}
			if (m_Doc->addGradient(grName, currentGradient))
				importedGradients.append(grName);
			gradientTranslate.insert(grSelf, grName);
			gradientTypeMap.insert(grName, grTyp);
		}
	}
}

void VivaPlug::parsePreferencesXML(const QDomElement& spNode)
{
	if ((importerFlags & LoadSavePlugin::lfCreateDoc) == 0)
		return;

	for (QDomNode n = spNode.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if (e.tagName() != "vd:text")
			continue;

		for (QDomNode spo = e.firstChild(); !spo.isNull(); spo = spo.nextSibling())
		{
			QDomElement eo = spo.toElement();
			if (eo.tagName() == "vd:superscriptVerticalOffset")
				m_Doc->typographicPrefs().valueSuperScript = eo.text().toInt();
			else if (eo.tagName() == "vd:superscriptCharacterHeight")
				m_Doc->typographicPrefs().scalingSuperScript = eo.text().toInt();
			else if (eo.tagName() == "vd:subscriptVerticalOffset")
				m_Doc->typographicPrefs().valueSubScript = eo.text().toInt();
			else if (eo.tagName() == "vd:subscriptCharacterHeight")
				m_Doc->typographicPrefs().scalingSubScript = eo.text().toInt();
			else if (eo.tagName() == "vd:smallCapsCharacterHeight")
				m_Doc->typographicPrefs().valueSmallCaps = eo.text().toInt();
		}
	}
}

void VivaPlug::parseLayerXML(const QDomElement& spNode)
{
	if (importerFlags & LoadSavePlugin::lfCreateDoc)
	{
		QString layerName = spNode.attribute("vd:name");
		bool printable = true;
		bool visible = true;
		bool locked = false;
		bool flow = false;
		int rc = 0;
		int gc = 0;
		int bc = 0;
		for (QDomNode n = spNode.firstChild(); !n.isNull(); n = n.nextSibling() )
		{
			QDomElement e = n.toElement();
			if (e.tagName() == "vd:print")
				printable = e.text() == "true";
			if (e.tagName() == "vd:hidden")
				visible = e.text() == "false";
			if (e.tagName() == "vd:locked")
				locked = e.text() == "true";
			if (e.tagName() == "vd:keepRunaround")
				flow = e.text() == "true";
			if (e.tagName() == "vd:color")
			{
				rc = e.attribute("vd:red", "0").toInt();
				gc = e.attribute("vd:green", "0").toInt();
				bc = e.attribute("vd:blue", "0").toInt();
			}
		}
		int currentLayer = m_Doc->activeLayer();
		if (!firstLayer)
			currentLayer = m_Doc->addLayer(layerName);
		else
			m_Doc->changeLayerName(currentLayer, layerName);
		m_Doc->setLayerVisible(currentLayer, visible);
		m_Doc->setLayerLocked(currentLayer, locked);
		m_Doc->setLayerPrintable(currentLayer, printable);
		m_Doc->setLayerFlow(currentLayer, flow);
		m_Doc->setLayerMarker(currentLayer, QColor(rc, gc, bc));
	}
	firstLayer = false;
}

void VivaPlug::parseMasterSpreadXML(const QDomElement& spNode)
{
	if ((importerFlags & LoadSavePlugin::lfCreateDoc) == 0)
		return;

	bool firstSpread = true;
	m_Doc->setMasterPageMode(true);
	ScPage *oldCur = m_Doc->currentPage();
	for (QDomNode n = spNode.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QString pageNam = spNode.attribute("vd:name");
		QDomElement e = n.toElement();
		if (e.tagName() != "vd:aliasPage")
			continue;

		if (spNode.tagName() == "vd:doubleAliasPage")
		{
			mspreadTypes.insert(pageNam, 1);
			if (firstSpread)
				pageNam += "_Left";
			else
				pageNam += "_Right";
		}
		else
			mspreadTypes.insert(pageNam, 0);
		ScPage *addedPage = m_Doc->addMasterPage(mpagecount, pageNam);
		m_Doc->setCurrentPage(addedPage);
		addedPage->clearMasterPageName();
		m_Doc->view()->addPage(mpagecount, true);
		baseX = addedPage->xOffset();
		baseY = addedPage->yOffset();
		mpagecount++;
		for (QDomNode spo = e.firstChild(); !spo.isNull(); spo = spo.nextSibling())
		{
			QDomElement eo = spo.toElement();
			if (eo.tagName() == "vo:object")
			{
				PageItem* ite = parseObjectXML(eo);
				if (ite == nullptr)
					continue;
				m_Doc->Items->append(ite);
				Elements.append(ite);
			}
		}
		firstSpread = false;
	}
	m_Doc->setCurrentPage(oldCur);
	m_Doc->setMasterPageMode(false);
}

void VivaPlug::parseSpreadXML(const QDomElement& spNode)
{
	for (QDomNode n = spNode.firstChild(); !n.isNull(); n = n.nextSibling() )
	{
		QDomElement e = n.toElement();
		if (e.tagName() != "vd:page")
			continue;

		if ((importerFlags & LoadSavePlugin::lfCreateDoc) && (!firstPage))
		{
			m_Doc->addPage(pagecount);
			m_Doc->currentPage()->setSize(papersize);
			m_Doc->currentPage()->setInitialHeight(docHeight);
			m_Doc->currentPage()->setInitialWidth(docWidth);
			m_Doc->currentPage()->setHeight(docHeight);
			m_Doc->currentPage()->setWidth(docWidth);
			m_Doc->currentPage()->initialMargins.setTop(topMargin);
			m_Doc->currentPage()->initialMargins.setBottom(bottomMargin);
			m_Doc->currentPage()->initialMargins.setLeft(leftMargin);
			m_Doc->currentPage()->initialMargins.setRight(rightMargin);
			m_Doc->currentPage()->setMasterPageNameNormal();
			m_Doc->view()->addPage(pagecount, true);
			pagecount++;
		}
		baseX = m_Doc->currentPage()->xOffset();
		baseY = m_Doc->currentPage()->yOffset();
		for (QDomNode sp = e.firstChild(); !sp.isNull(); sp = sp.nextSibling())
		{
			QDomElement spe = sp.toElement();
			if (spe.tagName() == "vd:content")
			{
				for (QDomNode spo = spe.firstChild(); !spo.isNull(); spo = spo.nextSibling())
				{
					QDomElement eo = spo.toElement();
					if (eo.tagName() == "vo:object")
					{
						PageItem* ite = parseObjectXML(eo);
						if (ite != nullptr)
						{
							m_Doc->Items->append(ite);
							Elements.append(ite);
						}
					}
				}
			}
			else if (spe.tagName() == "vd:column")
			{
				if ((importerFlags & LoadSavePlugin::lfCreateDoc) && firstPage)
				{
					if (spe.text() == "1")
						m_Doc->setPageSetFirstPage(m_Doc->pagePositioning(), 0);
					else
						m_Doc->setPageSetFirstPage(m_Doc->pagePositioning(), 1);
					m_Doc->reformPages(false);
					baseX = m_Doc->currentPage()->xOffset();
					baseY = m_Doc->currentPage()->yOffset();
				}
				if (importerFlags & LoadSavePlugin::lfCreateDoc)
				{
					QString mpage = e.attribute("vd:aliasPageName");
					int mType = mspreadTypes[mpage];
					if (mType == 1)
					{
						if (facingPages == 1)
						{
							if (spe.text() == "1")
								mpage += "_Left";
							else
								mpage += "_Right";
						}
					}
					m_Doc->applyMasterPage(mpage, m_Doc->currentPageNumber());
				}
			}
		}
		firstPage = false;
	}
}

void VivaPlug::parseTextChainsXML(const QDomElement& obNode)
{
	if (storyMap.isEmpty())
		return;
	QDomElement eo = obNode.toElement();
	for (QDomNode ob = eo.firstChild(); !ob.isNull(); ob = ob.nextSibling())
	{
		QDomElement obe = ob.toElement();
		if (obe.tagName() != "vd:sequence")
			continue;

		QList<PageItem*> GElements;
		for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
		{
			QDomElement eog = obg.toElement();
			if (eog.tagName() == "vd:object")
			{
				QString id = eog.attribute("vd:id");
				if (storyMap.contains(id))
					GElements.append(storyMap[id]);
			}
		}

		if (GElements.count() < 2)
			continue;

		PageItem *first = GElements[0];
		for (int a = 1; a < GElements.count(); a++)
		{
			PageItem *next = GElements[a];
			first->link(next);
			next->setColumns(first->columns());
			next->setColumnGap(first->columnGap());
			first = next;
		}
	}
}

PageItem* VivaPlug::parseObjectXML(const QDomElement& obNode)
{
	PageItem *retObj = nullptr;
	QDomElement eo = obNode.toElement();
	QString id = eo.attribute("vo:id");
	for (QDomNode ob = eo.firstChild(); !ob.isNull(); ob = ob.nextSibling())
	{
		QDomElement obe = ob.toElement();
		if (obe.tagName() == "vo:groupObject")
		{
			QList<PageItem*> GElements;
			double ob_xpos = 0;
			double ob_ypos = 0;
			for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
			{
				QDomElement eog = obg.toElement();
				if (eog.tagName() == "vo:object")
				{
					PageItem *gItem = parseObjectXML(eog);
					if (gItem != nullptr)
						GElements.append(gItem);
				}
				else if (eog.tagName() == "vo:transformation")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:translationX")
							ob_xpos = parseUnit(eo.text());
						else if (eo.tagName() == "vo:translationY")
							ob_ypos = parseUnit(eo.text());
					}
				}
			}
			if (!GElements.isEmpty())
			{
				double minx =  std::numeric_limits<double>::max();
				double miny =  std::numeric_limits<double>::max();
				double maxx = -std::numeric_limits<double>::max();
				double maxy = -std::numeric_limits<double>::max();
				bool groupClip = true;
				for (int ep = 0; ep < GElements.count(); ++ep)
				{
					const PageItem* currItem = GElements.at(ep);
					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);
					if (currItem->hasSoftShadow())
						groupClip = false;
				}
				double gx = minx;
				double gy = miny;
				double gw = maxx - minx;
				double gh = maxy - miny;
				int z = m_Doc->itemAdd(PageItem::Group, PageItem::Rectangle, gx, gy, gw, gh, 0, CommonStrings::None, CommonStrings::None);
				if (z >= 0)
				{
					retObj = m_Doc->Items->at(z);
					retObj->ClipEdited = true;
					retObj->FrameType = 3;
					retObj->setFillEvenOdd(false);
					retObj->OldB2 = retObj->width();
					retObj->OldH2 = retObj->height();
					retObj->updateClip();
					m_Doc->groupObjectsToItem(retObj, GElements);
					retObj->setGroupClipping(groupClip);
					retObj->moveBy(ob_xpos, ob_ypos, true);
					m_Doc->adjustItemSize(retObj);
					retObj->OwnPage = m_Doc->OnPage(retObj);
					m_Doc->GroupOnPage(retObj);
					m_Doc->Items->removeLast();
				}
			}
		}
		else if (obe.tagName() == "vo:graphicObject")
			retObj = parseObjectDetailsXML(obe, 0);
		else if (obe.tagName() == "vo:pictureObject")
			retObj = parseObjectDetailsXML(obe, 1);
		else if (obe.tagName() == "vo:textObject")
		{
			retObj = parseObjectDetailsXML(obe, 2);
			storyMap.insert(id, retObj);
		}
	}
	return retObj;
}

PageItem* VivaPlug::parseObjectDetailsXML(const QDomElement& obNode, int baseType)
{
	PageItem *retObj = nullptr;
	QDomElement eo = obNode.toElement();
	double ob_width = 0;
	double ob_height = 0;
	double ob_xpos = 0;
	double ob_ypos = 0;
	double ob_rotation = 0;
	QString fillColor = CommonStrings::None;
	QString strokeColor = CommonStrings::None;
	QString fillGradient;
	int fillGradientTyp = 6;
	int fillTint = 100;
	int strokeTint = 100;
	double lineWidth = 0;
	double fillOpacity = 0.0;
	double strokeOpacity = 0.0;
	double imageOpacity = 0.0;
	double gradientAngle = 0.0;
	double imageXoffs = 0;
	double imageYoffs = 0;
	double imageScaleX = 1.0;
//	double imageScaleY = 1.0;
	double cornerRadius = 0.0;
	int ob_type = 0;
	bool printable = false;
	bool locked = false;
	bool resizable = false;
	FPointArray Path;
	Path.resize(0);
	QString imageFile;
	QByteArray imageData;
	imageData.resize(0);
	QVector<double> DashValues;
	DashValues.clear();
	int LineStyle = 0;
	int ArrowLeft = 1;
	int ArrowRight = 1;
	double textMarginLeft = 0.0;
	double textMarginRight = 0.0;
	double textMarginTop = 0.0;
	double textMarginBottom = 0.0;
	double textColumnGap = 0.0;
	int textColumnCount = 1;
	bool hasShadow = false;
	double shadowX = 0.0;
	double shadowY = 0.0;
	double shadowBlur = 0.0;
	double shadowOpacity = 0.0;
	int shadowTint = 100;
	bool shadowErase = false;
	bool shadowObjTrans = false;
	QString shadowColor = "Black";
	StoryText itemText;
	itemText.clear();
	PageItem::TextFlowMode textFlow = PageItem::TextFlowDisabled;
	for (QDomNode ob = eo.firstChild(); !ob.isNull(); ob = ob.nextSibling())
	{
		QDomElement obe = ob.toElement();
		if ((obe.tagName() == "vo:rectangle") || (obe.tagName() == "vo:oval") || (obe.tagName() == "vo:polygon") || (obe.tagName() == "vo:line") || (obe.tagName() == "vo:polyline"))
		{
			if (obe.tagName() == "vo:rectangle")
				ob_type = 0;
			if (obe.tagName() == "vo:oval")
				ob_type = 1;
			if (obe.tagName() == "vo:polygon")
				ob_type = 2;
			if (obe.tagName() == "vo:line")
				ob_type = 3;
			if (obe.tagName() == "vo:polyline")
				ob_type = 4;
			for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
			{
				QDomElement eog = obg.toElement();
				if (eog.tagName() == "vo:size")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:width")
							ob_width = parseUnit(eo.text());
						else if (eo.tagName() == "vo:height")
							ob_height = parseUnit(eo.text());
					}
				}
				else if (eog.tagName() == "vo:transformation")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:translationX")
							ob_xpos = parseUnit(eo.text());
						else if (eo.tagName() == "vo:translationY")
							ob_ypos = parseUnit(eo.text());
						else if (eo.tagName() == "vo:rotation")
							ob_rotation = eo.text().toDouble();
					}
				}
				else if (eog.tagName() == "vo:design")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:lineColor")
							strokeColor = colorTranslate[eo.text()];
						else if (eo.tagName() == "vo:fillColor")
						{
							if (colorTranslate.contains(eo.text()))
								fillColor = colorTranslate[eo.text()];
							else if (gradientTranslate.contains(eo.text()))
							{
								fillGradient = gradientTranslate[eo.text()];
								fillGradientTyp = gradientTypeMap[fillGradient];
							}
						}
						else if (eo.tagName() == "vo:lineDensity")
						{
							if (eo.text() == "transparent")
								strokeTint = 0;
							else if (eo.text() == "opaque")
								strokeTint = 100;
							else
								strokeTint = eo.text().toInt();
						}
						else if (eo.tagName() == "vo:fillDensity")
						{
							if (eo.text() == "transparent")
								fillTint = 0;
							else if (eo.text() == "opaque")
								fillTint = 100;
							else
								fillTint = eo.text().toInt();
						}
						else if (eo.tagName() == "vo:lineWidth")
							lineWidth = parseUnit(eo.text());
						else if (eo.tagName() == "vo:lineStyle")
						{
							QString Lstyle = eo.text();
							if (Lstyle != "Solid")
							{
								if (Lstyle == "2")
									DashValues << 3 << 2;
								else if (Lstyle == "3")
									LineStyle = 15;
								else if (Lstyle == "4")
									DashValues << 5 << 2.2 << 1 << 2.2;
								else if (Lstyle == "5")
									LineStyle = 6;
								else if (Lstyle == "6")
									DashValues << 2 << 3.1;
								else if ((Lstyle == "7") || (Lstyle == "10"))
									LineStyle = 21;
								else if (Lstyle == "8")
									DashValues << 4 << 3.2 << 0.2 << 3.2;
								else if (Lstyle == "9")
									DashValues << 0.2 << 2;
							}
						}
						else if (eo.tagName() == "vo:startCap")
						{
							ArrowLeft = eo.text().toInt();
							if (ArrowLeft == 2)
								ArrowLeft = 3;
							else if (ArrowLeft == 3)
								ArrowLeft = 18;
							else if (ArrowLeft == 4)
								ArrowLeft = 6;
						}
						else if (eo.tagName() == "vo:endCap")
						{
							ArrowRight = eo.text().toInt();
							if (ArrowRight == 2)
								ArrowRight = 3;
							else if (ArrowRight == 3)
								ArrowRight = 18;
							else if (ArrowRight == 4)
								ArrowRight = 6;
						}
						else if (eo.tagName() == "vo:blendAngle")
							gradientAngle = eo.text().toDouble();
						else if (eo.tagName() == "vo:fillOpacity")
						{
							if (eo.text() == "transparent")
								fillOpacity = 1;
							else if (eo.text() == "opaque")
								fillOpacity = 0;
							else
								fillOpacity = 1.0 - (eo.text().toDouble() / 100.0);
						}
						else if (eo.tagName() == "vo:lineOpacity")
						{
							if (eo.text() == "transparent")
								strokeOpacity = 1;
							else if (eo.text() == "opaque")
								strokeOpacity = 0;
							else
								strokeOpacity = 1.0 - (eo.text().toDouble() / 100.0);
						}
						else if (eo.tagName() == "vo:baseOpacity")
						{
							double opa = 0.0;
							if (eo.text() == "transparent")
								opa = 1;
							else if (eo.text() == "opaque")
								opa = 0;
							else
								opa = 1.0 - (eo.text().toDouble() / 100.0);
							fillOpacity = 1.0 - ((1.0 - fillOpacity) * (1.0 - opa));
							strokeOpacity = 1.0 - ((1.0 - strokeOpacity) * (1.0 - opa));
						}
						else if (eo.tagName() == "vo:cornerRadius")
							cornerRadius = parseUnit(eo.text());
					}
				}
				else if (eog.tagName() == "vo:points")
				{
					Path.resize(0);
					bool hasBefore = false;
					bool hasAfter = false;
					triplePoint triPoint;
					QList<triplePoint> tPoints;
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:point")
						{
							FPoint pp(parseUnit(eo.attribute("vo:x", "0")), parseUnit(eo.attribute("vo:y", "0")));
							if (eo.hasAttribute("vo:control"))
							{
								if ((eo.attribute("vo:control") == "constraint-before") || (eo.attribute("vo:control") == "before"))
									hasBefore = true;
								else if ((eo.attribute("vo:control") == "constraint-after") || (eo.attribute("vo:control") == "after"))
									hasAfter = true;
							}
							if (hasBefore && ((eo.attribute("vo:control") == "constraint-before") || (eo.attribute("vo:control") == "before")))
								triPoint.beforePolyPoint = pp;
							else if (hasAfter && hasBefore)
							{
								triPoint.afterPolyPoint = pp;
								tPoints.append(triPoint);
								hasBefore = false;
								hasAfter = false;
							}
							else if (hasBefore)
								triPoint.PolyPoint = pp;
							else
							{
								triPoint.beforePolyPoint = pp;
								triPoint.PolyPoint = pp;
								triPoint.afterPolyPoint = pp;
								tPoints.append(triPoint);
								hasBefore = false;
								hasAfter = false;
							}
						}
					}
					if (!tPoints.isEmpty())
					{
						if (ob_type == 2)
						{
							Path.addPoint(tPoints[0].PolyPoint);
							Path.addPoint(tPoints[0].afterPolyPoint);
							for (int ppx = 1; ppx < tPoints.count(); ppx++)
							{
								Path.addPoint(tPoints[ppx].PolyPoint);
								Path.addPoint(tPoints[ppx].beforePolyPoint);
								Path.addPoint(tPoints[ppx].PolyPoint);
								Path.addPoint(tPoints[ppx].afterPolyPoint);
							}
							Path.addPoint(tPoints[0].PolyPoint);
							Path.addPoint(tPoints[0].beforePolyPoint);
						}
						else if (ob_type == 3)
						{
							Path.addPoint(tPoints[0].PolyPoint);
							Path.addPoint(tPoints[0].PolyPoint);
							Path.addPoint(tPoints[1].PolyPoint);
							Path.addPoint(tPoints[1].PolyPoint);
						}
						else if (ob_type == 4)
						{
							Path.addPoint(tPoints[0].PolyPoint);
							Path.addPoint(tPoints[0].afterPolyPoint);
							for (int ppx = 1; ppx < tPoints.count() - 1; ppx++)
							{
								Path.addPoint(tPoints[ppx].PolyPoint);
								Path.addPoint(tPoints[ppx].beforePolyPoint);
								Path.addPoint(tPoints[ppx].PolyPoint);
								Path.addPoint(tPoints[ppx].afterPolyPoint);
							}
							Path.addPoint(tPoints.last().PolyPoint);
							Path.addPoint(tPoints.last().beforePolyPoint);
						}
					}
				}
				else if (eog.tagName() == "vo:shadow")
				{
					hasShadow = true;
					double shadowAngle = 0;
					double shadowOffset = 0;
					for (QDomElement spo = eog.firstChildElement(); !spo.isNull(); spo = spo.nextSiblingElement())
					{
						if (spo.tagName() == "uni:color")
							shadowColor = colorTranslate[spo.text()];
						else if (spo.tagName() == "uni:opacity")
						{
							if (spo.text() == "transparent")
								shadowOpacity = 1;
							else if (spo.text() == "opaque")
								shadowOpacity = 0;
							else
								shadowOpacity = 1.0 - (spo.text().toDouble() / 100.0);
						}
						else if (spo.tagName() == "uni:density")
						{
							if (spo.text() == "transparent")
								shadowTint = 0;
							else if (spo.text() == "opaque")
								shadowTint = 100;
							else
								shadowTint = spo.text().toInt();
						}
						else if (spo.tagName() == "uni:angle")
							shadowAngle = spo.text().toDouble();
						else if (spo.tagName() == "uni:offset")
							shadowOffset = parseUnit(spo.text());
						else if (spo.tagName() == "uni:softValue")
							shadowBlur = parseUnit(spo.text());
						else if (spo.tagName() == "uni:coverShadow")
							shadowErase = (spo.text() == "true");
						else if (spo.tagName() == "uni:applyElementOpacity")
							shadowObjTrans = (spo.text() == "true");
					}
					QLineF oLine(0, 0, shadowOffset, 0);
					oLine.setAngle(shadowAngle - 180.0);
					shadowX = oLine.p2().x();
					shadowY = oLine.p2().y();
				}
			}
		}
		else if (obe.tagName() == "vo:properties")
		{
			for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
			{
				QDomElement eog = obg.toElement();
				if (eog.tagName() == "vo:printable")
					printable = eog.text() == "true";
				else if (eog.tagName() == "vo:protected")
					locked = eog.text() == "true";
				else if (eog.tagName() == "vo:fixed")
					resizable = eog.text() == "true";
			}
		}
		else if (obe.tagName() == "vo:runaround")
		{
			if ((obe.attribute("vo:mode") == "all") || (obe.attribute("vo:mode") == "left") || (obe.attribute("vo:mode") == "right"))
			{
				textFlow = PageItem::TextFlowUsesFrameShape;
				for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
				{
					QDomElement eog = obg.toElement();
					if (eog.tagName() == "vo:shape")
					{
						textFlow = PageItem::TextFlowUsesFrameShape;
						break;
					}
					if (eog.tagName() == "vo:block")
					{
						textFlow = PageItem::TextFlowUsesBoundingBox;
						break;
					}
				}
			}
		}
		else if (obe.tagName() == "vo:content")
		{
			for (QDomNode obg = obe.firstChild(); !obg.isNull(); obg = obg.nextSibling())
			{
				QDomElement eog = obg.toElement();
				if (eog.tagName() == "vo:filePath")
				{
					QString fileP = eog.text();
					QFileInfo fp(fileP);
					if (fp.exists())
						imageFile = fileP;
					else
					{
						QString  fileName = fp.fileName();
						QFileInfo fi2(fileName);
						if (fi2.exists())
							imageFile = fileName;
						else
							imageFile = fileP;
					}
				}
				else if (eog.tagName() == "vo:fillOpacity")
				{
					if (eog.text() == "transparent")
						imageOpacity = 1;
					else if (eog.text() == "opaque")
						imageOpacity = 0;
					else
						imageOpacity = 1.0 - (eog.text().toDouble() / 100.0);
				}
				else if (eog.tagName() == "vo:transformation")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "vo:translationX")
							imageXoffs = parseUnit(eo.text());
						else if (eo.tagName() == "vo:translationY")
							imageYoffs = parseUnit(eo.text());
						else if (eo.tagName() == "vo:scaleHorizontal")
							imageScaleX = eo.text().toDouble() / 100.0;
					//	else if (eo.tagName() == "vo:scaleVertical")
					//		imageScaleY = eo.text().toDouble() / 100.0;
					}
				}
				else if (eog.tagName() == "vo:preview")
					imageData = QByteArray::fromBase64(eog.text().toLatin1());
				else if (eog.tagName() == "vo:areaStructure")
				{
					for (QDomNode spo = eog.firstChild(); !spo.isNull(); spo = spo.nextSibling())
					{
						QDomElement eo = spo.toElement();
						if (eo.tagName() == "uni:indents")
						{
							for (QDomNode stx = eo.firstChild(); !stx.isNull(); stx = stx.nextSibling())
							{
								QDomElement stxe = stx.toElement();
								if (stxe.tagName() == "uni:left")
									textMarginLeft = parseUnit(stxe.text());
								else if (stxe.tagName() == "uni:right")
									textMarginRight = parseUnit(stxe.text());
								else if (stxe.tagName() == "uni:top")
									textMarginTop = parseUnit(stxe.text());
								else if (stxe.tagName() == "uni:bottom")
									textMarginBottom = parseUnit(stxe.text());
							}
						}
						else if (eo.tagName() == "uni:columns")
						{
							for (QDomNode stx = eo.firstChild(); !stx.isNull(); stx = stx.nextSibling())
							{
								QDomElement stxe = stx.toElement();
								if (stxe.tagName() == "uni:distance")
									textColumnGap = parseUnit(stxe.text());
								else if (stxe.tagName() == "uni:count")
									textColumnCount = stxe.text().toInt();
							}
						}
					}
				}
				else if (eog.tagName() == "vtr:vivaText")
				{
					itemText.setDoc(m_Doc);
					parseTextXML(eog, itemText, textColumnCount, textColumnGap);
				}
			}
		}
	}
	int z = -1;
	if (baseType == 0)
	{
		if (ob_type == 0)
			z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 1)
			z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 2)
			z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 3)
			z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 4)
			z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
	}
	else if (baseType == 1)
	{
		if (ob_type == 0)
			z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Rectangle, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 1)
			z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Ellipse, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 2)
			z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
	}
	else if (baseType == 2)
	{
		if (ob_type == 0)
			z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 1)
			z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Ellipse, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
		else if (ob_type == 2)
			z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, baseX, baseY, ob_width, ob_height, lineWidth, fillColor, strokeColor);
	}
	if (z >= 0)
	{
		PageItem* item = m_Doc->Items->at(z);
		item->setTextFlowMode(textFlow);
		if (((ob_type == 2) || (ob_type == 3) || (ob_type == 4)) && !Path.isEmpty())
		{
			item->PoLine = Path.copy();
			FPoint wh = getMaxClipF(&item->PoLine);
			item->setWidthHeight(wh.x(),wh.y());
			m_Doc->adjustItemSize(item, true);
		}
		item->ClipEdited = true;
		if ((cornerRadius != 0) && (item->frameType() == PageItem::Rectangle))
		{
			item->setCornerRadius(cornerRadius);
			item->SetFrameRound();
		}
		else
			item->FrameType = 3;
		if (fillTint == 0)
		{
			item->setFillColor(CommonStrings::None);
			item->setFillShade(100);
		}
		else
		{
			item->setFillColor(fillColor);
			item->setFillShade(fillTint);
		}
		if (strokeTint == 0)
		{
			item->setLineColor(CommonStrings::None);
			item->setLineShade(100);
		}
		else
		{
			item->setLineColor(strokeColor);
			item->setLineShade(strokeTint);
		}
		if (baseType == 1)
			item->setFillTransparency(imageOpacity);
		else
			item->setFillTransparency(fillOpacity);
		item->setLineTransparency(strokeOpacity);
		if (!fillGradient.isEmpty())
		{
			QLineF gradientVectorE;
			gradientVectorE.setP1(QPointF(item->width() / 2.0, item->height() / 2.0));
			gradientVectorE.setAngle(gradientAngle);
			gradientVectorE.setLength(sqrt(item->width() * item->width() + item->height() * item->height()) / 2.0 + 1.0);
			QPointF gradEnd = intersectBoundingRect(item, gradientVectorE);
			QLineF gradientVectorS;
			gradientVectorS.setP1(QPointF(item->width() / 2.0, item->height() / 2.0));
			gradientVectorS.setAngle(gradientAngle + 180);
			gradientVectorS.setLength(sqrt(item->width() * item->width() + item->height() * item->height()) / 2.0 + 1.0);
			QPointF gradStart = intersectBoundingRect(item, gradientVectorS);
			item->fill_gradient = m_Doc->docGradients[fillGradient];
			if (fillGradientTyp == 6)
			{
				item->setGradientVector(gradStart.x(), gradStart.y(), gradEnd.x(), gradEnd.y(), gradStart.x(), gradStart.y(), 1, 0);
				item->setGradient(fillGradient);
				item->setGradientType(fillGradientTyp);
			}
			else if (fillGradientTyp == 7)
			{
				QList<VColorStop*> colorStops = item->fill_gradient.colorStops();
				QString gradColor2Str = colorStops[0]->name;
				QColor gradColor2 = colorStops[0]->color;
				QString gradColor1Str = colorStops[1]->name;
				QColor gradColor1 = colorStops[1]->color;
				item->meshGradientPatches.clear();
				FPoint center(item->width() / 2.0, item->height() / 2.0);
				MeshPoint cP;
				cP.resetTo(center);
				cP.transparency = 1.0;
				cP.shade = 100;
				cP.colorName = gradColor2Str;
				cP.color = gradColor2;
				for (int poi = 0; poi < item->PoLine.size()-3; poi += 4)
				{
					meshGradientPatch patch;
					patch.BL = cP;
					patch.BR = cP;
					if (item->PoLine.isMarker(poi))
						continue;
					MeshPoint tL;
					tL.resetTo(item->PoLine.point(poi));
					tL.controlRight = item->PoLine.point(poi + 1);
					tL.transparency = 1.0;
					tL.shade = 100;
					tL.colorName = gradColor1Str;
					tL.color = gradColor1;
					MeshPoint tR;
					tR.resetTo(item->PoLine.point(poi + 2));
					tR.controlLeft = item->PoLine.point(poi + 3);
					tR.transparency = 1.0;
					tR.shade = 100;
					tR.colorName = gradColor1Str;
					tR.color = gradColor1;
					patch.TL = tL;
					patch.TR = tR;
					item->meshGradientPatches.append(patch);
				}
				item->GrType = Gradient_PatchMesh;
			}
			else
			{
				item->GrControl1 = FPoint(0, 0);
				item->GrControl2 = FPoint(item->width(), 0);
				item->GrControl3 = FPoint(item->width(), item->height());
				item->GrControl4 = FPoint(0, item->height());
				if (gradientAngle != 0)
				{
					QLineF gradientVector(item->width() / 2.0, item->height() / 2.0, 0, 0);
					gradientVector.setLength(gradientVector.length() + 1);
					gradientVector.setAngle(gradientVector.angle() + gradientAngle);
					QPointF g1 = intersectBoundingRect(item, gradientVector);
					item->GrControl1 = FPoint(g1.x(), g1.y());
					gradientVector = QLineF(item->width() / 2.0, item->height() / 2.0, item->width(), 0);
					gradientVector.setLength(gradientVector.length() + 1);
					gradientVector.setAngle(gradientVector.angle() + gradientAngle);
					g1 = intersectBoundingRect(item, gradientVector);
					item->GrControl2 = FPoint(g1.x(), g1.y());
					gradientVector = QLineF(item->width() / 2.0, item->height() / 2.0, item->width(), item->height());
					gradientVector.setLength(gradientVector.length() + 1);
					gradientVector.setAngle(gradientVector.angle() + gradientAngle);
					g1 = intersectBoundingRect(item, gradientVector);
					item->GrControl3 = FPoint(g1.x(), g1.y());
					gradientVector = QLineF(item->width() / 2.0, item->height() / 2.0, 0, item->height());
					gradientVector.setLength(gradientVector.length() + 1);
					gradientVector.setAngle(gradientVector.angle() + gradientAngle);
					g1 = intersectBoundingRect(item, gradientVector);
					item->GrControl4 = FPoint(g1.x(), g1.y());
				}
				item->GrControl5 = FPoint(item->width() / 2.0, item->height() / 2.0);
				item->setGradient(fillGradient);
				item->setGradientType(fillGradientTyp);
			}
		}
		item->setDashOffset(0);
		if (!DashValues.isEmpty())
		{
			QVector<double> pattern(DashValues.count());
			for (int i = 0; i < DashValues.count(); ++i)
			{
				pattern[i] = DashValues[i] * lineWidth;
			}
			item->setDashes(pattern);
		}
		else
			item->setLineStyle(Qt::PenStyle(LineStyle));
		if (ArrowLeft > 1)
			item->setStartArrowIndex(ArrowLeft);
		if (ArrowRight > 1)
			item->setEndArrowIndex(ArrowRight);
		item->setRotation(-ob_rotation, true);
		item->moveBy(ob_xpos, ob_ypos, true);
		item->setFillEvenOdd(false);
		item->OldB2 = item->width();
		item->OldH2 = item->height();
		item->updateClip();
		item->OwnPage = m_Doc->OnPage(item);
		item->ContourLine = item->PoLine.copy();
		if (hasShadow)
		{
			item->setHasSoftShadow(true);
			item->setSoftShadowColor(shadowColor);
			item->setSoftShadowXOffset(shadowX);
			item->setSoftShadowYOffset(shadowY);
			item->setSoftShadowBlurRadius(shadowBlur);
			item->setSoftShadowShade(shadowTint);
			item->setSoftShadowOpacity(shadowOpacity);
			item->setSoftShadowBlendMode(0);
			item->setSoftShadowErasedByObject(shadowErase);
			item->setSoftShadowHasObjectTransparency(shadowObjTrans);
		}
		if (baseType == 1)
		{
			item->AspectRatio = true;
			item->ScaleType   = false;
			bool erf = m_Doc->loadPict(imageFile, item);
			if (!erf)
			{
				if (!imageData.isEmpty())
				{
					QTemporaryFile tempFile(QDir::tempPath() + "/scribus_temp_viva_XXXXXX.png");
					if (tempFile.open())
					{
						QString fileName = getLongPathName(tempFile.fileName());
						if (!fileName.isEmpty())
						{
							tempFile.setAutoRemove(false);
							tempFile.write(imageData);
							tempFile.close();
							item->isInlineImage = true;
							item->isTempFile = true;
							item->AspectRatio = true;
							item->ScaleType   = false;
							m_Doc->loadPict(fileName, item);
						}
					}
				}
			}
			item->setImageXYScale(imageScaleX / item->pixm.imgInfo.xres * 72, imageScaleX / item->pixm.imgInfo.xres * 72);
			item->setImageXYOffset(imageXoffs / item->imageXScale(), imageYoffs / item->imageYScale());
		}
		else if (baseType == 2)
		{
			item->setTextToFrameDist(textMarginLeft, textMarginRight, textMarginTop, textMarginBottom);
			item->setColumns(textColumnCount);
			item->setColumnGap(textColumnGap);
			if (itemText.length() > 0)
				item->itemText.append(itemText);
			item->itemText.trim();
		}
		item->setLocked(locked);
		item->setSizeLocked(resizable);
		item->setPrintEnabled(printable);
		retObj = m_Doc->Items->takeAt(z);
	}
	return retObj;
}

void VivaPlug::parseTextXML(const QDomElement& obNode, StoryText &itemText, int &textColumnCount, double &textColumnGap)
{
	QString pStyle = CommonStrings::DefaultParagraphStyle;
	ParagraphStyle newStyle;
	newStyle.setDefaultStyle(false);
	newStyle.setParent(pStyle);
	ParagraphStyle ttx = m_Doc->paragraphStyle(pStyle);
	CharStyle nstyle = ttx.charStyle();
	newStyle.setLineSpacingMode(ParagraphStyle::FixedLineSpacing);
	newStyle.setLineSpacing(nstyle.fontSize() / 10.0);
	itemText.setDefaultStyle(newStyle);
	int posC = 0;
	for (QDomNode spo = obNode.firstChild(); !spo.isNull(); spo = spo.nextSibling())
	{
		QDomElement eo = spo.toElement();
		if (eo.tagName() == "vs:stylesheets")
			parseStylesheetsXML(eo);
		else if (eo.tagName() == "vs:attribute-sets")
			parseAttributeSetsXML(eo);
		else if (eo.tagName() == "vt:story")
		{
			if (eo.hasAttribute("vt:story-attribute-set"))
			{
				applyParagraphAttrs(newStyle, AttributeSets[eo.attribute("vt:story-attribute-set")]);
				applyCharacterAttrs(newStyle.charStyle(), newStyle, AttributeSets[eo.attribute("vt:story-attribute-set")]);
			}
			for (QDomNode stx = eo.firstChild(); !stx.isNull(); stx = stx.nextSibling())
			{
				QDomElement stxe = stx.toElement();
				if (stxe.tagName() == "vt:chapter")
				{
					for (QDomNode st = stxe.firstChild(); !st.isNull(); st = st.nextSibling())
					{
						QDomElement ste = st.toElement();
						if (ste.tagName() == "vt:layout")
						{
							if (ste.hasAttribute("vt:layout-attribute-set"))
							{
								AttributeSet attrs = AttributeSets[ste.attribute("vt:layout-attribute-set")];
								if (attrs.columnCount.valid)
									textColumnCount = attrs.columnCount.value.toInt();
								if (attrs.columnGutter.valid)
									textColumnGap = attrs.columnGutter.value.toDouble();
							}
							for (QDomNode stc = ste.firstChild(); !stc.isNull(); stc = stc.nextSibling())
							{
								QDomElement stce = stc.toElement();
								if (stce.tagName() == "vt:p")
								{
									ParagraphStyle tmpStyle = newStyle;
									if (stce.hasAttribute("vt:paragraph-attribute-set"))
									{
										if (AttributeSets.contains(stce.attribute("vt:paragraph-attribute-set")))
											applyParagraphAttrs(tmpStyle, AttributeSets[stce.attribute("vt:paragraph-attribute-set")]);
										else if (m_Doc->styleExists(stce.attribute("vt:paragraph-attribute-set")))
											tmpStyle = m_Doc->paragraphStyle(stce.attribute("vt:paragraph-attribute-set"));
									}
									for (QDomNode stces = stce.firstChild(); !stces.isNull(); stces = stces.nextSibling())
									{
										QDomElement stcet = stces.toElement();
										if (stcet.tagName() == "vt:span")
										{
											CharStyle tmpCStyle = tmpStyle.charStyle();
											if (stcet.hasAttribute("vt:character-attribute-set"))
												applyCharacterAttrs(tmpCStyle, tmpStyle, AttributeSets[stcet.attribute("vt:character-attribute-set")]);
											for (QDomNode stcesp = stcet.firstChild(); !stcesp.isNull(); stcesp = stcesp.nextSibling())
											{
												QDomElement stcespt = stcesp.toElement();
												int count = stcespt.text().length();
												if (stcespt.tagName() == "vt:plain-text")
													itemText.insertChars(posC, stcespt.text());
												else if (stcespt.tagName() == "vt:lf")
												{
													count = 1;
													itemText.insertChars(posC, SpecialChars::LINEBREAK);
												}
												else if (stcespt.tagName() == "vt:soft-hyphen")
												{
													count = 1;
													itemText.insertChars(posC, SpecialChars::SHYPHEN);
												}
												else if (stcespt.tagName() == "vt:space")
												{
													if (stcespt.attribute("vt:br") == "false")
													{
														count = 1;
														itemText.insertChars(posC, SpecialChars::NBSPACE);
													}
												}
												else if (stcespt.tagName() == "vt:variable")
												{
													if (stcespt.attribute("vt:type") == "Viva Technology/Page Number")
													{
														count = 1;
														itemText.insertChars(posC, SpecialChars::PAGENUMBER);
													}
													else if (stcespt.attribute("vt:type") == "Viva Technology/Number of Pages")
													{
														count = 1;
														itemText.insertChars(posC, SpecialChars::PAGECOUNT);
													}
												/*	else if (stcespt.attribute("vt:type") == "Viva Technology/TextEngine/Date")
													{
														QDomNode anc = stcespt.firstChild();
														QDomElement anco = anc.toElement();
														if (anco.tagName() == "uni:data")
														{
															QByteArray data;
															if (anco.hasAttribute("uni:encoder") && (anco.attribute("uni:encoder") == "base64"))
																data = QByteArray::fromBase64(anco.text().toLatin1());
															else
																data = anco.text().toLatin1();
															QByteArray decomdata;
															if (anco.hasAttribute("uni:compressor") && (anco.attribute("uni:compressor") == "zlib/deflate"))
																decomdata = qUncompress(data);
															else
																decomdata = data;
														}
													} */
												}
												else if (stcespt.tagName() == "vt:anchoring-object")
												{
													for (QDomNode anc = stcespt.firstChild(); !anc.isNull(); anc = anc.nextSibling())
													{
														QDomElement anco = anc.toElement();
														if (anco.tagName() == "vo:object")
														{
															PageItem* item = parseObjectXML(anco);
															if (item != nullptr)
															{
																item->isEmbedded = true;
																item->gXpos = 0;
																item->gYpos = 0;
																item->gWidth = item->width();
																item->gHeight = item->height();
																int fIndex = m_Doc->addToInlineFrames(item);
																itemText.insertObject(fIndex);
															}
														}
													}
													count = 1;
												}
												else if (stcespt.tagName() == "vt:tab")
												{
													count = 1;
													itemText.insertChars(posC, SpecialChars::TAB);
												}
												if (count != 0)
												{
													itemText.applyStyle(posC, tmpStyle);
													itemText.applyCharStyle(posC, count, tmpCStyle);
												}
												posC = itemText.length();
											}
										}
									}
									if (stce.attribute("vt:break") == "paragraph-break")
										itemText.insertChars(posC, SpecialChars::PARSEP);
									else if (stce.attribute("vt:break") == "layout-column-break")
										itemText.insertChars(posC, SpecialChars::COLBREAK);
									else if (stce.attribute("vt:break") == "area-break")
										itemText.insertChars(posC, SpecialChars::FRAMEBREAK);
									else
										itemText.insertChars(posC, SpecialChars::PARSEP);
									itemText.applyStyle(posC, tmpStyle);
									posC = itemText.length();
								}
							}
						}
					}
				}
			}
		}
	}
}

void VivaPlug::parseAttributeSetXML(const QDomElement& obNode, AttributeSet &attrs)
{
	if (obNode.tagName() == "vs:template")
		attrs.parentStyle = obNode.text();
	for (QDomNode stx = obNode.firstChild(); !stx.isNull(); stx = stx.nextSibling())
	{
		QDomElement stxe = stx.toElement();
		if (stxe.tagName() == "vta:font")
		{
			if (stxe.hasAttribute("vta:family"))
				attrs.fontFamily = AttributeValue(stxe.attribute("vta:family"));
			if (stxe.hasAttribute("vta:style"))
				attrs.fontStyle = AttributeValue(stxe.attribute("vta:style"));
		}
		else if (stxe.tagName() == "vta:font-size")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.fontSize = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:character-color")
		{
			if (stxe.hasAttribute("vta:name"))
				attrs.fontColor = AttributeValue(colorTranslate[stxe.attribute("vta:name")]);
		}
		else if (stxe.tagName() == "vta:character-color-density")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.fontColorDensity = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:character-type")
		{
			if (stxe.hasAttribute("vta:type"))
				attrs.fontEffect = AttributeValue(stxe.attribute("vta:type"));
		}
		else if (stxe.tagName() == "vta:character-placement")
		{
			if (stxe.hasAttribute("vta:type"))
				attrs.placement = AttributeValue(stxe.attribute("vta:type"));
		}
		else if (stxe.tagName() == "vta:underline")
		{
			attrs.underline = AttributeValue("true");
			attrs.underlineOffset = AttributeValue(stxe.attribute("vta:offset"));
			QDomNode ul = stxe.firstChild();
			if (!ul.isNull())
			{
				QDomElement ule = ul.toElement();
				if (ule.tagName() == "vta:pen")
					attrs.underlineWidth = AttributeValue(ule.attribute("vta:width"));
			}
		}
		else if (stxe.tagName() == "vta:strikethrough")
		{
			attrs.strikethrough = AttributeValue("true");
			attrs.strikethroughOffset = AttributeValue(stxe.attribute("vta:offset"));
			QDomNode ul = stxe.firstChild();
			if (!ul.isNull())
			{
				QDomElement ule = ul.toElement();
				if (ule.tagName() == "vta:pen")
					attrs.strikethroughWidth = AttributeValue(ule.attribute("vta:width"));
			}
		}
		else if (stxe.tagName() == "vta:character-outline")
		{
			if (stxe.attribute("vta:active") == "true")
			{
				attrs.outline = AttributeValue("true");
				QDomNode ul = stxe.firstChild();
				if (!ul.isNull())
				{
					QDomElement ule = ul.toElement();
					if (ule.tagName() == "vta:pen")
					{
						attrs.outlineWidth = AttributeValue(ule.attribute("vta:width"));
						attrs.outlineColor = AttributeValue(colorTranslate[ule.attribute("vta:color")]);
					}
				}
			}
		}
		else if (stxe.tagName() == "vta:character-width-scale")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.widthScale = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:character-height-scale")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.heightScale = AttributeValue(stxe.attribute("vta:value"));
		}
		else if ((stxe.tagName() == "vta:character-spacing") || (stxe.tagName() == "vta:kerning"))
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.spacing = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:baseline-shift")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.baselineOffset = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:writing-justification")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.justification = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:paragraph-distance-before")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.gapbefore = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:paragraph-distance-after")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.gapafter = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:line-distance")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.lineSpacing = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:paragraph-indent")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.firstLineIndent = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:paragraph-begin-indent")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.indent = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:paragraph-end-indent")
		{
			if (stxe.hasAttribute("vta:value"))
				attrs.rightIndent = AttributeValue(stxe.attribute("vta:value"));
		}
		else if (stxe.tagName() == "vta:layout-columns")
		{
			int columnCount = 0;
			double columnGutter = 0.0;
			for (QDomNode stc = stxe.firstChild(); !stc.isNull(); stc = stc.nextSibling())
			{
				QDomElement stce = stc.toElement();
				if (stce.tagName() == "vta:column")
				{
					columnCount++;
					columnGutter = qMax(columnGutter, parseUnit(stce.attribute("vta:gutter", "0")));
				}
			}
			if (columnCount > 0)
			{
				attrs.columnCount = AttributeValue(QString("%1").arg(columnCount));
				attrs.columnGutter = AttributeValue(QString("%1").arg(columnGutter));
			}
		}
		else if (stxe.tagName() == "vta:initials")
		{
			if (stxe.attribute("vta:active") == "true")
			{
				attrs.dropCaps = AttributeValue("true");
				attrs.dropCapsDist = AttributeValue(stxe.attribute("vta:distance-to-text", "0"));
				for (QDomNode stc = stxe.firstChild(); !stc.isNull(); stc = stc.nextSibling())
				{
					QDomElement stce = stc.toElement();
					if (stce.tagName() == "vta:size")
					{
						QDomNode ul = stce.firstChild();
						if (!ul.isNull())
						{
							QDomElement ule = ul.toElement();
							if (ule.tagName() == "vta:dynamic-lines")
							{
								attrs.dropCapsLines = AttributeValue(ule.attribute("vta:maximum-lines", "1"));
							}
						}
					}
				}
			}
		}
		else if (stxe.tagName() == "vta:tabulators")
		{
			QString tabs;
			for (QDomNode stc = stxe.firstChild(); !stc.isNull(); stc = stc.nextSibling())
			{
				QDomElement stce = stc.toElement();
				if (stce.tagName() == "vta:tabulator")
				{
					if (stce.hasAttribute("vta:position"))
						tabs += stce.attribute("vta:position");
					tabs += "\t";
					if (stce.hasAttribute("vta:alignment"))
						tabs += stce.attribute("vta:alignment");
					tabs += "\t";
					if (stce.hasAttribute("vta:filler"))
						tabs += stce.attribute("vta:filler");
				}
				tabs += "\n";
			}
			attrs.tabulators = AttributeValue(tabs);
		}
	}
	if ((attrs.fontFamily.valid) && (attrs.fontStyle.valid))
		attrs.fontFullName = AttributeValue(constructFontName(attrs.fontFamily.value, attrs.fontStyle.value));
}

void VivaPlug::parseAttributeSetsXML(const QDomElement& obNode)
{
	for (QDomNode spo = obNode.firstChild(); !spo.isNull(); spo = spo.nextSibling())
	{
		QDomElement eo = spo.toElement();
		AttributeSet attrs;
		parseAttributeSetXML(eo, attrs);
		if (eo.hasAttribute("vs:paragraph-style"))
			attrs.applyedParStyle = AttributeValue(eo.attribute("vs:paragraph-style"));
		AttributeSets.insert(eo.attribute("vs:name"), attrs);
	}
}

void VivaPlug::parseStylesheetsXML(const QDomElement& obNode)
{
	for (QDomNode spo = obNode.firstChild(); !spo.isNull(); spo = spo.nextSibling())
	{
		QDomElement eo = spo.toElement();
		if (eo.tagName() == "vs:paragraphStylesheet")
		{
			ParagraphStyle newStyle;
			newStyle.erase();
			newStyle.setDefaultStyle(false);
			newStyle.setName(eo.attribute("vs:name"));
			newStyle.setParent(CommonStrings::DefaultParagraphStyle);
			ParagraphStyle ttx = m_Doc->paragraphStyle(CommonStrings::DefaultParagraphStyle);
			CharStyle nstyle = ttx.charStyle();
			newStyle.setLineSpacingMode(ParagraphStyle::FixedLineSpacing);
			newStyle.setLineSpacing(nstyle.fontSize() / 10.0);
			AttributeSet attrs;
			for (QDomNode stx = eo.firstChild(); !stx.isNull(); stx = stx.nextSibling())
			{
				QDomElement stxe = stx.toElement();
				parseAttributeSetXML(stxe, attrs);
			}
			applyParagraphAttrs(newStyle, attrs);
			applyCharacterAttrs(newStyle.charStyle(), newStyle, attrs);
			StyleSet<ParagraphStyle>tmp;
			tmp.create(newStyle);
			m_Doc->redefineStyles(tmp, false);
		}
	}
}

void VivaPlug::applyParagraphAttrs(ParagraphStyle& newStyle, const AttributeSet& pAttrs) const
{
	if (pAttrs.applyedParStyle.valid)
		newStyle = m_Doc->paragraphStyle(pAttrs.applyedParStyle.value);
	if (pAttrs.parentStyle.valid)
		newStyle.setParent(pAttrs.parentStyle.value);
	if (pAttrs.justification.valid)
	{
		if (pAttrs.justification.value == "left")
			newStyle.setAlignment(ParagraphStyle::LeftAligned);
		else if (pAttrs.justification.value == "right")
			newStyle.setAlignment(ParagraphStyle::RightAligned);
		else if (pAttrs.justification.value == "center")
			newStyle.setAlignment(ParagraphStyle::Centered);
		else if (pAttrs.justification.value == "justified")
			newStyle.setAlignment(ParagraphStyle::Justified);
		else if (pAttrs.justification.value == "forced-justified")
			newStyle.setAlignment(ParagraphStyle::Extended);
	}
	if (pAttrs.gapbefore.valid)
		newStyle.setGapBefore(parseUnit(pAttrs.gapbefore.value));
	if (pAttrs.gapafter.valid)
		newStyle.setGapAfter(parseUnit(pAttrs.gapafter.value));
	if (pAttrs.lineSpacing.valid)
	{
		newStyle.setLineSpacingMode(ParagraphStyle::FixedLineSpacing);
		newStyle.setLineSpacing(parseUnit(pAttrs.lineSpacing.value));
	}
	else
		newStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
	if (pAttrs.firstLineIndent.valid)
		newStyle.setFirstIndent(parseUnit(pAttrs.firstLineIndent.value));
	if (pAttrs.indent.valid)
	{
		newStyle.setLeftMargin(parseUnit(pAttrs.indent.value));
		newStyle.setFirstIndent(newStyle.firstIndent() - parseUnit(pAttrs.indent.value));
	}
	if (pAttrs.rightIndent.valid)
		newStyle.setRightMargin(parseUnit(pAttrs.rightIndent.value));
	if (pAttrs.dropCaps.valid)
	{
		newStyle.setHasDropCap(true);
		if (pAttrs.dropCapsLines.valid)
			newStyle.setDropCapLines(pAttrs.dropCapsLines.value.toInt());
		if (pAttrs.dropCapsDist.valid)
			newStyle.setParEffectOffset(parseUnit(pAttrs.dropCapsDist.value));
	}
	if (pAttrs.tabulators.valid)
	{
		QList<ParagraphStyle::TabRecord> tbs;
		newStyle.resetTabValues();
		QStringList tabList = pAttrs.tabulators.value.split("\n");
		for (int a = 0; a < tabList.count(); a++)
		{
			QString tbv = tabList[a];
			if (!tbv.isEmpty())
			{
				ParagraphStyle::TabRecord tb;
				QStringList tab = tbv.split("\t");
				tb.tabPosition = parseUnit(tab[0]);
				tb.tabType = 0;
				if (tab[1] == "begin")
					tb.tabType = 0;
				else if (tab[1] == "center")
					tb.tabType = 4;
				else if (tab[1] == "end")
					tb.tabType = 1;
				else if (tab[1] == "character")
					tb.tabType = 3;
				tb.tabFillChar = tab[2].isEmpty() ? QChar() : tab[2][0];
				tbs.append(tb);
			}
		}
		if (!tbs.isEmpty())
			newStyle.setTabValues(tbs);
	}
}

void VivaPlug::applyCharacterAttrs(CharStyle &tmpCStyle, ParagraphStyle &newStyle, const AttributeSet &pAttrs)
{
	if (pAttrs.fontSize.valid)
	{
		tmpCStyle.setFontSize(pAttrs.fontSize.value.toDouble() * 10);
		if (pAttrs.lineSpacing.valid)
		{
			if (pAttrs.fontSize.value.toInt() > parseUnit(pAttrs.lineSpacing.value))
				newStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
		}
	}
	if (pAttrs.fontFullName.valid)
		tmpCStyle.setFont((*m_Doc->AllFonts)[pAttrs.fontFullName.value]);
	if (pAttrs.fontColor.valid)
		tmpCStyle.setFillColor(pAttrs.fontColor.value);
	if (pAttrs.fontColorDensity.valid)
	{
		int tint = 100;
		if (pAttrs.fontColorDensity.value == "transparent")
			tint = 0;
		else
			tint = pAttrs.fontColorDensity.value.toInt();
		tmpCStyle.setFillShade(tint);
	}
	if (pAttrs.underline.valid)
	{
		if (pAttrs.underlineWidth.valid)
			tmpCStyle.setUnderlineWidth(qRound(parseUnit(pAttrs.underlineWidth.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
		else
			tmpCStyle.setUnderlineWidth(-1);
		if (pAttrs.underlineOffset.valid)
		{
			if (parseUnit(pAttrs.underlineOffset.value) != 0)
				tmpCStyle.setUnderlineOffset(qRound(parseUnit(pAttrs.underlineOffset.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
			else
				tmpCStyle.setUnderlineOffset(-1);
		}
		else
			tmpCStyle.setUnderlineOffset(-1);
		StyleFlag styleEffects = tmpCStyle.effects();
		styleEffects |= ScStyle_Underline;
		tmpCStyle.setFeatures(styleEffects.featureList());
	}
	if (pAttrs.strikethrough.valid)
	{
		if (pAttrs.strikethroughWidth.valid)
			tmpCStyle.setStrikethruWidth(qRound(parseUnit(pAttrs.strikethroughWidth.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
		else
			tmpCStyle.setStrikethruWidth(-1);
		if (pAttrs.strikethroughOffset.valid)
		{
			if (parseUnit(pAttrs.strikethroughOffset.value) != 0)
				tmpCStyle.setStrikethruOffset(qRound(parseUnit(pAttrs.strikethroughOffset.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
			else
				tmpCStyle.setStrikethruOffset(-1);
		}
		else
			tmpCStyle.setStrikethruOffset(-1);
		StyleFlag styleEffects = tmpCStyle.effects();
		styleEffects |= ScStyle_Strikethrough;
		tmpCStyle.setFeatures(styleEffects.featureList());
	}
	if (pAttrs.outline.valid)
	{
		if (pAttrs.outlineWidth.valid)
			tmpCStyle.setOutlineWidth(qRound(parseUnit(pAttrs.outlineWidth.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
		else
			tmpCStyle.setOutlineWidth(-1);
		if (pAttrs.outlineColor.valid)
			tmpCStyle.setStrokeColor(pAttrs.outlineColor.value);
		StyleFlag styleEffects = tmpCStyle.effects();
		styleEffects |= ScStyle_Outline;
		tmpCStyle.setFeatures(styleEffects.featureList());
	}
	if (pAttrs.placement.valid)
	{
		StyleFlag styleEffects = tmpCStyle.effects();
		if ((pAttrs.placement.value == "superscript") || (pAttrs.placement.value == "index"))
			styleEffects |= ScStyle_Superscript;
		else if (pAttrs.placement.value == "subscript")
			styleEffects |= ScStyle_Subscript;
		tmpCStyle.setFeatures(styleEffects.featureList());
	}
	if (pAttrs.fontEffect.valid)
	{
		StyleFlag styleEffects = tmpCStyle.effects();
		if (pAttrs.fontEffect.value == "caps")
			styleEffects |= ScStyle_AllCaps;
		else if (pAttrs.fontEffect.value == "small-caps")
			styleEffects |= ScStyle_SmallCaps;
		tmpCStyle.setFeatures(styleEffects.featureList());
	}
	if (pAttrs.widthScale.valid)
		tmpCStyle.setScaleH(pAttrs.widthScale.value.toInt() * 10);
	if (pAttrs.heightScale.valid)
		tmpCStyle.setScaleV(pAttrs.heightScale.value.toInt() * 10);
	if (pAttrs.spacing.valid)
		tmpCStyle.setTracking(pAttrs.spacing.value.toInt() * 10);
	if (pAttrs.baselineOffset.valid)
	{
		if (parseUnit(pAttrs.baselineOffset.value) != 0)
			tmpCStyle.setBaselineOffset(qRound(parseUnit(pAttrs.baselineOffset.value) * 1000 / (tmpCStyle.fontSize() / 10.0)));
	}
}

QString VivaPlug::constructFontName(const QString& fontBaseName, const QString& fontStyle)
{
	QString fontName;
	bool found = false;
	SCFontsIterator it(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts);
	for ( ; it.hasNext(); it.next())
	{
		if (fontBaseName.toLower() == it.current().family().toLower())
		{
			// found the font family, now go for the style
			QStringList slist = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.fontMap[it.current().family()];
			slist.sort();
			if (!slist.isEmpty())
			{
				for (int a = 0; a < slist.count(); a++)
				{
					if (fontStyle.toLower() == slist[a].toLower())
					{
						found = true;
						fontName = it.current().family() + " " + slist[a];
						break;
					}
				}
				if (!found)
				{
					int reInd = slist.indexOf("Regular");
					if (reInd < 0)
						fontName = it.current().family() + " " + slist[0];
					else
						fontName = it.current().family() + " " + slist[reInd];
					found = true;
				}
			}
			else
			{
				fontName = it.current().family();
				found = true;
			}
			break;
		}
	}
	if (!found)
	{
		if (importerFlags & LoadSavePlugin::lfCreateThumbnail)
			fontName = PrefsManager::instance().appPrefs.itemToolPrefs.textFont;
		else
		{
			QString family = fontBaseName;
			if (!fontStyle.isEmpty())
				family += " " + fontStyle;
			if (!PrefsManager::instance().appPrefs.fontPrefs.GFontSub.contains(family))
			{
				QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
				QScopedPointer<MissingFont> dia(new MissingFont(nullptr, family, m_Doc));
				dia->exec();
				fontName = dia->getReplacementFont();
				QApplication::changeOverrideCursor(QCursor(Qt::WaitCursor));
				PrefsManager::instance().appPrefs.fontPrefs.GFontSub[family] = fontName;
			}
			else
				fontName = PrefsManager::instance().appPrefs.fontPrefs.GFontSub[family];
		}
	}
	return fontName;
}

QPointF VivaPlug::intersectBoundingRect(const PageItem *item, const QLineF& gradientVector) const
{
	QPointF interPoint;
	QPointF gradEnd;
	if (gradientVector.intersects(QLineF(0, 0, item->width(), 0), &interPoint) == QLineF::BoundedIntersection)
		gradEnd = interPoint;
	else if (gradientVector.intersects(QLineF(item->width(), 0, item->width(), item->height()), &interPoint) == QLineF::BoundedIntersection)
		gradEnd = interPoint;
	else if (gradientVector.intersects(QLineF(item->width(), item->height(), 0, item->height()), &interPoint) == QLineF::BoundedIntersection)
		gradEnd = interPoint;
	else if (gradientVector.intersects(QLineF(0, item->height(), 0, 0), &interPoint) == QLineF::BoundedIntersection)
		gradEnd = interPoint;
	return gradEnd;
}
