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