1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 
8 #include <QCursor>
9 #include <QDir>
10 #include <QDrag>
11 #include <QDomElement>
12 #include <QFile>
13 #include <QMessageBox>
14 #include <QMimeData>
15 #include <QString>
16 #include <QRegExp>
17 #include <QWidget>
18 
19 #include "oodrawimp.h"
20 
21 #include "scconfig.h"
22 
23 #include "commonstrings.h"
24 #include "fpointarray.h"
25 #include "pageitem.h"
26 #include "pluginmanager.h"
27 #include "prefscontext.h"
28 #include "prefsfile.h"
29 #include "prefsmanager.h"
30 #include "prefstable.h"
31 #include "scclocale.h"
32 #include "sccolorengine.h"
33 #include "scmimedata.h"
34 #include "scraction.h"
35 #include "scribusXml.h"
36 #include "scribuscore.h"
37 #include "scribusdoc.h"
38 #include "scribusview.h"
39 #include "selection.h"
40 #include "serializer.h"
41 #include "stylestack.h"
42 #include "third_party/zip/scribus_zip.h"
43 #include "ui/customfdialog.h"
44 #include "ui/propertiespalette.h"
45 #include "ui/scmessagebox.h"
46 #include "ui/scmwmenumanager.h"
47 #include "undomanager.h"
48 #include "util.h"
49 #include "util_math.h"
50 
51 
52 
53 using namespace std;
54 
oodrawimp_getPluginAPIVersion()55 int oodrawimp_getPluginAPIVersion()
56 {
57 	return PLUGIN_API_VERSION;
58 }
59 
oodrawimp_getPlugin()60 ScPlugin* oodrawimp_getPlugin()
61 {
62 	OODrawImportPlugin* plug = new OODrawImportPlugin();
63 	Q_CHECK_PTR(plug);
64 	return plug;
65 }
66 
oodrawimp_freePlugin(ScPlugin * plugin)67 void oodrawimp_freePlugin(ScPlugin* plugin)
68 {
69 	OODrawImportPlugin* plug = qobject_cast<OODrawImportPlugin*>(plugin);
70 	Q_ASSERT(plug);
71 	delete plug;
72 }
73 
OODrawImportPlugin()74 OODrawImportPlugin::OODrawImportPlugin() :
75 	importAction(new ScrAction(ScrAction::DLL, "", QKeySequence(), this))
76 {
77 	// Set action info in languageChange, so we only have to do
78 	// it in one place. This includes registering file formats.
79 	registerFormats();
80 	languageChange();
81 }
82 
~OODrawImportPlugin()83 OODrawImportPlugin::~OODrawImportPlugin()
84 {
85 	unregisterAll();
86 	// note: importAction is automatically deleted by Qt
87 }
88 
languageChange()89 void OODrawImportPlugin::languageChange()
90 {
91 	importAction->setText( tr("Import &OpenOffice.org Draw..."));
92 //	FileFormat* fmt = getFormatByExt("odg");
93 //	fmt->trName = tr("OpenDocument 1.0 Draw", "Import/export format name");
94 //	fmt->filter = tr("OpenDocument 1.0 Draw (*.odg *.ODG)");
95 	FileFormat* fmt2 = getFormatByExt("sxd");
96 	fmt2->trName = tr("OpenOffice.org 1.x Draw", "Import/export format name");
97 	fmt2->filter = tr("OpenOffice.org 1.x Draw (*.sxd *.SXD)");
98 }
99 
fullTrName() const100 QString OODrawImportPlugin::fullTrName() const
101 {
102 	return QObject::tr("OpenOffice.org Draw Importer");
103 }
104 
getAboutData() const105 const ScActionPlugin::AboutData* OODrawImportPlugin::getAboutData() const
106 {
107 	AboutData* about = new AboutData;
108 	about->authors = "Franz Schmid <franz@scribus.info>";
109 	about->shortDescription = tr("Imports OpenOffice.org Draw Files");
110 	about->description = tr("Imports most OpenOffice.org Draw files into the current document, converting their vector data into Scribus objects.");
111 	about->license = "GPL";
112 	Q_CHECK_PTR(about);
113 	return about;
114 }
115 
deleteAboutData(const AboutData * about) const116 void OODrawImportPlugin::deleteAboutData(const AboutData* about) const
117 {
118 	Q_ASSERT(about);
119 	delete about;
120 }
121 
registerFormats()122 void OODrawImportPlugin::registerFormats()
123 {
124 //	QString odtName = tr("OpenDocument 1.0 Draw", "Import/export format name");
125 //	FileFormat odtformat(this);
126 //	odtformat.trName = odtName; // Human readable name
127 //	odtformat.formatId = 0;
128 //	odtformat.filter = odtName + " (*.odg *.ODG)"; // QFileDialog filter
129 //	odtformat.fileExtensions = QStringList() << "odg";
130 //	odtformat.load = true;
131 //	odtformat.save = false;
132 //	odtformat.thumb = true;
133 //	odtformat.mimeTypes = QStringList("application/vnd.oasis.opendocument.graphics"); // MIME types
134 //	odtformat.priority = 64; // Priority
135 //	registerFormat(odtformat);
136 
137 	QString sxdName = tr("OpenOffice.org 1.x Draw", "Import/export format name");
138 	FileFormat sxdformat(this);
139 	sxdformat.trName = sxdName; // Human readable name
140 	sxdformat.formatId = 0;
141 	sxdformat.filter = sxdName + " (*.sxd *.SXD)"; // QFileDialog filter
142 	sxdformat.fileExtensions = QStringList() << "sxd";
143 	sxdformat.load = true;
144 	sxdformat.save = false;
145 	sxdformat.thumb = true;
146 	sxdformat.mimeTypes = QStringList("application/vnd.sun.xml.draw"); // MIME types
147 	sxdformat.priority = 64; // Priority
148 	registerFormat(sxdformat);
149 }
150 
fileSupported(QIODevice *,const QString & fileName) const151 bool OODrawImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
152 {
153 	// TODO: try to identify .sxd / .odt files
154 	return true;
155 }
156 
loadFile(const QString & fileName,const FileFormat &,int flags,int)157 bool OODrawImportPlugin::loadFile(const QString & fileName, const FileFormat &, int flags, int /*index*/)
158 {
159 	// For this plugin, right now "load" and "import" are the same thing
160 	return import(fileName, flags);
161 }
162 
import(QString fileName,int flags)163 bool OODrawImportPlugin::import(QString fileName, int flags)
164 {
165 	if (!checkFlags(flags))
166 		return false;
167 	if (fileName.isEmpty())
168 	{
169 		flags |= lfInteractive;
170 		PrefsContext* prefs = PrefsManager::instance().prefsFile->getPluginContext("OODrawImport");
171 		QString wdir = prefs->get("wdir", ".");
172 		CustomFDialog diaf(ScCore->primaryMainWindow(), wdir, QObject::tr("Open"), QObject::tr("OpenOffice.org Draw (*.sxd *.SXD);;All Files (*)"));
173 		if (diaf.exec())
174 		{
175 			fileName = diaf.selectedFile();
176 			prefs->set("wdir", fileName.left(fileName.lastIndexOf("/")));
177 		}
178 		else
179 			return true;
180 	}
181 	m_Doc=ScCore->primaryMainWindow()->doc;
182 	UndoTransaction activeTransaction;
183 	bool emptyDoc = (m_Doc == nullptr);
184 	bool hasCurrentPage = (m_Doc && m_Doc->currentPage());
185 	TransactionSettings trSettings;
186 	trSettings.targetName   = hasCurrentPage ? m_Doc->currentPage()->getUName() : "";
187 	trSettings.targetPixmap = Um::IImageFrame;
188 	trSettings.actionName   = Um::ImportOOoDraw;
189 	trSettings.description  = fileName;
190 	trSettings.actionPixmap = Um::IImportOOoDraw;
191 	OODPlug dia(m_Doc);
192 	if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
193 		UndoManager::instance()->setUndoEnabled(false);
194 	if (UndoManager::undoEnabled())
195 		activeTransaction = UndoManager::instance()->beginTransaction(trSettings);
196 	bool importDone = dia.import(fileName, trSettings, flags);
197 	if (activeTransaction)
198 		activeTransaction.commit();
199 	if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
200 		UndoManager::instance()->setUndoEnabled(true);
201 	if (dia.importCanceled)
202 	{
203 		if ((!importDone) || (dia.importFailed))
204 			ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, tr("The file could not be imported"));
205 		else if (dia.unsupported)
206 			ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, tr("This file contains some unsupported features"));
207 	}
208 	return importDone;
209 }
210 
readThumbnail(const QString & fileName)211 QImage OODrawImportPlugin::readThumbnail(const QString& fileName)
212 {
213 	if (fileName.isEmpty())
214 		return QImage();
215 	UndoManager::instance()->setUndoEnabled(false);
216 	m_Doc = nullptr;
217 	OODPlug *dia = new OODPlug(m_Doc);
218 	Q_CHECK_PTR(dia);
219 	QImage ret = dia->readThumbnail(fileName);
220 	UndoManager::instance()->setUndoEnabled(true);
221 	delete dia;
222 	return ret;
223 }
224 
OODPlug(ScribusDoc * doc)225 OODPlug::OODPlug(ScribusDoc* doc)
226 {
227 	m_Doc=doc;
228 	unsupported = false;
229 	interactive = false;
230 	importFailed = false;
231 	importCanceled = true;
232 	importedColors.clear();
233 	tmpSel=new Selection(this, false);
234 }
235 
readThumbnail(const QString & fileName)236 QImage OODPlug::readThumbnail(const QString& fileName)
237 {
238 	QByteArray f, f2, f3;
239 	if (!QFile::exists(fileName))
240 		return QImage();
241 	ScZipHandler* fun = new ScZipHandler();
242 	if (!fun->open(fileName))
243 	{
244 		delete fun;
245 		return QImage();
246 	}
247 	if (fun->contains("styles.xml"))
248 		fun->read("styles.xml", f);
249 	if (fun->contains("content.xml"))
250 		fun->read("content.xml", f2);
251 	if (fun->contains("meta.xml"))
252 		fun->read("meta.xml", f3);
253 	delete fun;
254 	HaveMeta = inpMeta.setContent(f3);
255 	QString docname = fileName.right(fileName.length() - fileName.lastIndexOf("/") - 1);
256 	docname = docname.left(docname.lastIndexOf("."));
257 	if (f.isEmpty())
258 		return QImage();
259 	if (f2.isEmpty())
260 		return QImage();
261 	if (!inpStyles.setContent(f))
262 		return QImage();
263 	if (!inpContents.setContent(f2))
264 		return QImage();
265 	QString CurDirP = QDir::currentPath();
266 	QFileInfo efp(fileName);
267 	QDir::setCurrent(efp.path());
268 	bool isOODraw2 = false;
269 	QDomNode drawPagePNode;
270 	QList<PageItem*> Elements;
271 	createStyleMap( inpStyles );
272 	QDomElement docElem = inpContents.documentElement();
273 	QDomNode automaticStyles = docElem.namedItem( "office:automatic-styles" );
274 	if (!automaticStyles.isNull())
275 		insertStyles( automaticStyles.toElement() );
276 	QDomNode body = docElem.namedItem( "office:body" );
277 	QDomNode drawPage = body.namedItem( "draw:page" );
278 	if (drawPage.isNull())
279 	{
280 		QDomNode offDraw = body.namedItem( "office:drawing" );
281 		drawPage = offDraw.namedItem( "draw:page" );
282 		if (drawPage.isNull())
283 			return QImage();
284 		isOODraw2 = true;
285 		drawPagePNode = body.namedItem( "office:drawing" );
286 	}
287 	else
288 		drawPagePNode = body;
289 	StyleStack::Mode mode = isOODraw2 ? StyleStack::OODraw2x : StyleStack::OODraw1x;
290 	m_styleStack.setMode( mode );
291 	QDomElement dp = drawPage.toElement();
292 	QDomElement *master = m_styles[dp.attribute( "draw:master-page-name" )];
293 	QDomElement *style = nullptr;
294 	QDomElement properties;
295 	if (isOODraw2)
296 	{
297 		style = m_styles.value(master->attribute( "style:page-layout-name" ), nullptr);
298 		if (style)
299 			properties = style->namedItem("style:page-layout-properties" ).toElement();
300 	}
301 	else
302 	{
303 		style = m_styles.value(master->attribute( "style:page-master-name" ), nullptr);
304 		if (style)
305 			properties = style->namedItem( "style:properties" ).toElement();
306 	}
307 	double width = !properties.attribute( "fo:page-width" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-width" ) ) : 550.0;
308 	double height = !properties.attribute( "fo:page-height" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-height" ) ) : 841.0;
309 	m_Doc = new ScribusDoc();
310 	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
311 	m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
312 	m_Doc->addPage(0);
313 	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
314 	Elements.clear();
315 	m_Doc->setLoading(true);
316 	m_Doc->DoDrawing = false;
317 	m_Doc->scMW()->setScriptRunning(true);
318 	if (!m_Doc->PageColors.contains("Black"))
319 		m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
320 	QDomNode drawPag = drawPagePNode.firstChild();
321 	QDomElement dpg = drawPag.toElement();
322 	m_styleStack.clear();
323 	fillStyleStack( dpg );
324 	QList<PageItem*> el = parseGroup( dpg );
325 	for (int ec = 0; ec < el.count(); ++ec)
326 		Elements.append(el.at(ec));
327 	tmpSel->clear();
328 	QImage tmpImage = QImage();
329 	if (Elements.count() > 0)
330 	{
331 		if (Elements.count() > 1)
332 			m_Doc->groupObjectsList(Elements);
333 		m_Doc->DoDrawing = true;
334 		m_Doc->m_Selection->delaySignalsOn();
335 		for (int dre=0; dre<Elements.count(); ++dre)
336 		{
337 			tmpSel->addItem(Elements.at(dre), true);
338 		}
339 		tmpSel->setGroupRect();
340 		double xs = tmpSel->width();
341 		double ys = tmpSel->height();
342 		tmpImage = Elements.at(0)->DrawObj_toImage(500);
343 		tmpImage.setText("XSize", QString("%1").arg(xs));
344 		tmpImage.setText("YSize", QString("%1").arg(ys));
345 		m_Doc->m_Selection->delaySignalsOff();
346 		m_Doc->setLoading(false);
347 	}
348 	m_Doc->scMW()->setScriptRunning(false);
349 	delete m_Doc;
350 	QDir::setCurrent(CurDirP);
351 	return tmpImage;
352 }
353 
import(const QString & fileName,const TransactionSettings & trSettings,int flags)354 bool OODPlug::import(const QString& fileName, const TransactionSettings& trSettings, int flags)
355 {
356 	bool importDone = false;
357 	interactive = (flags & LoadSavePlugin::lfInteractive);
358 	QByteArray f, f2, f3;
359 	if (!QFile::exists(fileName))
360 		return false;
361 	ScZipHandler* fun = new ScZipHandler();
362 	if (!fun->open(fileName))
363 	{
364 		delete fun;
365 		return false;
366 	}
367 	if (fun->contains("styles.xml"))
368 		fun->read("styles.xml", f);
369 	if (fun->contains("content.xml"))
370 		fun->read("content.xml", f2);
371 	if (fun->contains("meta.xml"))
372 		fun->read("meta.xml", f3);
373 	delete fun;
374 	HaveMeta = inpMeta.setContent(f3);
375 	QString docname = fileName.right(fileName.length() - fileName.lastIndexOf("/") - 1);
376 	docname = docname.left(docname.lastIndexOf("."));
377 	if (f.isEmpty())
378 		return false;
379 	if (f2.isEmpty())
380 		return false;
381 	if (!inpStyles.setContent(f))
382 		return false;
383 	if (!inpContents.setContent(f2))
384 		return false;
385 	QString CurDirP = QDir::currentPath();
386 	QFileInfo efp(fileName);
387 	QDir::setCurrent(efp.path());
388 	importDone = convert(trSettings, flags);
389 	QDir::setCurrent(CurDirP);
390 	return importDone;
391 }
392 
convert(const TransactionSettings & trSettings,int flags)393 bool OODPlug::convert(const TransactionSettings& trSettings, int flags)
394 {
395 	bool ret = false;
396 	bool isOODraw2 = false;
397 	QDomNode drawPagePNode;
398 	int PageCounter = 0;
399 	QList<PageItem*> Elements;
400 	createStyleMap( inpStyles );
401 	QDomElement docElem = inpContents.documentElement();
402 	QDomNode automaticStyles = docElem.namedItem( "office:automatic-styles" );
403 	if (!automaticStyles.isNull() )
404 		insertStyles( automaticStyles.toElement() );
405 	QDomNode body = docElem.namedItem( "office:body" );
406 	QDomNode drawPage = body.namedItem( "draw:page" );
407 	if (drawPage.isNull())
408 	{
409 		QDomNode offDraw = body.namedItem( "office:drawing" );
410 		drawPage = offDraw.namedItem( "draw:page" );
411 		if (drawPage.isNull())
412 		{
413 			ScMessageBox::warning( m_Doc->scMW(), CommonStrings::trWarning, tr("This document does not seem to be an OpenOffice Draw file.") );
414 			return false;
415 		}
416 		isOODraw2 = true;
417 		drawPagePNode = body.namedItem( "office:drawing" );
418 	}
419 	else
420 		drawPagePNode = body;
421 	StyleStack::Mode mode = isOODraw2 ? StyleStack::OODraw2x : StyleStack::OODraw1x;
422 	m_styleStack.setMode( mode );
423 	QDomElement dp = drawPage.toElement();
424 	QDomElement *master = m_styles[dp.attribute( "draw:master-page-name" )];
425 	QDomElement *style = nullptr;
426 	QDomElement properties;
427 	if (isOODraw2)
428 	{
429 		style = m_styles.value(master->attribute( "style:page-layout-name" ), nullptr);
430 		if (style)
431 			properties = style->namedItem("style:page-layout-properties" ).toElement();
432 	}
433 	else
434 	{
435 		style = m_styles.value(master->attribute( "style:page-master-name" ), nullptr);
436 		if (style)
437 			properties = style->namedItem( "style:properties" ).toElement();
438 	}
439 	double width = !properties.attribute( "fo:page-width" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-width" ) ) : 550.0;
440 	double height = !properties.attribute( "fo:page-height" ).isEmpty() ? parseUnit(properties.attribute( "fo:page-height" ) ) : 841.0;
441 	if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
442 		m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
443 	else
444 	{
445 		if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
446 		{
447 			m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
448 			ScCore->primaryMainWindow()->HaveNewDoc();
449 			ret = true;
450 		}
451 	}
452 	if ((ret) || (!interactive))
453 	{
454 		if (width > height)
455 			m_Doc->setPageOrientation(1);
456 		else
457 			m_Doc->setPageOrientation(0);
458 		m_Doc->setPageSize("Custom");
459 		QDomNode mpg;
460 		QDomElement metaElem = inpMeta.documentElement();
461 		QDomElement mp = metaElem.namedItem( "office:meta" ).toElement();
462 		mpg = mp.namedItem( "dc:title" );
463 		if (!mpg.isNull())
464 			m_Doc->documentInfo().setTitle(mpg.toElement().text());
465 		mpg = mp.namedItem( "meta:initial-creator" );
466 		if (!mpg.isNull())
467 			m_Doc->documentInfo().setAuthor(mpg.toElement().text());
468 		mpg = mp.namedItem( "dc:description" );
469 		if (!mpg.isNull())
470 			m_Doc->documentInfo().setComments(mpg.toElement().text());
471 		mpg = mp.namedItem( "dc:language" );
472 		if (!mpg.isNull())
473 			m_Doc->documentInfo().setLangInfo(mpg.toElement().text());
474 		mpg = mp.namedItem( "meta:creation-date" );
475 		if (!mpg.isNull())
476 			m_Doc->documentInfo().setDate(mpg.toElement().text());
477 		mpg = mp.namedItem( "dc:creator" );
478 		if (!mpg.isNull())
479 			m_Doc->documentInfo().setContrib(mpg.toElement().text());
480 		mpg = mp.namedItem( "meta:keywords" );
481 		if (!mpg.isNull())
482 		{
483 			QString Keys = "";
484 			for (QDomNode n = mpg.firstChild(); !n.isNull(); n = n.nextSibling())
485 			{
486 				Keys += n.toElement().text()+", ";
487 			}
488 			if (Keys.length() > 2)
489 				m_Doc->documentInfo().setKeywords(Keys.left(Keys.length()-2));
490 		}
491 	}
492 	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
493 		m_Doc->view()->deselectItems();
494 	Elements.clear();
495 	m_Doc->setLoading(true);
496 	m_Doc->DoDrawing = false;
497 	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
498 		m_Doc->view()->updatesOn(false);
499 	m_Doc->scMW()->setScriptRunning(true);
500 	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
501 	if (!m_Doc->PageColors.contains("Black"))
502 		m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
503 	for (QDomNode drawPag = drawPagePNode.firstChild(); !drawPag.isNull(); drawPag = drawPag.nextSibling())
504 	{
505 		QDomElement dpg = drawPag.toElement();
506 		if (!interactive)
507 		{
508 			m_Doc->addPage(PageCounter);
509 			m_Doc->view()->addPage(PageCounter);
510 		}
511 		PageCounter++;
512 		m_styleStack.clear();
513 		fillStyleStack( dpg );
514 		QList<PageItem*> el = parseGroup( dpg );
515 		for (int ec = 0; ec < el.count(); ++ec)
516 			Elements.append(el.at(ec));
517 		if ((interactive) && (PageCounter == 1))
518 			break;
519 	}
520 	tmpSel->clear();
521 //	if ((Elements.count() > 1) && (interactive))
522 	if (Elements.count() == 0)
523 	{
524 		importFailed = true;
525 		if (importedColors.count() != 0)
526 		{
527 			for (int cd = 0; cd < importedColors.count(); cd++)
528 			{
529 				m_Doc->PageColors.remove(importedColors[cd]);
530 			}
531 		}
532 	}
533 	if (Elements.count() > 1)
534 		m_Doc->groupObjectsList(Elements);
535 	m_Doc->DoDrawing = true;
536 	m_Doc->scMW()->setScriptRunning(false);
537 	if (interactive)
538 		m_Doc->setLoading(false);
539 	qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
540 	if ((Elements.count() > 0) && (!ret) && (interactive))
541 	{
542 		if (flags & LoadSavePlugin::lfScripted)
543 		{
544 			bool loadF = m_Doc->isLoading();
545 			m_Doc->setLoading(false);
546 			m_Doc->changed();
547 			m_Doc->setLoading(loadF);
548 			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
549 			{
550 				m_Doc->m_Selection->delaySignalsOn();
551 				for (int dre=0; dre<Elements.count(); ++dre)
552 				{
553 					m_Doc->m_Selection->addItem(Elements.at(dre), true);
554 				}
555 				m_Doc->m_Selection->delaySignalsOff();
556 				m_Doc->m_Selection->setGroupRect();
557 				m_Doc->view()->updatesOn(true);
558 			}
559 			importCanceled = false;
560 		}
561 		else
562 		{
563 			m_Doc->DragP = true;
564 			m_Doc->DraggedElem = nullptr;
565 			m_Doc->DragElements.clear();
566 			m_Doc->m_Selection->delaySignalsOn();
567 			for (int dre=0; dre<Elements.count(); ++dre)
568 			{
569 				tmpSel->addItem(Elements.at(dre), true);
570 			}
571 			tmpSel->setGroupRect();
572 			ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
573 			m_Doc->itemSelection_DeleteItem(tmpSel);
574 			m_Doc->view()->updatesOn(true);
575 			m_Doc->m_Selection->delaySignalsOff();
576 			// We must copy the TransationSettings object as it is owned
577 			// by handleObjectImport method afterwards
578 			TransactionSettings* transacSettings = new TransactionSettings(trSettings);
579 			m_Doc->view()->handleObjectImport(md, transacSettings);
580 			m_Doc->DragP = false;
581 			m_Doc->DraggedElem = nullptr;
582 			m_Doc->DragElements.clear();
583 		}
584 	}
585 	else
586 	{
587 		bool loadF = m_Doc->isLoading();
588 		m_Doc->setLoading(false);
589 		m_Doc->changed();
590 		m_Doc->reformPages();
591 		if (!(flags & LoadSavePlugin::lfLoadAsPattern))
592 			m_Doc->view()->updatesOn(true);
593 		m_Doc->setLoading(loadF);
594 	}
595 	qApp->restoreOverrideCursor();
596 	return true;
597 }
598 
parseGroup(const QDomElement & e)599 QList<PageItem*> OODPlug::parseGroup(const QDomElement &e)
600 {
601 	OODrawStyle oostyle;
602 	FPointArray ImgClip;
603 	QList<PageItem*> elements, cElements;
604 //	double BaseX = m_Doc->currentPage()->xOffset();
605 //	double BaseY = m_Doc->currentPage()->yOffset();
606 	storeObjectStyles(e);
607 	parseStyle(oostyle, e);
608 //	QString drawID = e.attribute("draw:name");
609 //	int zn = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None);
610 //	PageItem *neu = m_Doc->Items->at(zn);
611 	for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
612 	{
613 		QDomElement b = n.toElement();
614 		if (b.isNull() )
615 			continue;
616 		QList<PageItem*> el = parseElement(b);
617 		for (int ec = 0; ec < el.count(); ++ec)
618 			cElements.append(el.at(ec));
619 	}
620 	if (cElements.count() < 2)
621 	{
622 		for (int gr = 0; gr < cElements.count(); ++gr)
623 		{
624 			elements.append(cElements.at(gr));
625 		}
626 	}
627 	else
628 	{
629 		PageItem *neu = m_Doc->groupObjectsList(cElements);
630 		elements.append(neu);
631 		if (!e.attribute("id").isEmpty() )
632 			neu->setItemName(e.attribute("id"));
633 		else
634 			neu->setItemName( tr("Group%1").arg(m_Doc->GroupCounter));
635 	}
636 	return elements;
637 }
638 
parseElement(const QDomElement & e)639 QList<PageItem*> OODPlug::parseElement(const QDomElement &e)
640 {
641 	QList<PageItem*> GElements;
642 	QString STag = e.tagName();
643 	if (STag == "draw:g")
644 	{
645 		GElements = parseGroup(e);
646 		return GElements;
647 	}
648 	if (STag == "draw:rect")
649 		GElements = parseRect(e);
650 	else if (STag == "draw:circle" || STag == "draw:ellipse")
651 		GElements = parseEllipse(e);
652 	else if (STag == "draw:line")
653 		GElements = parseLine(e);
654 	else if (STag == "draw:polygon")
655 		GElements = parsePolygon(e);
656 	else if (STag == "draw:polyline")
657 		GElements = parsePolyline(e);
658 	else if (STag == "draw:path")
659 		GElements = parsePath(e);
660 	else if (STag == "draw:text-box")
661 		GElements = parseTextBox(e);
662 	else if (STag == "draw:frame")
663 		GElements = parseFrame(e);
664 	else if (STag == "draw:connector")
665 		GElements = parseConnector(e);
666 	else
667 	{
668 		// warn if unsupported feature are encountered
669 		unsupported = true;
670 		qDebug("Not supported yet: %s", STag.toLocal8Bit().data());
671 	}
672 	return GElements;
673 }
674 
parseRect(const QDomElement & e)675 QList<PageItem*> OODPlug::parseRect(const QDomElement &e)
676 {
677 	OODrawStyle style;
678 	QList<PageItem*> elements;
679 	double BaseX = m_Doc->currentPage()->xOffset();
680 	double BaseY = m_Doc->currentPage()->yOffset();
681 	double x = parseUnit(e.attribute("svg:x"));
682 	double y = parseUnit(e.attribute("svg:y")) ;
683 	double w = parseUnit(e.attribute("svg:width"));
684 	double h = parseUnit(e.attribute("svg:height"));
685 	double corner = parseUnit(e.attribute("draw:corner-radius"));
686 	storeObjectStyles(e);
687 	parseStyle(style, e);
688 	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX+x, BaseY+y, w, h, style.strokeWidth, style.fillColor, style.strokeColor);
689 	PageItem* ite = m_Doc->Items->at(z);
690 	if (corner != 0)
691 	{
692 		ite->setCornerRadius(corner);
693 		ite->SetFrameRound();
694 		m_Doc->setRedrawBounding(ite);
695 	}
696 	ite = finishNodeParsing(e, ite, style);
697 	elements.append(ite);
698 	return elements;
699 }
700 
parseEllipse(const QDomElement & e)701 QList<PageItem*> OODPlug::parseEllipse(const QDomElement &e)
702 {
703 	OODrawStyle style;
704 	QList<PageItem*> elements;
705 	double BaseX = m_Doc->currentPage()->xOffset();
706 	double BaseY = m_Doc->currentPage()->yOffset();
707 	double x = parseUnit(e.attribute("svg:x"));
708 	double y = parseUnit(e.attribute("svg:y")) ;
709 	double w = parseUnit(e.attribute("svg:width"));
710 	double h = parseUnit(e.attribute("svg:height"));
711 	storeObjectStyles(e);
712 	parseStyle(style, e);
713 	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX+x, BaseY+y, w, h, style.strokeWidth, style.fillColor, style.strokeColor);
714 	PageItem* ite = m_Doc->Items->at(z);
715 	ite = finishNodeParsing(e, ite, style);
716 	elements.append(ite);
717 	return elements;
718 }
719 
parseLine(const QDomElement & e)720 QList<PageItem*> OODPlug::parseLine(const QDomElement &e)
721 {
722 	OODrawStyle style;
723 	QList<PageItem*> elements;
724 	double BaseX = m_Doc->currentPage()->xOffset();
725 	double BaseY = m_Doc->currentPage()->yOffset();
726 	double x1 = e.attribute( "svg:x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:x1" ) );
727 	double y1 = e.attribute( "svg:y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:y1" ) );
728 	double x2 = e.attribute( "svg:x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:x2" ) );
729 	double y2 = e.attribute( "svg:y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "svg:y2" ) );
730 	storeObjectStyles(e);
731 	parseStyle(style, e);
732 	int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, CommonStrings::None, style.strokeColor);
733 	PageItem* ite = m_Doc->Items->at(z);
734 	ite->PoLine.resize(4);
735 	ite->PoLine.setPoint(0, FPoint(x1, y1));
736 	ite->PoLine.setPoint(1, FPoint(x1, y1));
737 	ite->PoLine.setPoint(2, FPoint(x2, y2));
738 	ite->PoLine.setPoint(3, FPoint(x2, y2));
739 	FPoint wh = getMaxClipF(&ite->PoLine);
740 	ite->setWidthHeight(wh.x(), wh.y());
741 	ite->ClipEdited = true;
742 	ite->FrameType = 3;
743 	if (!e.hasAttribute("draw:transform"))
744 	{
745 		ite->Clip = flattenPath(ite->PoLine, ite->Segments);
746 		m_Doc->adjustItemSize(ite);
747 	}
748 	ite = finishNodeParsing(e, ite, style);
749 	elements.append(ite);
750 	return elements;
751 }
752 
parsePolygon(const QDomElement & e)753 QList<PageItem*> OODPlug::parsePolygon(const QDomElement &e)
754 {
755 	OODrawStyle style;
756 	QList<PageItem*> elements;
757 	double BaseX = m_Doc->currentPage()->xOffset();
758 	double BaseY = m_Doc->currentPage()->yOffset();
759 	storeObjectStyles(e);
760 	parseStyle(style, e);
761 	int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, style.fillColor, style.strokeColor);
762 	PageItem* ite = m_Doc->Items->at(z);
763 	ite->PoLine.resize(0);
764 	appendPoints(&ite->PoLine, e, true);
765 	FPoint wh = getMaxClipF(&ite->PoLine);
766 	ite->setWidthHeight(wh.x(), wh.y());
767 	ite->ClipEdited = true;
768 	ite->FrameType = 3;
769 	if (!e.hasAttribute("draw:transform"))
770 	{
771 		ite->Clip = flattenPath(ite->PoLine, ite->Segments);
772 		m_Doc->adjustItemSize(ite);
773 	}
774 	ite = finishNodeParsing(e, ite, style);
775 	elements.append(ite);
776 	return elements;
777 }
778 
parsePolyline(const QDomElement & e)779 QList<PageItem*> OODPlug::parsePolyline(const QDomElement &e)
780 {
781 	OODrawStyle style;
782 	QList<PageItem*> elements;
783 	double BaseX = m_Doc->currentPage()->xOffset();
784 	double BaseY = m_Doc->currentPage()->yOffset();
785 	storeObjectStyles(e);
786 	parseStyle(style, e);
787 	int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, CommonStrings::None, style.strokeColor);
788 	PageItem* ite = m_Doc->Items->at(z);
789 	ite->PoLine.resize(0);
790 	appendPoints(&ite->PoLine, e, false);
791 	FPoint wh = getMaxClipF(&ite->PoLine);
792 	ite->setWidthHeight(wh.x(), wh.y());
793 	ite->ClipEdited = true;
794 	ite->FrameType = 3;
795 	if (!e.hasAttribute("draw:transform"))
796 	{
797 		ite->Clip = flattenPath(ite->PoLine, ite->Segments);
798 		m_Doc->adjustItemSize(ite);
799 	}
800 	ite = finishNodeParsing(e, ite, style);
801 	elements.append(ite);
802 	return elements;
803 }
804 
parsePath(const QDomElement & e)805 QList<PageItem*> OODPlug::parsePath(const QDomElement &e)
806 {
807 	OODrawStyle style;
808 	FPointArray pArray;
809 	QList<PageItem*> elements;
810 	double BaseX = m_Doc->currentPage()->xOffset();
811 	double BaseY = m_Doc->currentPage()->yOffset();
812 	storeObjectStyles(e);
813 	parseStyle(style, e);
814 	PageItem::ItemType itype = parseSVG(e.attribute("svg:d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
815 	int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, style.strokeWidth, style.fillColor, style.strokeColor);
816 	PageItem* ite = m_Doc->Items->at(z);
817 	ite->PoLine.resize(0);
818 	ite->PoLine = pArray;
819 	if (ite->PoLine.size() < 4)
820 	{
821 // 		m_Doc->m_Selection->addItem(ite);
822 		tmpSel->addItem(ite);
823 // 		m_Doc->itemSelection_DeleteItem();
824 		m_Doc->itemSelection_DeleteItem(tmpSel);
825 	}
826 	else
827 	{
828 		QTransform mat;
829 		double x = parseUnit(e.attribute("svg:x"));
830 		double y = parseUnit(e.attribute("svg:y")) ;
831 		double w = parseUnit(e.attribute("svg:width"));
832 		double h = parseUnit(e.attribute("svg:height"));
833 		double vx = 0;
834 		double vy = 0;
835 		double vw = 1;
836 		double vh = 1;
837 		parseViewBox(e, &vx, &vy, &vw, &vh);
838 		double sx = (vw != 0.0) ? (w / vw) : w;
839 		double sy = (vh != 0.0) ? (h / vh) : h;
840 		mat.translate(x, y);
841 		mat.scale(sx, sy);
842 		ite->PoLine.map(mat);
843 		FPoint wh = getMaxClipF(&ite->PoLine);
844 		ite->setWidthHeight(wh.x(), wh.y());
845 		ite->ClipEdited = true;
846 		ite->FrameType = 3;
847 		if (!e.hasAttribute("draw:transform"))
848 		{
849 			ite->Clip = flattenPath(ite->PoLine, ite->Segments);
850 			m_Doc->adjustItemSize(ite);
851 		}
852 		ite = finishNodeParsing(e, ite, style);
853 		elements.append(ite);
854 	}
855 	return elements;
856 }
857 
parseTextBox(const QDomElement & e)858 QList<PageItem*> OODPlug::parseTextBox(const QDomElement &e)
859 {
860 	OODrawStyle style;
861 	QList<PageItem*> elements;
862 	double BaseX = m_Doc->currentPage()->xOffset();
863 	double BaseY = m_Doc->currentPage()->yOffset();
864 	double x = parseUnit(e.attribute("svg:x"));
865 	double y = parseUnit(e.attribute("svg:y")) ;
866 	double w = parseUnit(e.attribute("svg:width"));
867 	double h = parseUnit(e.attribute("svg:height"));
868 	storeObjectStyles(e);
869 	parseStyle(style, e);
870 	int z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, BaseX+x, BaseY+y, w, h+(h*0.1), style.strokeWidth, CommonStrings::None, style.strokeColor);
871 	PageItem* ite = m_Doc->Items->at(z);
872 	ite->setFillColor(style.fillColor);
873 	ite->setLineColor(style.strokeColor);
874 	ite = finishNodeParsing(e, ite, style);
875 	elements.append(ite);
876 	return elements;
877 }
878 
parseFrame(const QDomElement & e)879 QList<PageItem*> OODPlug::parseFrame(const QDomElement &e)
880 {
881 	OODrawStyle oostyle;
882 	QList<PageItem*> elements;
883 	QString drawID = e.attribute("draw:name");
884 	double BaseX = m_Doc->currentPage()->xOffset();
885 	double BaseY = m_Doc->currentPage()->yOffset();
886 	double x = parseUnit(e.attribute("svg:x"));
887 	double y = parseUnit(e.attribute("svg:y")) ;
888 	double w = parseUnit(e.attribute("svg:width"));
889 	double h = parseUnit(e.attribute("svg:height"));
890 	storeObjectStyles(e);
891 	parseStyle(oostyle, e);
892 	QDomNode n = e.firstChild();
893 	QString STag2 = n.toElement().tagName();
894 	if (STag2 == "draw:text-box")
895 	{
896 		int z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, BaseX+x, BaseY+y, w, h+(h*0.1), oostyle.strokeWidth, CommonStrings::None, oostyle.strokeColor);
897 		PageItem* ite = m_Doc->Items->at(z);
898 		ite->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
899 		ite->setFillTransparency(oostyle.fillTrans);
900 		ite->setLineTransparency(oostyle.strokeTrans);
901 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
902 		if (!drawID.isEmpty())
903 			ite->setItemName(drawID);
904 		ite = parseTextP(n.toElement(), ite);
905 		elements.append(ite);
906 	}
907 	return elements;
908 }
909 
parseConnector(const QDomElement & e)910 QList<PageItem*> OODPlug::parseConnector(const QDomElement &e)
911 {
912 	QList<PageItem*> elements;
913 	if (e.hasAttribute("svg:x1") && e.hasAttribute("svg:x2") && e.hasAttribute("svg:y1") && e.hasAttribute("svg:y2"))
914 	{
915 		elements = parseLine(e);
916 	}
917 	else
918 	{
919 		unsupported = true;
920 		qDebug("an unsupported form of connector was found");
921 	}
922 	return elements;
923 }
924 
parseStyle(OODrawStyle & oostyle,const QDomElement & e)925 void OODPlug::parseStyle(OODrawStyle& oostyle, const QDomElement &e)
926 {
927 	oostyle.haveGradient = false;
928 	oostyle.gradient.clearStops();
929 	if (m_styleStack.hasAttribute("draw:stroke") )
930 	{
931 		if (m_styleStack.attribute( "draw:stroke" ) == "none" )
932 			oostyle.strokeWidth = 0.0;
933 		else
934 		{
935 			if (m_styleStack.hasAttribute("svg:stroke-width"))
936 			{
937 				oostyle.strokeWidth = parseUnit(m_styleStack.attribute("svg:stroke-width"));
938 				if (oostyle.strokeWidth == 0)
939 					oostyle.strokeWidth = 1;
940 			}
941 			if (m_styleStack.hasAttribute("svg:stroke-color"))
942 				oostyle.strokeColor = parseColor(m_styleStack.attribute("svg:stroke-color"));
943 			if (m_styleStack.hasAttribute( "svg:stroke-opacity" ) )
944 				oostyle.strokeTrans = 1.0 - ScCLocale::toDoubleC(m_styleStack.attribute( "svg:stroke-opacity" ).remove( '%' )) / 100.0;
945 			if (m_styleStack.attribute( "draw:stroke" ) == "dash" )
946 			{
947 				QString style = m_styleStack.attribute( "draw:stroke-dash" );
948 				if (style == "Ultrafine Dashed")
949 					oostyle.dashes << 1.4 << 1.4;
950 				else if (style == "Fine Dashed" )
951 					oostyle.dashes << 14.4 << 14.4;
952 				else if (style == "Fine Dotted")
953 					oostyle.dashes << 13 << 13;
954 				else if (style == "Ultrafine 2 Dots 3 Dashes")
955 					oostyle.dashes << 1.45 << 3.6 << 1.45 << 3.6 << 7.2 << 3.6 << 7.2 << 3.6 << 7.2 << 3.6;
956 				else if (style == "Line with Fine Dots")
957 				{
958 					oostyle.dashes << 56.9 << 4.31;
959 					for (int dd = 0; dd < 10; ++ dd)
960 					{
961 						oostyle.dashes << 8.6 << 4.31;
962 					}
963 				}
964 				else if (style == "2 Dots 1 Dash" )
965 					oostyle.dashes << 2.8 << 5.75 << 2.8 << 5.75 << 5.75 << 5.75;
966 			}
967 		}
968 	}
969 	if (m_styleStack.hasAttribute( "draw:fill" ) )
970 	{
971 		QString fill = m_styleStack.attribute( "draw:fill" );
972 		if (fill == "solid" )
973 		{
974 			if (m_styleStack.hasAttribute( "draw:fill-color" ) )
975 				oostyle.fillColor = parseColor( m_styleStack.attribute("draw:fill-color"));
976 			if (m_styleStack.hasAttribute( "draw:transparency" ) )
977 				oostyle.fillTrans = 1.0 - ScCLocale::toDoubleC(m_styleStack.attribute( "draw:transparency" ).remove( '%' )) / 100.0;
978 		}
979 		else if (fill == "gradient" )
980 		{
981 			oostyle.haveGradient = true;
982 			oostyle.gradientAngle = 0;
983 			oostyle.gradient.clearStops();
984 			oostyle.gradient.setRepeatMethod( VGradient::none );
985 			QString style = m_styleStack.attribute( "draw:fill-gradient-name" );
986 			QDomElement* draw = m_draws[style];
987 			if (draw )
988 			{
989 				double border = 0.0;
990 				int shadeS = 100;
991 				int shadeE = 100;
992 				if (draw->hasAttribute( "draw:border" ) )
993 					border += ScCLocale::toDoubleC(draw->attribute( "draw:border" ).remove( '%' )) / 100.0;
994 				if (draw->hasAttribute( "draw:start-intensity" ) )
995 					shadeS = draw->attribute( "draw:start-intensity" ).remove( '%' ).toInt();
996 				if (draw->hasAttribute( "draw:end-intensity" ) )
997 					shadeE = draw->attribute( "draw:end-intensity" ).remove( '%' ).toInt();
998 				QString type = draw->attribute( "draw:style" );
999 				if (type == "linear" || type == "axial" )
1000 				{
1001 					oostyle.gradient.setType( VGradient::linear );
1002 					oostyle.gradientAngle = ScCLocale::toDoubleC(draw->attribute( "draw:angle" )) / 10;
1003 					oostyle.gradientType = 1;
1004 				}
1005 				else if (type == "radial" || type == "ellipsoid" )
1006 				{
1007 					if (draw->hasAttribute( "draw:cx" ) )
1008 						oostyle.gradientPointX = ScCLocale::toDoubleC(draw->attribute( "draw:cx" ).remove( '%' )) / 100.0;
1009 					else
1010 						oostyle.gradientPointX = 0.5;
1011 					if (draw->hasAttribute( "draw:cy" ) )
1012 						oostyle.gradientPointY = ScCLocale::toDoubleC(draw->attribute( "draw:cy" ).remove( '%' )) / 100.0;
1013 					else
1014 						oostyle.gradientPointY = 0.5;
1015 					oostyle.gradientType = 2;
1016 				}
1017 				QString c, c2;
1018 				c = parseColor( draw->attribute( "draw:start-color" ) );
1019 				c2 = parseColor( draw->attribute( "draw:end-color" ) );
1020 				const ScColor& col1 = m_Doc->PageColors[c];
1021 				const ScColor& col2 = m_Doc->PageColors[c2];
1022 				if (((oostyle.gradientAngle > 90) && (oostyle.gradientAngle < 271)) || (oostyle.gradientType == 2))
1023 				{
1024 					const ScColor& col1 = m_Doc->PageColors[c];
1025 					const ScColor& col2 = m_Doc->PageColors[c2];
1026 					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col2, m_Doc, shadeE), 0.0, 0.5, 1, c2, shadeE );
1027 					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col1, m_Doc, shadeS), 1.0 - border, 0.5, 1, c, shadeS );
1028 				}
1029 				else
1030 				{
1031 					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col1, m_Doc, shadeS), border, 0.5, 1, c, shadeS );
1032 					oostyle.gradient.addStop( ScColorEngine::getShadeColor(col2, m_Doc, shadeE), 1.0, 0.5, 1, c2, shadeE );
1033 				}
1034 			}
1035 		}
1036 	}
1037 }
1038 
parseCharStyle(CharStyle & style,const QDomElement & e)1039 void OODPlug::parseCharStyle(CharStyle& style, const QDomElement &e)
1040 {
1041 	if (m_styleStack.hasAttribute("fo:font-size"))
1042 	{
1043 		QString fs = m_styleStack.attribute("fo:font-size").remove( "pt" );
1044 		int FontSize = (int) (ScCLocale::toFloatC(fs) * 10.0);
1045 		style.setFontSize(FontSize);
1046 	}
1047 }
1048 
parseParagraphStyle(ParagraphStyle & style,const QDomElement & e)1049 void OODPlug::parseParagraphStyle(ParagraphStyle& style, const QDomElement &e)
1050 {
1051 	if (m_styleStack.hasAttribute("fo:text-align"))
1052 	{
1053 		QString attValue = m_styleStack.attribute("fo:text-align");
1054 		if (attValue == "left")
1055 			style.setAlignment(ParagraphStyle::LeftAligned);
1056 		if (attValue == "center")
1057 			style.setAlignment(ParagraphStyle::Centered);
1058 		if (attValue == "right")
1059 			style.setAlignment(ParagraphStyle::RightAligned);
1060 	}
1061 	if (m_styleStack.hasAttribute("fo:font-size"))
1062 	{
1063 		QString fs = m_styleStack.attribute("fo:font-size").remove( "pt" );
1064 		int FontSize = (int) (ScCLocale::toFloatC(fs) * 10.0);
1065 		style.charStyle().setFontSize(FontSize);
1066 		style.setLineSpacing((FontSize + FontSize * 0.2) / 10.0);
1067 	}
1068 }
1069 
parseTextP(const QDomElement & elm,PageItem * item)1070 PageItem* OODPlug::parseTextP (const QDomElement& elm, PageItem* item)
1071 {
1072 	for ( QDomNode n = elm.firstChild(); !n.isNull(); n = n.nextSibling() )
1073 	{
1074 		if (!n.hasAttributes() && !n.hasChildNodes())
1075 			continue;
1076 		QDomElement e = n.toElement();
1077 		if (e.text().isEmpty())
1078 			continue;
1079 		storeObjectStyles(e);
1080 		item->itemText.insertChars(-1, SpecialChars::PARSEP);
1081 		item = parseTextSpans(e, item);
1082 	}
1083 	return item;
1084 }
1085 
parseTextSpans(const QDomElement & elm,PageItem * item)1086 PageItem* OODPlug::parseTextSpans(const QDomElement& elm, PageItem* item)
1087 {
1088 	bool firstSpan = true;
1089 	for ( QDomNode n = elm.firstChild(); !n.isNull(); n = n.nextSibling() )
1090 	{
1091 		QString chars;
1092 		QDomElement e = n.toElement();
1093 		if (n.isElement() && (e.tagName() == "text:span"))
1094 		{
1095 			chars = e.text().simplified();
1096 			storeObjectStyles(e);
1097 		}
1098 		if (n.isText())
1099 		{
1100 			QDomText t = n.toText();
1101 			chars = t.data().simplified();
1102 		}
1103 		if (chars.isEmpty())
1104 			continue;
1105 		int pos = item->itemText.length();
1106 		if (firstSpan && (m_styleStack.hasAttribute("fo:text-align") || m_styleStack.hasAttribute("fo:font-size")))
1107 		{
1108 			ParagraphStyle newStyle;
1109 			parseParagraphStyle(newStyle, n.isElement() ? e : elm);
1110 			item->itemText.applyStyle(-1, newStyle);
1111 		}
1112 		item->itemText.insertChars( -2, chars);
1113 		if (!firstSpan && m_styleStack.hasAttribute("fo:font-size"))
1114 		{
1115 			CharStyle newStyle;
1116 			parseCharStyle(newStyle, n.isElement() ? e : elm);
1117 			item->itemText.applyCharStyle(pos, chars.length(), newStyle);
1118 		}
1119 		if (!item->isPolyLine() && !item->isTextFrame())
1120 			item = m_Doc->convertItemTo(item, PageItem::TextFrame);
1121 		firstSpan = false;
1122 	}
1123 	return item;
1124 }
1125 
finishNodeParsing(const QDomElement & elm,PageItem * item,OODrawStyle & oostyle)1126 PageItem* OODPlug::finishNodeParsing(const QDomElement &elm, PageItem* item, OODrawStyle& oostyle)
1127 {
1128 	item->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
1129 	item->itemText.trim();
1130 //	bool firstPa = false;
1131 	QString drawID = elm.attribute("draw:name");
1132 	item = parseTextP(elm, item);
1133 	item->setFillTransparency(oostyle.fillTrans);
1134 	item->setLineTransparency(oostyle.strokeTrans);
1135 	if (oostyle.dashes.count() != 0)
1136 		item->DashValues = oostyle.dashes;
1137 	if (!drawID.isEmpty())
1138 		item->setItemName(drawID);
1139 	if (elm.hasAttribute("draw:transform"))
1140 	{
1141 		parseTransform(&item->PoLine, elm.attribute("draw:transform"));
1142 		item->ClipEdited = true;
1143 		item->FrameType = 3;
1144 		FPoint wh = getMaxClipF(&item->PoLine);
1145 		item->setWidthHeight(wh.x(), wh.y());
1146 		item->Clip = flattenPath(item->PoLine, item->Segments);
1147 		m_Doc->adjustItemSize(item);
1148 	}
1149 	item->OwnPage = m_Doc->OnPage(item);
1150 	//ite->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
1151 	item->setTextFlowMode(PageItem::TextFlowDisabled);
1152 	if (oostyle.haveGradient)
1153 	{
1154 		item->GrType = 0;
1155 		if (oostyle.gradient.stops() > 1)
1156 		{
1157 			item->fill_gradient = oostyle.gradient;
1158 			if (oostyle.gradientType == 1)
1159 			{
1160 				bool flipped = false;
1161 				double gradientAngle(oostyle.gradientAngle);
1162 				if ((gradientAngle == 0) || (gradientAngle == 180) || (gradientAngle == 90) || (gradientAngle == 270))
1163 				{
1164 					item->GrType = Gradient_Linear;
1165 					if ((gradientAngle == 0) || (gradientAngle == 180))
1166 					{
1167 						item->GrStartX = item->width() / 2.0;
1168 						item->GrStartY = 0;
1169 						item->GrEndX = item->width() / 2.0;
1170 						item->GrEndY = item->height();
1171 					}
1172 					else if ((gradientAngle == 90) || (gradientAngle == 270))
1173 					{
1174 						item->GrStartX = 0;
1175 						item->GrStartY = item->height() / 2.0;
1176 						item->GrEndX = item->width();
1177 						item->GrEndY = item->height() / 2.0;
1178 					}
1179 				}
1180 				else
1181 				{
1182 					if ((gradientAngle > 90) && (gradientAngle < 270))
1183 						gradientAngle -= 180;
1184 					else if ((gradientAngle > 270) && (gradientAngle < 360))
1185 					{
1186 						gradientAngle = 360 - gradientAngle;
1187 						flipped = true;
1188 					}
1189 					double xpos;
1190 					xpos = (item->width() / 2) * tan(gradientAngle* M_PI / 180.0) * (item->height() / item->width()) + (item->width() / 2);
1191 					if ((xpos < 0) || (xpos > item->width()))
1192 					{
1193 						xpos = (item->height() / 2)- (item->height() / 2) * tan(gradientAngle* M_PI / 180.0) * (item->height() / item->width());
1194 						if (flipped)
1195 						{
1196 							item->GrEndX = item->width();
1197 							item->GrEndY = item->height() - xpos;
1198 							item->GrStartX = 0;
1199 							item->GrStartY = xpos;
1200 						}
1201 						else
1202 						{
1203 							item->GrEndY = xpos;
1204 							item->GrEndX = item->width();
1205 							item->GrStartX = 0;
1206 							item->GrStartY = item->height() - xpos;
1207 						}
1208 					}
1209 					else
1210 					{
1211 						item->GrEndX = xpos;
1212 						item->GrEndY = item->height();
1213 						item->GrStartX = item->width() - xpos;
1214 						item->GrStartY = 0;
1215 					}
1216 					if (flipped)
1217 					{
1218 						item->GrEndX = item->width() - xpos;
1219 						item->GrEndY = item->height();
1220 						item->GrStartX = xpos;
1221 						item->GrStartY = 0;
1222 					}
1223 					item->GrType = Gradient_Linear;
1224 				}
1225 			}
1226 			if (oostyle.gradientType == 2)
1227 			{
1228 				item->GrType = Gradient_Radial;
1229 				item->GrStartX = item->width() * oostyle.gradientPointX;
1230 				item->GrStartY = item->height()* oostyle.gradientPointY;
1231 				if (item->width() >= item->height())
1232 				{
1233 					item->GrEndX = item->width();
1234 					item->GrEndY = item->height() / 2.0;
1235 				}
1236 				else
1237 				{
1238 					item->GrEndX = item->width() / 2.0;
1239 					item->GrEndY = item->height();
1240 				}
1241 				//m_Doc->view()->updateGradientVectors(ite);
1242 				item->updateGradientVectors();
1243 			}
1244 		}
1245 		else
1246 		{
1247 			QList<VColorStop*> cstops = oostyle.gradient.colorStops();
1248 			item->setFillColor(cstops.at(0)->name);
1249 			item->setFillShade(cstops.at(0)->shade);
1250 		}
1251 	}
1252 	return item;
1253 }
1254 
createStyleMap(QDomDocument & docstyles)1255 void OODPlug::createStyleMap( QDomDocument &docstyles)
1256 {
1257 	QDomElement styles = docstyles.documentElement();
1258 	if (styles.isNull())
1259 		return;
1260 
1261 	QDomNode fixedStyles = styles.namedItem( "office:styles" );
1262 	if (!fixedStyles.isNull())
1263 	{
1264 		insertDraws( fixedStyles.toElement() );
1265 		insertStyles( fixedStyles.toElement() );
1266 	}
1267 	QDomNode automaticStyles = styles.namedItem( "office:automatic-styles" );
1268 	if (!automaticStyles.isNull())
1269 		insertStyles( automaticStyles.toElement() );
1270 
1271 	QDomNode masterStyles = styles.namedItem( "office:master-styles" );
1272 	if (!masterStyles.isNull())
1273 		insertStyles( masterStyles.toElement() );
1274 }
1275 
insertDraws(const QDomElement & styles)1276 void OODPlug::insertDraws(const QDomElement& styles)
1277 {
1278 	for (QDomNode n = styles.firstChild(); !n.isNull(); n = n.nextSibling())
1279 	{
1280 		QDomElement e = n.toElement();
1281 		if (!e.hasAttribute( "draw:name" ))
1282 			continue;
1283 		QString name = e.attribute( "draw:name" );
1284 		m_draws.insert(name, new QDomElement(e) );
1285 	}
1286 }
1287 
insertStyles(const QDomElement & styles)1288 void OODPlug::insertStyles( const QDomElement& styles )
1289 {
1290 	for (QDomNode n = styles.firstChild(); !n.isNull(); n = n.nextSibling())
1291 	{
1292 		QDomElement e = n.toElement();
1293 		if (!e.hasAttribute( "style:name" ))
1294 			continue;
1295 		QString name = e.attribute( "style:name" );
1296 		m_styles.insert(name, new QDomElement(e));
1297 	}
1298 }
1299 
fillStyleStack(const QDomElement & object)1300 void OODPlug::fillStyleStack( const QDomElement& object )
1301 {
1302 	if (object.hasAttribute( "presentation:style-name" ))
1303 		addStyles( m_styles.value(object.attribute( "presentation:style-name" ), nullptr) );
1304 	if (object.hasAttribute( "draw:style-name" ))
1305 		addStyles( m_styles.value(object.attribute( "draw:style-name" ), nullptr) );
1306 	if (object.hasAttribute( "draw:text-style-name" ))
1307 		addStyles( m_styles.value(object.attribute( "draw:text-style-name" ), nullptr) );
1308 	if (object.hasAttribute( "text:style-name" ))
1309 		addStyles( m_styles.value(object.attribute( "text:style-name" ), nullptr) );
1310 }
1311 
addStyles(const QDomElement * style)1312 void OODPlug::addStyles(const QDomElement* style)
1313 {
1314 	if (style)
1315 	{
1316 		if (style->hasAttribute( "style:parent-style-name" ))
1317 			addStyles(m_styles.value(style->attribute( "style:parent-style-name" ), nullptr));
1318 		m_styleStack.push(*style);
1319 	}
1320 }
1321 
storeObjectStyles(const QDomElement & object)1322 void OODPlug::storeObjectStyles(const QDomElement& object)
1323 {
1324 	fillStyleStack(object);
1325 }
1326 
parseUnit(const QString & unit)1327 double OODPlug::parseUnit(const QString &unit)
1328 {
1329 	QString unitval=unit;
1330 	if (unit.isEmpty())
1331 		return 0.0;
1332 	if (unit.right( 2 ) == "pt")
1333 		unitval.replace( "pt", "" );
1334 	else if (unit.right( 2 ) == "cm")
1335 		unitval.replace( "cm", "" );
1336 	else if (unit.right( 2 ) == "mm")
1337 		unitval.replace( "mm" , "" );
1338 	else if (unit.right( 2 ) == "in")
1339 		unitval.replace( "in", "" );
1340 	else if (unit.right( 2 ) == "px")
1341 		unitval.replace( "px", "" );
1342 	double value = ScCLocale::toDoubleC(unitval);
1343 	if (unit.right( 2 ) == "pt")
1344 		{}/* value = value; */ // no change
1345 	else if (unit.right( 2 ) == "cm")
1346 		value = ( value / 2.54 ) * 72;
1347 	else if (unit.right( 2 ) == "mm")
1348 		value = ( value / 25.4 ) * 72;
1349 	else if (unit.right( 2 ) == "in")
1350 		value = value * 72;
1351 	else if (unit.right( 2 ) == "px")
1352 		{}/* value = value; */ // no change
1353 	return value;
1354 }
1355 
parseColor(const QString & s)1356 QString OODPlug::parseColor( const QString &s )
1357 {
1358 	QColor c;
1359 	QString ret = CommonStrings::None;
1360 	if (s.startsWith( "rgb(" ))
1361 	{
1362 		QString parse = s.trimmed();
1363 		QStringList colors = parse.split( ',', Qt::SkipEmptyParts );
1364 		QString r = colors[0].right( ( colors[0].length() - 4 ) );
1365 		QString g = colors[1];
1366 		QString b = colors[2].left( ( colors[2].length() - 1 ) );
1367 		if (r.contains( "%" ))
1368 		{
1369 			r.chop(1);
1370 			r = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(r) ) / 100.0 ) ) );
1371 		}
1372 		if (g.contains( "%" ))
1373 		{
1374 			g.chop(1);
1375 			g = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(g) ) / 100.0 ) ) );
1376 		}
1377 		if (b.contains( "%" ) )
1378 		{
1379 			b.chop(1);
1380 			b = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(b) ) / 100.0 ) ) );
1381 		}
1382 		c = QColor(r.toInt(), g.toInt(), b.toInt());
1383 	}
1384 	else
1385 		c.setNamedColor(s.trimmed());
1386 
1387 	ScColor tmp;
1388 	tmp.fromQColor(c);
1389 	tmp.setSpotColor(false);
1390 	tmp.setRegistrationColor(false);
1391 	QString fNam = m_Doc->PageColors.tryAddColor("FromOODraw"+c.name(), tmp);
1392 	if (fNam == "FromOODraw"+c.name())
1393 		importedColors.append(fNam);
1394 	ret = fNam;
1395 	return ret;
1396 }
1397 
parseTransform(FPointArray * composite,const QString & transform)1398 void OODPlug::parseTransform(FPointArray *composite, const QString &transform)
1399 {
1400 	double dx, dy;
1401 	QTransform result;
1402 	QStringList subtransforms = transform.split(')', Qt::SkipEmptyParts);
1403 	QStringList::ConstIterator it = subtransforms.begin();
1404 	QStringList::ConstIterator end = subtransforms.end();
1405 	for (; it != end; ++it)
1406 	{
1407 		QStringList subtransform = (*it).split('(', Qt::SkipEmptyParts);
1408 		subtransform[0] = subtransform[0].trimmed().toLower();
1409 		subtransform[1] = subtransform[1].simplified();
1410 		QRegExp reg("[,( ]");
1411 		QStringList params = subtransform[1].split(reg, Qt::SkipEmptyParts);
1412 		if (subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
1413 			subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
1414 		if (subtransform[0] == "rotate")
1415 		{
1416 			result = QTransform();
1417 			result.rotate(-parseUnit(params[0]) * 180 / M_PI);
1418 			composite->map(result);
1419 		}
1420 		else if (subtransform[0] == "translate")
1421 		{
1422 			if (params.count() == 2)
1423 			{
1424 				dx = parseUnit(params[0]);
1425 				dy = parseUnit(params[1]);
1426 			}
1427 			else
1428 			{
1429 				dx = parseUnit(params[0]);
1430 				dy =0.0;
1431 			}
1432 			result = QTransform();
1433 			result.translate(dx, dy);
1434 			composite->map(result);
1435 		}
1436 		else if (subtransform[0] == "skewx")
1437 		{
1438 			result = QTransform();
1439 			result.shear(-tan(ScCLocale::toDoubleC(params[0])), 0.0);
1440 			composite->map(result);
1441 		}
1442 		else if (subtransform[0] == "skewy")
1443 		{
1444 			result = QTransform();
1445 			result.shear(0.0, -tan(ScCLocale::toDoubleC(params[0])));
1446 			composite->map(result);
1447 		}
1448 	}
1449 }
1450 
parseViewBox(const QDomElement & object,double * x,double * y,double * w,double * h)1451 void OODPlug::parseViewBox(const QDomElement& object, double *x, double *y, double *w, double *h)
1452 {
1453 	if (!object.attribute( "svg:viewBox" ).isEmpty())
1454 	{
1455 		QString viewbox( object.attribute( "svg:viewBox" ) );
1456 		QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split(' ', Qt::SkipEmptyParts);
1457 		*x = ScCLocale::toDoubleC(points[0]);
1458 		*y = ScCLocale::toDoubleC(points[1]);
1459 		*w = ScCLocale::toDoubleC(points[2]);
1460 		*h = ScCLocale::toDoubleC(points[3]);
1461 	}
1462 }
1463 
appendPoints(FPointArray * composite,const QDomElement & object,bool closePath)1464 void OODPlug::appendPoints(FPointArray *composite, const QDomElement& object, bool closePath)
1465 {
1466 	double x = parseUnit(object.attribute("svg:x"));
1467 	double y = parseUnit(object.attribute("svg:y")) ;
1468 	double w = parseUnit(object.attribute("svg:width"));
1469 	double h = parseUnit(object.attribute("svg:height"));
1470 	double vx = 0;
1471 	double vy = 0;
1472 	double vw = 1;
1473 	double vh = 1;
1474 	parseViewBox(object, &vx, &vy, &vw, &vh);
1475 	double sx = (vw != 0.0) ? (w / vw) : w;
1476 	double sy = (vh != 0.0) ? (h / vh) : h;
1477 	QStringList ptList = object.attribute( "draw:points" ).split( ' ', Qt::SkipEmptyParts );
1478 	FPoint point, firstP;
1479 	bool bFirst = true;
1480 	for (QStringList::Iterator it = ptList.begin(); it != ptList.end(); ++it)
1481 	{
1482 		point = FPoint(ScCLocale::toDoubleC((*it).section( ',', 0, 0 )), ScCLocale::toDoubleC((*it).section( ',', 1, 1 )));
1483 		if (bFirst)
1484 		{
1485 			composite->addPoint(point);
1486 			composite->addPoint(point);
1487 			firstP = point;
1488 			bFirst = false;
1489 		}
1490 		else
1491 		{
1492 			composite->addPoint(point);
1493 			composite->addPoint(point);
1494 			composite->addPoint(point);
1495 			composite->addPoint(point);
1496 		}
1497 	}
1498 	if (closePath)
1499 	{
1500 		composite->addPoint(firstP);
1501 		composite->addPoint(firstP);
1502 	}
1503 	QTransform mat;
1504 	mat.translate(x, y);
1505 	mat.scale(sx, sy);
1506 	composite->map(mat);
1507 }
1508 
getCoord(const char * ptr,double & number)1509 const char * OODPlug::getCoord( const char *ptr, double &number )
1510 {
1511 	int integer, exponent;
1512 	double decimal, frac;
1513 	int sign, expsign;
1514 
1515 	exponent = 0;
1516 	integer = 0;
1517 	frac = 1.0;
1518 	decimal = 0;
1519 	sign = 1;
1520 	expsign = 1;
1521 
1522 	// read the sign
1523 	if (*ptr == '+')
1524 		ptr++;
1525 	else if (*ptr == '-')
1526 	{
1527 		ptr++;
1528 		sign = -1;
1529 	}
1530 
1531 	// read the integer part
1532 	while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1533 		integer = (integer * 10) + *(ptr++) - '0';
1534 	if (*ptr == '.') // read the decimals
1535 	{
1536 		ptr++;
1537 		while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1538 			decimal += (*(ptr++) - '0') * (frac *= 0.1);
1539 	}
1540 
1541 	if (*ptr == 'e' || *ptr == 'E') // read the exponent part
1542 	{
1543 		ptr++;
1544 
1545 		// read the sign of the exponent
1546 		if (*ptr == '+')
1547 			ptr++;
1548 		else if (*ptr == '-')
1549 		{
1550 			ptr++;
1551 			expsign = -1;
1552 		}
1553 
1554 		exponent = 0;
1555 		while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1556 		{
1557 			exponent *= 10;
1558 			exponent += *ptr - '0';
1559 			ptr++;
1560 		}
1561 	}
1562 	number = integer + decimal;
1563 	number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
1564 
1565 	// skip the following space
1566 	if (*ptr == ' ')
1567 		ptr++;
1568 
1569 	return ptr;
1570 }
1571 
parseSVG(const QString & s,FPointArray * ite)1572 bool OODPlug::parseSVG(const QString &s, FPointArray *ite)
1573 {
1574 	QString d = s;
1575 	d = d.replace( QRegExp( "," ), " ");
1576 	bool ret = false;
1577 	if (!d.isEmpty())
1578 	{
1579 		d = d.simplified();
1580 		QByteArray data = d.toLatin1();
1581 		const char *ptr = data.constData();
1582 		const char *end = data.constData() + data.length() + 1;
1583 		double contrlx, contrly, curx, cury, tox, toy, x1, y1, x2, y2, xc, yc;
1584 		double px1, py1, px2, py2, px3, py3;
1585 		bool relative;
1586 		FirstM = true;
1587 		char command = *(ptr++), lastCommand = ' ';
1588 		curx = cury = contrlx = contrly = 0.0;
1589 		while (ptr < end)
1590 		{
1591 			if (*ptr == ' ')
1592 				ptr++;
1593 			relative = false;
1594 			switch (command)
1595 			{
1596 			case 'm':
1597 				relative = true;
1598 			case 'M':
1599 				{
1600 					ptr = getCoord( ptr, tox );
1601 					ptr = getCoord( ptr, toy );
1602 					WasM = true;
1603 					curx = relative ? curx + tox : tox;
1604 					cury = relative ? cury + toy : toy;
1605 					svgMoveTo(curx, cury );
1606 					break;
1607 				}
1608 			case 'l':
1609 				relative = true;
1610 			case 'L':
1611 				{
1612 					ptr = getCoord( ptr, tox );
1613 					ptr = getCoord( ptr, toy );
1614 					curx = relative ? curx + tox : tox;
1615 					cury = relative ? cury + toy : toy;
1616 					svgLineTo(ite, curx, cury );
1617 					break;
1618 				}
1619 			case 'h':
1620 				{
1621 					ptr = getCoord( ptr, tox );
1622 					curx = curx + tox;
1623 					svgLineTo(ite, curx, cury );
1624 					break;
1625 				}
1626 			case 'H':
1627 				{
1628 					ptr = getCoord( ptr, tox );
1629 					curx = tox;
1630 					svgLineTo(ite, curx, cury );
1631 					break;
1632 				}
1633 			case 'v':
1634 				{
1635 					ptr = getCoord( ptr, toy );
1636 					cury = cury + toy;
1637 					svgLineTo(ite, curx, cury );
1638 					break;
1639 				}
1640 			case 'V':
1641 				{
1642 					ptr = getCoord( ptr, toy );
1643 					cury = toy;
1644 					svgLineTo(ite,  curx, cury );
1645 					break;
1646 				}
1647 			case 'z':
1648 			case 'Z':
1649 				{
1650 					svgClosePath(ite);
1651 					break;
1652 				}
1653 			case 'c':
1654 				relative = true;
1655 			case 'C':
1656 				{
1657 					ptr = getCoord( ptr, x1 );
1658 					ptr = getCoord( ptr, y1 );
1659 					ptr = getCoord( ptr, x2 );
1660 					ptr = getCoord( ptr, y2 );
1661 					ptr = getCoord( ptr, tox );
1662 					ptr = getCoord( ptr, toy );
1663 					px1 = relative ? curx + x1 : x1;
1664 					py1 = relative ? cury + y1 : y1;
1665 					px2 = relative ? curx + x2 : x2;
1666 					py2 = relative ? cury + y2 : y2;
1667 					px3 = relative ? curx + tox : tox;
1668 					py3 = relative ? cury + toy : toy;
1669 					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1670 					contrlx = relative ? curx + x2 : x2;
1671 					contrly = relative ? cury + y2 : y2;
1672 					curx = relative ? curx + tox : tox;
1673 					cury = relative ? cury + toy : toy;
1674 					break;
1675 				}
1676 			case 's':
1677 				relative = true;
1678 			case 'S':
1679 				{
1680 					ptr = getCoord( ptr, x2 );
1681 					ptr = getCoord( ptr, y2 );
1682 					ptr = getCoord( ptr, tox );
1683 					ptr = getCoord( ptr, toy );
1684 					px1 = 2 * curx - contrlx;
1685 					py1 = 2 * cury - contrly;
1686 					px2 = relative ? curx + x2 : x2;
1687 					py2 = relative ? cury + y2 : y2;
1688 					px3 = relative ? curx + tox : tox;
1689 					py3 = relative ? cury + toy : toy;
1690 					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1691 					contrlx = relative ? curx + x2 : x2;
1692 					contrly = relative ? cury + y2 : y2;
1693 					curx = relative ? curx + tox : tox;
1694 					cury = relative ? cury + toy : toy;
1695 					break;
1696 				}
1697 			case 'q':
1698 				relative = true;
1699 			case 'Q':
1700 				{
1701 					ptr = getCoord( ptr, x1 );
1702 					ptr = getCoord( ptr, y1 );
1703 					ptr = getCoord( ptr, tox );
1704 					ptr = getCoord( ptr, toy );
1705 					px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
1706 					py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
1707 					px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
1708 					py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
1709 					px3 = relative ? curx + tox : tox;
1710 					py3 = relative ? cury + toy : toy;
1711 					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1712 					contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
1713 					contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
1714 					curx = relative ? curx + tox : tox;
1715 					cury = relative ? cury + toy : toy;
1716 					break;
1717 				}
1718 			case 't':
1719 				relative = true;
1720 			case 'T':
1721 				{
1722 					ptr = getCoord(ptr, tox);
1723 					ptr = getCoord(ptr, toy);
1724 					xc = 2 * curx - contrlx;
1725 					yc = 2 * cury - contrly;
1726 					px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
1727 					py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
1728 					px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
1729 					py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
1730 					px3 = relative ? curx + tox : tox;
1731 					py3 = relative ? cury + toy : toy;
1732 					svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1733 					contrlx = xc;
1734 					contrly = yc;
1735 					curx = relative ? curx + tox : tox;
1736 					cury = relative ? cury + toy : toy;
1737 					break;
1738 				}
1739 			case 'a':
1740 				relative = true;
1741 			case 'A':
1742 				{
1743 					bool largeArc, sweep;
1744 					double angle, rx, ry;
1745 					ptr = getCoord( ptr, rx );
1746 					ptr = getCoord( ptr, ry );
1747 					ptr = getCoord( ptr, angle );
1748 					ptr = getCoord( ptr, tox );
1749 					largeArc = tox == 1;
1750 					ptr = getCoord( ptr, tox );
1751 					sweep = tox == 1;
1752 					ptr = getCoord( ptr, tox );
1753 					ptr = getCoord( ptr, toy );
1754 					calculateArc(ite, relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
1755 				}
1756 			}
1757 			lastCommand = command;
1758 			if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
1759 			{
1760 				// there are still coords in this command
1761 				if (command == 'M')
1762 					command = 'L';
1763 				else if (command == 'm')
1764 					command = 'l';
1765 			}
1766 			else
1767 				command = *(ptr++);
1768 
1769 			if (lastCommand != 'C' && lastCommand != 'c' &&
1770 			        lastCommand != 'S' && lastCommand != 's' &&
1771 			        lastCommand != 'Q' && lastCommand != 'q' &&
1772 			        lastCommand != 'T' && lastCommand != 't')
1773 			{
1774 				contrlx = curx;
1775 				contrly = cury;
1776 			}
1777 		}
1778 		if ((lastCommand != 'z') && (lastCommand != 'Z'))
1779 			ret = true;
1780 		if (ite->size() > 2)
1781 		{
1782 			if ((ite->point(0).x() == ite->point(ite->size()-2).x()) && (ite->point(0).y() == ite->point(ite->size()-2).y()))
1783 				ret = false;
1784 		}
1785 	}
1786 	return ret;
1787 }
1788 
calculateArc(FPointArray * ite,bool relative,double & curx,double & cury,double angle,double x,double y,double r1,double r2,bool largeArcFlag,bool sweepFlag)1789 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)
1790 {
1791 	double sin_th, cos_th;
1792 	double a00, a01, a10, a11;
1793 	double x0, y0, x1, y1, xc, yc;
1794 	double d, sfactor, sfactor_sq;
1795 	double th0, th1, th_arc;
1796 	int i, n_segs;
1797 	sin_th = sin(angle * (M_PI / 180.0));
1798 	cos_th = cos(angle * (M_PI / 180.0));
1799 	double dx;
1800 	if (!relative)
1801 		dx = (curx - x) / 2.0;
1802 	else
1803 		dx = -x / 2.0;
1804 	double dy;
1805 	if (!relative)
1806 		dy = (cury - y) / 2.0;
1807 	else
1808 		dy = -y / 2.0;
1809 	double _x1 =  cos_th * dx + sin_th * dy;
1810 	double _y1 = -sin_th * dx + cos_th * dy;
1811 	double Pr1 = r1 * r1;
1812 	double Pr2 = r2 * r2;
1813 	double Px = _x1 * _x1;
1814 	double Py = _y1 * _y1;
1815 	double check = Px / Pr1 + Py / Pr2;
1816 	if (check > 1)
1817 	{
1818 		r1 = r1 * sqrt(check);
1819 		r2 = r2 * sqrt(check);
1820 	}
1821 	a00 = cos_th / r1;
1822 	a01 = sin_th / r1;
1823 	a10 = -sin_th / r2;
1824 	a11 = cos_th / r2;
1825 	x0 = a00 * curx + a01 * cury;
1826 	y0 = a10 * curx + a11 * cury;
1827 	if (!relative)
1828 		x1 = a00 * x + a01 * y;
1829 	else
1830 		x1 = a00 * (curx + x) + a01 * (cury + y);
1831 	if (!relative)
1832 		y1 = a10 * x + a11 * y;
1833 	else
1834 		y1 = a10 * (curx + x) + a11 * (cury + y);
1835 	d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
1836 	sfactor_sq = 1.0 / d - 0.25;
1837 	if (sfactor_sq < 0)
1838 		sfactor_sq = 0;
1839 	sfactor = sqrt(sfactor_sq);
1840 	if (sweepFlag == largeArcFlag)
1841 		sfactor = -sfactor;
1842 	xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
1843 	yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
1844 
1845 	th0 = atan2(y0 - yc, x0 - xc);
1846 	th1 = atan2(y1 - yc, x1 - xc);
1847 	th_arc = th1 - th0;
1848 	if (th_arc < 0 && sweepFlag)
1849 		th_arc += 2 * M_PI;
1850 	else if (th_arc > 0 && !sweepFlag)
1851 		th_arc -= 2 * M_PI;
1852 	n_segs = static_cast<int>(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))));
1853 	for (i = 0; i < n_segs; i++)
1854 	{
1855 		{
1856 			double sin_th, cos_th;
1857 			double a00, a01, a10, a11;
1858 			double x1, y1, x2, y2, x3, y3;
1859 			double t;
1860 			double th_half;
1861 			double _th0 = th0 + i * th_arc / n_segs;
1862 			double _th1 = th0 + (i + 1) * th_arc / n_segs;
1863 			sin_th = sin(angle * (M_PI / 180.0));
1864 			cos_th = cos(angle * (M_PI / 180.0));
1865 			a00 = cos_th * r1;
1866 			a01 = -sin_th * r2;
1867 			a10 = sin_th * r1;
1868 			a11 = cos_th * r2;
1869 			th_half = 0.5 * (_th1 - _th0);
1870 			t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
1871 			x1 = xc + cos(_th0) - t * sin(_th0);
1872 			y1 = yc + sin(_th0) + t * cos(_th0);
1873 			x3 = xc + cos(_th1);
1874 			y3 = yc + sin(_th1);
1875 			x2 = x3 + t * sin(_th1);
1876 			y2 = y3 - t * cos(_th1);
1877 			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 );
1878 		}
1879 	}
1880 	if (!relative)
1881 		curx = x;
1882 	else
1883 		curx += x;
1884 	if (!relative)
1885 		cury = y;
1886 	else
1887 		cury += y;
1888 }
1889 
svgMoveTo(double x1,double y1)1890 void OODPlug::svgMoveTo(double x1, double y1)
1891 {
1892 	CurrX = x1;
1893 	CurrY = y1;
1894 	StartX = x1;
1895 	StartY = y1;
1896 	PathLen = 0;
1897 }
1898 
svgLineTo(FPointArray * i,double x1,double y1)1899 void OODPlug::svgLineTo(FPointArray *i, double x1, double y1)
1900 {
1901 	if ((!FirstM) && (WasM))
1902 	{
1903 		i->setMarker();
1904 		PathLen += 4;
1905 	}
1906 	FirstM = false;
1907 	WasM = false;
1908 	if (i->size() > 3)
1909 	{
1910 		const FPoint& b1 = i->point(i->size()-4);
1911 		const FPoint& b2 = i->point(i->size()-3);
1912 		const FPoint& b3 = i->point(i->size()-2);
1913 		const FPoint& b4 = i->point(i->size()-1);
1914 		FPoint n1 = FPoint(CurrX, CurrY);
1915 		FPoint n2 = FPoint(x1, y1);
1916 		if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2))
1917 			return;
1918 	}
1919 	i->addPoint(FPoint(CurrX, CurrY));
1920 	i->addPoint(FPoint(CurrX, CurrY));
1921 	i->addPoint(FPoint(x1, y1));
1922 	i->addPoint(FPoint(x1, y1));
1923 	CurrX = x1;
1924 	CurrY = y1;
1925 	PathLen += 4;
1926 }
1927 
svgCurveToCubic(FPointArray * i,double x1,double y1,double x2,double y2,double x3,double y3)1928 void OODPlug::svgCurveToCubic(FPointArray *i, double x1, double y1, double x2, double y2, double x3, double y3)
1929 {
1930 	if ((!FirstM) && (WasM))
1931 	{
1932 		i->setMarker();
1933 		PathLen += 4;
1934 	}
1935 	FirstM = false;
1936 	WasM = false;
1937 	if (PathLen > 3)
1938 	{
1939 		const FPoint& b1 = i->point(i->size()-4);
1940 		const FPoint& b2 = i->point(i->size()-3);
1941 		const FPoint& b3 = i->point(i->size()-2);
1942 		const FPoint& b4 = i->point(i->size()-1);
1943 		FPoint n1 = FPoint(CurrX, CurrY);
1944 		FPoint n2 = FPoint(x1, y1);
1945 		FPoint n3 = FPoint(x3, y3);
1946 		FPoint n4 = FPoint(x2, y2);
1947 		if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4))
1948 			return;
1949 	}
1950 	i->addPoint(FPoint(CurrX, CurrY));
1951 	i->addPoint(FPoint(x1, y1));
1952 	i->addPoint(FPoint(x3, y3));
1953 	i->addPoint(FPoint(x2, y2));
1954 	CurrX = x3;
1955 	CurrY = y3;
1956 	PathLen += 4;
1957 }
1958 
svgClosePath(FPointArray * i)1959 void OODPlug::svgClosePath(FPointArray *i)
1960 {
1961 	if (PathLen > 2)
1962 	{
1963 		if ((PathLen == 4) || (i->point(i->size()-2).x() != StartX) || (i->point(i->size()-2).y() != StartY))
1964 		{
1965 			i->addPoint(i->point(i->size()-2));
1966 			i->addPoint(i->point(i->size()-3));
1967 			i->addPoint(FPoint(StartX, StartY));
1968 			i->addPoint(FPoint(StartX, StartY));
1969 		}
1970 	}
1971 }
1972 
~OODPlug()1973 OODPlug::~OODPlug()
1974 {
1975 	delete tmpSel;
1976 	// it's probably needed as QHash() dos not support autocleaning
1977 	m_styles.clear();
1978 	m_draws.clear();
1979 }
1980 
1981 
1982