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 							 -------------------
9 	begin                : Sun Jan  3 2016
10 	copyright            : (C) 2016 by Franz Schmid
11 	email                : Franz.Schmid@altmuehlnet.de
12  ***************************************************************************/
13 #include "importodt.h"
14 
15 #include <QApplication>
16 #include <QByteArray>
17 #include <QScopedPointer>
18 
19 #include "scribusdoc.h"
20 #include "styles/charstyle.h"
21 #include "styles/paragraphstyle.h"
22 #include "third_party/zip/scribus_zip.h"
23 #include "prefsmanager.h"
24 #include "scclocale.h"
25 #include "ui/missing.h"
26 #include "util.h"
27 
28 
FileFormatName()29 QString FileFormatName()
30 {
31 	return QObject::tr("ODT Document");
32 }
33 
FileExtensions()34 QStringList FileExtensions()
35 {
36 	QStringList ret;
37 	ret.append("odt");
38 	ret.append("fodt");
39 	return ret;
40 }
41 
GetText2(const QString & filename,const QString & encoding,bool textOnly,bool prefix,bool append,PageItem * textItem)42 void GetText2(const QString& filename, const QString& encoding, bool textOnly, bool prefix, bool append, PageItem *textItem)
43 {
44 	ODTIm* docxim = new ODTIm(filename, textItem, textOnly, prefix, append);
45 	delete docxim;
46 }
47 
ODTIm(const QString & fileName,PageItem * textItem,bool textOnly,bool prefix,bool append)48 ODTIm::ODTIm(const QString& fileName, PageItem *textItem, bool textOnly, bool prefix, bool append)
49 {
50 	m_Doc = textItem->doc();
51 	m_item = textItem;
52 	m_prefixName = prefix;
53 	m_append = append;
54 	QFileInfo fi = QFileInfo(fileName);
55 	QString ext = fi.suffix().toLower();
56 	if (ext == "fodt")
57 	{
58 		QByteArray f;
59 		loadRawText(fileName, f);
60 		QDomDocument designMapDom;
61 		QString errorMsg;
62 		int errorLine = 0;
63 		int errorColumn = 0;
64 		if (!designMapDom.setContent(f, &errorMsg, &errorLine, &errorColumn))
65 		{
66 			qDebug() << "Error loading File" << errorMsg << "at Line" << errorLine << "Column" << errorColumn;
67 			return;
68 		}
69 		if (textOnly)
70 			parseRawDocReferenceXML(designMapDom);
71 		else
72 			parseDocReferenceXML(designMapDom);
73 	}
74 	else
75 	{
76 		uz = new ScZipHandler();
77 		if (uz)
78 		{
79 			if (!uz->open(fileName))
80 			{
81 				delete uz;
82 				QByteArray f;
83 				loadRawText(fileName, f);
84 				QDomDocument designMapDom;
85 				QString errorMsg;
86 				int errorLine = 0;
87 				int errorColumn = 0;
88 				if (designMapDom.setContent(f, &errorMsg, &errorLine, &errorColumn))
89 				{
90 					if (textOnly)
91 						parseRawDocReferenceXML(designMapDom);
92 					else
93 						parseDocReferenceXML(designMapDom);
94 				}
95 				else
96 				{
97 					qDebug() << "Error loading File" << errorMsg << "at Line" << errorLine << "Column" << errorColumn;
98 					return;
99 				}
100 			}
101 			else
102 			{
103 				if (textOnly)
104 				{
105 					if (uz->contains("content.xml"))
106 						parseRawDocReference("content.xml");
107 				}
108 				else
109 				{
110 					if (uz->contains("styles.xml"))
111 					{
112 						if (parseStyleSheets("styles.xml"))
113 						{
114 							if (uz->contains("content.xml"))
115 								parseDocReference("content.xml");
116 						}
117 					}
118 					else
119 					{
120 						if (uz->contains("content.xml"))
121 							parseDocReference("content.xml");
122 					}
123 				}
124 				uz->close();
125 				delete uz;
126 			}
127 		}
128 	}
129 	textItem->itemText.trim();
130 	textItem->itemText.invalidateLayout();
131 }
132 
~ODTIm()133 ODTIm::~ODTIm()
134 {
135 }
136 
137 /* Raw Text import */
138 
parseRawDocReference(const QString & designMap)139 bool ODTIm::parseRawDocReference(const QString& designMap)
140 {
141 	QByteArray xmlData;
142 	QDomDocument designMapDom;
143 	if (!uz->read(designMap, xmlData))
144 		return false;
145 
146 	QString errorMsg;
147 	int errorLine = 0;
148 	int errorColumn = 0;
149 	if (!designMapDom.setContent(xmlData, false, &errorMsg, &errorLine, &errorColumn))
150 	{
151 		qDebug() << "Error loading File" << errorMsg << "at Line" << errorLine << "Column" << errorColumn;
152 		return false;
153 	}
154 	return parseRawDocReferenceXML(designMapDom);
155 }
156 
parseRawDocReferenceXML(QDomDocument & designMapDom)157 bool ODTIm::parseRawDocReferenceXML(QDomDocument &designMapDom)
158 {
159 	QDomElement docElem = designMapDom.documentElement();
160 	for (QDomElement drawPag = docElem.firstChildElement(); !drawPag.isNull(); drawPag = drawPag.nextSiblingElement())
161 	{
162 		if (drawPag.tagName() == "office:body")
163 		{
164 			for (QDomElement sp = drawPag.firstChildElement(); !sp.isNull(); sp = sp.nextSiblingElement() )
165 			{
166 				if (sp.tagName() == "office:text")
167 				{
168 					parseRawText(sp, m_item);
169 				}
170 			}
171 		}
172 	}
173 	return true;
174 }
175 
parseRawTextSpan(QDomElement & elem,PageItem * item,ParagraphStyle & tmpStyle,CharStyle & tmpCStyle,int & posC)176 void ODTIm::parseRawTextSpan(QDomElement &elem, PageItem* item, ParagraphStyle &tmpStyle, CharStyle &tmpCStyle, int &posC)
177 {
178 	if (!elem.hasChildNodes())
179 		return;
180 
181 	for (QDomNode spn = elem.firstChild(); !spn.isNull(); spn = spn.nextSibling())
182 	{
183 		QString txt = "";
184 		QDomElement spEl = spn.toElement();
185 		if (spn.nodeName() == "#text")
186 			txt = spn.nodeValue();
187 		else if (spn.nodeName() == "text:span")
188 			parseRawTextSpan(spEl, item, tmpStyle, tmpCStyle, posC);
189 		else if (spn.nodeName() == "text:s")
190 		{
191 			if (spEl.hasAttribute("text:c"))
192 			{
193 				int n = spEl.attribute("text:c").toInt();
194 				for (int nn = 0; nn < n; nn++)
195 				{
196 					txt += " ";
197 				}
198 			}
199 			else
200 				txt = " ";
201 		}
202 		else if (spn.nodeName() == "text:tab")
203 			txt = SpecialChars::TAB;
204 		else if (spn.nodeName() == "text:line-break")
205 			txt = SpecialChars::LINEBREAK;
206 		if (!txt.isEmpty())
207 		{
208 			txt.replace(QChar(0xAD), SpecialChars::SHYPHEN);
209 			txt.replace(QChar(0x2011), SpecialChars::NBHYPHEN);
210 			txt.replace(QChar(0xA0), SpecialChars::NBSPACE);
211 			insertChars(item, txt, tmpStyle, tmpCStyle, posC);
212 		}
213 	}
214 }
215 
parseRawTextParagraph(QDomNode & elem,PageItem * item,ParagraphStyle & newStyle,int & posC)216 void ODTIm::parseRawTextParagraph(QDomNode &elem, PageItem* item, ParagraphStyle &newStyle, int &posC)
217 {
218 	CharStyle tmpCStyle = newStyle.charStyle();
219 	if (elem.hasChildNodes())
220 	{
221 		for (QDomNode spn = elem.firstChild(); !spn.isNull(); spn = spn.nextSibling())
222 		{
223 			QString txt = "";
224 			QDomElement spEl = spn.toElement();
225 			if (spn.nodeName() == "#text")
226 				txt = spn.nodeValue();
227 			else if (spn.nodeName() == "text:span")
228 				parseRawTextSpan(spEl, item, newStyle, tmpCStyle, posC);
229 			else if (spn.nodeName() == "text:s")
230 			{
231 				if (spEl.hasAttribute("text:c"))
232 				{
233 					int n = spEl.attribute("text:c").toInt();
234 					for (int nn = 0; nn < n; nn++)
235 					{
236 						txt += " ";
237 					}
238 				}
239 				else
240 					txt = " ";
241 			}
242 			else if (spn.nodeName() == "text:tab")
243 				txt = SpecialChars::TAB;
244 			else if (spn.nodeName() == "text:line-break")
245 				txt = SpecialChars::LINEBREAK;
246 			if (!txt.isEmpty())
247 			{
248 				txt.replace(QChar(0xAD), SpecialChars::SHYPHEN);
249 				txt.replace(QChar(0x2011), SpecialChars::NBHYPHEN);
250 				txt.replace(QChar(0xA0), SpecialChars::NBSPACE);
251 				insertChars(item, txt, newStyle, tmpCStyle, posC);
252 			}
253 		}
254 	}
255 	item->itemText.insertChars(posC, SpecialChars::PARSEP);
256 	item->itemText.applyStyle(posC, newStyle);
257 	posC = item->itemText.length();
258 }
259 
parseRawText(QDomElement & elem,PageItem * item)260 void ODTIm::parseRawText(QDomElement &elem, PageItem* item)
261 {
262 	QString pStyleD = CommonStrings::DefaultParagraphStyle;
263 	ParagraphStyle newStyle;
264 	newStyle.setDefaultStyle(false);
265 	newStyle.setParent(pStyleD);
266 	if (!m_append)
267 	{
268 		item->itemText.clear();
269 		item->itemText.setDefaultStyle(newStyle);
270 	}
271 	int posC = item->itemText.length();
272 	for (QDomNode para = elem.firstChild(); !para.isNull(); para = para.nextSibling())
273 	{
274 		if ((para.nodeName() == "text:p") || (para.nodeName() == "text:h"))
275 			parseRawTextParagraph(para, item, newStyle, posC);
276 		else if (para.nodeName() == "text:list")
277 		{
278 			if (!para.hasChildNodes())
279 				continue;
280 			for (QDomNode spn = para.firstChild(); !spn.isNull(); spn = spn.nextSibling())
281 			{
282 				if (spn.nodeName() == "text:list-item")
283 				{
284 					if (!spn.hasChildNodes())
285 						continue;
286 					for (QDomNode spp = spn.firstChild(); !spp.isNull(); spp = spp.nextSibling())
287 					{
288 						if (spp.nodeName() == "text:p")
289 						{
290 							parseRawTextParagraph(spp, item, newStyle, posC);
291 						}
292 					}
293 				}
294 			}
295 		}
296 		else if (para.nodeName() == "text:section")
297 		{
298 			if (!para.hasChildNodes())
299 				continue;
300 			for (QDomNode spn = para.firstChild(); !spn.isNull(); spn = spn.nextSibling())
301 			{
302 				if (spn.nodeName() == "text:p")
303 				{
304 					parseRawTextParagraph(spn, item, newStyle, posC);
305 				}
306 			}
307 		}
308 	}
309 }
310 
311 /* Styled Text import */
312 
parseStyleSheets(const QString & designMap)313 bool ODTIm::parseStyleSheets(const QString& designMap)
314 {
315 	QByteArray xmlData;
316 	QDomDocument designMapDom;
317 	if (!uz->read(designMap, xmlData))
318 		return false;
319 
320 	QString errorMsg;
321 	int errorLine = 0;
322 	int errorColumn = 0;
323 	if (!designMapDom.setContent(xmlData, false, &errorMsg, &errorLine, &errorColumn))
324 	{
325 		qDebug() << "Error loading File" << errorMsg << "at Line" << errorLine << "Column" << errorColumn;
326 		return false;
327 	}
328 	return parseStyleSheetsXML(designMapDom);
329 }
330 
parseStyleSheetsXML(QDomDocument & designMapDom)331 bool ODTIm::parseStyleSheetsXML(QDomDocument &designMapDom)
332 {
333 	QDomElement docElem = designMapDom.documentElement();
334 	for (QDomElement sp = docElem.firstChildElement(); !sp.isNull(); sp = sp.nextSiblingElement() )
335 	{
336 		if (sp.tagName() == "office:font-face-decls")
337 		{
338 			for (QDomElement spf = sp.firstChildElement(); !spf.isNull(); spf = spf.nextSiblingElement() )
339 			{
340 				if (spf.tagName() == "style:font-face")
341 				{
342 					if (!spf.attribute("style:name").isEmpty())
343 					{
344 						QString fontFamily = spf.attribute("svg:font-family");
345 						if (fontFamily.startsWith(QChar('\'')))
346 							fontFamily = fontFamily.mid(1);
347 						if (fontFamily.endsWith(QChar('\'')))
348 							fontFamily.chop(1);
349 						m_fontMap.insert(spf.attribute("style:name"), fontFamily);
350 					}
351 				}
352 			}
353 		}
354 		else if (sp.tagName() == "office:styles")
355 			parseStyles(sp, "styles");
356 		else if (sp.tagName() == "office:automatic-styles")
357 			parseStyles(sp, "auto");
358 	}
359 	return true;
360 }
361 
parseStyles(QDomElement & sp,const QString & type)362 void ODTIm::parseStyles(QDomElement &sp, const QString& type)
363 {
364 	for (QDomElement spd = sp.firstChildElement(); !spd.isNull(); spd = spd.nextSiblingElement() )
365 	{
366 		if (spd.tagName() == "style:default-style")
367 		{
368 			DrawStyle currStyle;
369 			currStyle.styleOrigin = AttributeValue(type);
370 			for (QDomElement spe = spd.firstChildElement(); !spe.isNull(); spe = spe.nextSiblingElement() )
371 			{
372 				if (spe.tagName() == "style:paragraph-properties")
373 				{
374 					currStyle.margin_top = AttributeValue(spe.attribute("fo:margin-top", ""));
375 					currStyle.margin_bottom = AttributeValue(spe.attribute("fo:margin-bottom", ""));
376 					currStyle.margin_left = AttributeValue(spe.attribute("fo:margin-left", ""));
377 					currStyle.margin_right = AttributeValue(spe.attribute("fo:margin-right", ""));
378 					currStyle.textIndent = AttributeValue(spe.attribute("fo:text-indent", ""));
379 					currStyle.textAlign = AttributeValue(spe.attribute("fo:text-align", ""));
380 					currStyle.lineHeight = AttributeValue(spe.attribute("fo:line-height", ""));
381 					currStyle.parBackgroundColor = AttributeValue(spe.attribute("fo:background-color", ""));
382 					currStyle.breakAfter = AttributeValue(spe.attribute("fo:break-after", ""));
383 					currStyle.breakBefore = AttributeValue(spe.attribute("fo:break-before", ""));
384 					if (spe.hasChildNodes())
385 					{
386 						for (QDomElement spt = spe.firstChildElement(); !spt.isNull(); spt = spt.nextSiblingElement() )
387 						{
388 							if (spt.tagName() == "style:tab-stops")
389 							{
390 								QString tabDists = "";
391 								QString tabTypes = "";
392 								for (QDomElement spte = spt.firstChildElement(); !spte.isNull(); spte = spte.nextSiblingElement() )
393 								{
394 									if (spte.tagName() == "style:tab-stop")
395 									{
396 										if (spte.hasAttribute("style:position"))
397 											tabDists.append(spte.attribute("style:position") + ";");
398 										else
399 											tabDists.append("0;");
400 										if (spte.hasAttribute("style:type"))
401 											tabTypes.append(spte.attribute("style:type") + " ");
402 										else
403 											tabTypes.append("left ");
404 									}
405 								}
406 								currStyle.tabDists = AttributeValue(tabDists);
407 								currStyle.tabTypes = AttributeValue(tabTypes);
408 							}
409 						}
410 					}
411 				}
412 				else if (spe.tagName() == "style:text-properties")
413 				{
414 					currStyle.fontName = AttributeValue(spe.attribute("style:font-name", ""));
415 					if (!currStyle.fontName.valid)
416 						currStyle.fontName = AttributeValue(spe.attribute("fo:font-family", ""));
417 					currStyle.fontSize = AttributeValue(spe.attribute("fo:font-size", ""));
418 					currStyle.fontColor = AttributeValue(spe.attribute("fo:color", ""));
419 					currStyle.fontStyle = AttributeValue(spe.attribute("fo:font-style", ""));
420 					currStyle.fontWeight = AttributeValue(spe.attribute("fo:font-weight", ""));
421 					currStyle.textBackgroundColor = AttributeValue(spe.attribute("fo:background-color", ""));
422 					currStyle.textPos = AttributeValue(spe.attribute("style:text-position", ""));
423 					currStyle.textOutline = AttributeValue(spe.attribute("style:text-outline", ""));
424 					currStyle.textUnderline = AttributeValue(spe.attribute("style:text-underline-style", ""));
425 					currStyle.textUnderlineWords = AttributeValue(spe.attribute("style:text-underline-mode", ""));
426 					currStyle.textUnderlineColor = AttributeValue(spe.attribute("style:text-underline-color", ""));
427 					currStyle.textStrikeThrough = AttributeValue(spe.attribute("style:text-line-through-style", ""));
428 					currStyle.textShadow = AttributeValue(spe.attribute("fo:text-shadow", ""));
429 					currStyle.fontVariant = AttributeValue(spe.attribute("fo:font-variant", ""));
430 				}
431 			}
432 			if (spd.attribute("style:family") == "paragraph")
433 				parDefaultStyle = currStyle;
434 			else if (spd.attribute("style:family") == "text")
435 				txtDefaultStyle = currStyle;
436 		}
437 		else if (spd.tagName() == "style:style")
438 		{
439 			DrawStyle currStyle;
440 			currStyle.parentStyle = AttributeValue(spd.attribute("style:parent-style-name", ""));
441 			if (!currStyle.parentStyle.valid)
442 			{
443 				if (spd.attribute("style:family") == "paragraph")
444 					currStyle = parDefaultStyle;
445 				else if (spd.attribute("style:family") == "text")
446 					currStyle = txtDefaultStyle;
447 			}
448 			currStyle.styleType = AttributeValue(spd.attribute("style:family", ""));
449 			currStyle.styleOrigin = AttributeValue(type);
450 			for (QDomElement spe = spd.firstChildElement(); !spe.isNull(); spe = spe.nextSiblingElement() )
451 			{
452 				if (spe.tagName() == "style:paragraph-properties")
453 				{
454 					currStyle.margin_top = AttributeValue(spe.attribute("fo:margin-top", ""));
455 					currStyle.margin_bottom = AttributeValue(spe.attribute("fo:margin-bottom", ""));
456 					currStyle.margin_left = AttributeValue(spe.attribute("fo:margin-left", ""));
457 					currStyle.margin_right = AttributeValue(spe.attribute("fo:margin-right", ""));
458 					currStyle.textIndent = AttributeValue(spe.attribute("fo:text-indent", ""));
459 					currStyle.textAlign = AttributeValue(spe.attribute("fo:text-align", ""));
460 					currStyle.lineHeight = AttributeValue(spe.attribute("fo:line-height", ""));
461 					currStyle.parBackgroundColor = AttributeValue(spe.attribute("fo:background-color", ""));
462 					currStyle.breakAfter = AttributeValue(spe.attribute("fo:break-after", ""));
463 					currStyle.breakBefore = AttributeValue(spe.attribute("fo:break-before", ""));
464 					if (spe.hasChildNodes())
465 					{
466 						for (QDomElement spt = spe.firstChildElement(); !spt.isNull(); spt = spt.nextSiblingElement() )
467 						{
468 							if (spt.tagName() == "style:tab-stops")
469 							{
470 								QString tabDists = "";
471 								QString tabTypes = "";
472 								for (QDomElement spte = spt.firstChildElement(); !spte.isNull(); spte = spte.nextSiblingElement() )
473 								{
474 									if (spte.tagName() == "style:tab-stop")
475 									{
476 										if (spte.hasAttribute("style:position"))
477 											tabDists.append(spte.attribute("style:position") + ";");
478 										else
479 											tabDists.append("0;");
480 										if (spte.hasAttribute("style:type"))
481 											tabTypes.append(spte.attribute("style:type") + " ");
482 										else
483 											tabTypes.append("left ");
484 									}
485 								}
486 								currStyle.tabDists = AttributeValue(tabDists);
487 								currStyle.tabTypes = AttributeValue(tabTypes);
488 							}
489 						}
490 					}
491 				}
492 				else if (spe.tagName() == "style:text-properties")
493 				{
494 					currStyle.fontName = AttributeValue(spe.attribute("style:font-name", ""));
495 					if (!currStyle.fontName.valid)
496 						currStyle.fontName = AttributeValue(spe.attribute("fo:font-family", ""));
497 					currStyle.fontSize = AttributeValue(spe.attribute("fo:font-size", ""));
498 					currStyle.fontColor = AttributeValue(spe.attribute("fo:color", ""));
499 					currStyle.fontStyle = AttributeValue(spe.attribute("fo:font-style", ""));
500 					currStyle.fontWeight = AttributeValue(spe.attribute("fo:font-weight", ""));
501 					currStyle.textBackgroundColor = AttributeValue(spe.attribute("fo:background-color", ""));
502 					currStyle.textPos = AttributeValue(spe.attribute("style:text-position", ""));
503 					currStyle.textOutline = AttributeValue(spe.attribute("style:text-outline", ""));
504 					currStyle.textUnderline = AttributeValue(spe.attribute("style:text-underline-style", ""));
505 					currStyle.textUnderlineWords = AttributeValue(spe.attribute("style:text-underline-mode", ""));
506 					currStyle.textUnderlineColor = AttributeValue(spe.attribute("style:text-underline-color", ""));
507 					currStyle.textStrikeThrough = AttributeValue(spe.attribute("style:text-line-through-style", ""));
508 					currStyle.textShadow = AttributeValue(spe.attribute("fo:text-shadow", ""));
509 					currStyle.fontVariant = AttributeValue(spe.attribute("fo:font-variant", ""));
510 				}
511 			}
512 			currStyle.displayName = AttributeValue(spd.attribute("style:display-name", ""));
513 			m_Styles.insert(spd.attribute("style:name"), currStyle);
514 			if (type == "styles")
515 			{
516 				ObjStyleODT tmpOStyle;
517 				resolveStyle(tmpOStyle, spd.attribute("style:name"));
518 				if (spd.attribute("style:family") == "paragraph")
519 				{
520 					ParagraphStyle newStyle;
521 					newStyle.erase();
522 					newStyle.setDefaultStyle(false);
523 					newStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
524 					QString styleName = spd.attribute("style:name");
525 					if (currStyle.displayName.valid)
526 						styleName = currStyle.displayName.value;
527 					if (m_prefixName)
528 						newStyle.setName(m_item->itemName() + "_" + styleName);
529 					else
530 						newStyle.setName(styleName);
531 					QString parentName = CommonStrings::DefaultParagraphStyle;
532 					if (currStyle.parentStyle.valid)
533 					{
534 						if (m_Styles.contains(currStyle.parentStyle.value))
535 						{
536 							DrawStyle pStyle = m_Styles[currStyle.parentStyle.value];
537 							parentName = currStyle.parentStyle.value;
538 							if (pStyle.displayName.valid)
539 								parentName = pStyle.displayName.value;
540 						}
541 					}
542 					if (m_prefixName)
543 						newStyle.setParent(m_item->itemName() + "_" + parentName);
544 					else
545 						newStyle.setParent(parentName);
546 					applyParagraphStyle(newStyle, tmpOStyle);
547 					applyCharacterStyle(newStyle.charStyle(), tmpOStyle);
548 					StyleSet<ParagraphStyle>tmp;
549 					tmp.create(newStyle);
550 					m_Doc->redefineStyles(tmp, false);
551 				}
552 				else if (spd.attribute("style:family") == "text")
553 				{
554 					CharStyle newStyle;
555 					newStyle.setDefaultStyle(false);
556 					QString styleName = spd.attribute("style:name");
557 					if (currStyle.displayName.valid)
558 						styleName = currStyle.displayName.value;
559 					if (m_prefixName)
560 						newStyle.setName(m_item->itemName() + "_" + styleName);
561 					else
562 						newStyle.setName(styleName);
563 					newStyle.setParent(CommonStrings::DefaultCharacterStyle);
564 					applyCharacterStyle(newStyle, tmpOStyle);
565 					StyleSet<CharStyle> temp;
566 					temp.create(newStyle);
567 					m_Doc->redefineCharStyles(temp, false);
568 				}
569 			}
570 		}
571 	}
572 }
573 
parseDocReference(const QString & designMap)574 bool ODTIm::parseDocReference(const QString& designMap)
575 {
576 	QByteArray xmlData;
577 	QDomDocument designMapDom;
578 	if (!uz->read(designMap, xmlData))
579 		return false;
580 
581 	QString errorMsg;
582 	int errorLine = 0;
583 	int errorColumn = 0;
584 	if (!designMapDom.setContent(xmlData, false, &errorMsg, &errorLine, &errorColumn))
585 	{
586 		qDebug() << "Error loading File" << errorMsg << "at Line" << errorLine << "Column" << errorColumn;
587 		return false;
588 	}
589 	return parseDocReferenceXML(designMapDom);
590 }
591 
parseDocReferenceXML(QDomDocument & designMapDom)592 bool ODTIm::parseDocReferenceXML(QDomDocument &designMapDom)
593 {
594 	QDomElement docElem = designMapDom.documentElement();
595 	for (QDomElement drawPag = docElem.firstChildElement(); !drawPag.isNull(); drawPag = drawPag.nextSiblingElement())
596 	{
597 		if (drawPag.tagName() == "office:font-face-decls")
598 		{
599 			for (QDomElement spf = drawPag.firstChildElement(); !spf.isNull(); spf = spf.nextSiblingElement() )
600 			{
601 				if (spf.tagName() == "style:font-face")
602 				{
603 					if (!spf.attribute("style:name").isEmpty())
604 					{
605 						QString fontFamily = spf.attribute("svg:font-family");
606 						if (fontFamily.startsWith(QChar('\'')))
607 							fontFamily = fontFamily.mid(1);
608 						if (fontFamily.endsWith(QChar('\'')))
609 							fontFamily.chop(1);
610 						m_fontMap.insert(spf.attribute("style:name"), fontFamily);
611 					}
612 				}
613 			}
614 		}
615 		else if (drawPag.tagName() == "office:styles")
616 			parseStyles(drawPag, "styles");
617 		else if (drawPag.tagName() == "office:automatic-styles")
618 			parseStyles(drawPag, "auto");
619 		else if (drawPag.tagName() == "office:body")
620 		{
621 			for (QDomElement sp = drawPag.firstChildElement(); !sp.isNull(); sp = sp.nextSiblingElement() )
622 			{
623 				if (sp.tagName() == "office:text")
624 				{
625 					ObjStyleODT tmpOStyle;
626 					resolveStyle(tmpOStyle, "standard");
627 					parseText(sp, m_item, tmpOStyle);
628 				}
629 			}
630 		}
631 	}
632 	return true;
633 }
634 
parseTextSpan(QDomElement & elem,PageItem * item,ParagraphStyle & tmpStyle,CharStyle & tmpCStyle,ObjStyleODT & tmpOStyle,int & posC)635 void ODTIm::parseTextSpan(QDomElement &elem, PageItem* item, ParagraphStyle &tmpStyle, CharStyle &tmpCStyle, ObjStyleODT &tmpOStyle, int &posC)
636 {
637 	ObjStyleODT odtStyle = tmpOStyle;
638 	CharStyle cStyle = tmpCStyle;
639 
640 	QString textStyleName = elem.attribute("text:style-name");
641 	if (textStyleName.length() > 0)
642 	{
643 		resolveStyle(odtStyle, textStyleName);
644 		m_textStylesStack.push(textStyleName);
645 	}
646 
647 	applyCharacterStyle(cStyle, odtStyle);
648 	if (!elem.hasChildNodes())
649 		return;
650 
651 	for (QDomNode spn = elem.firstChild(); !spn.isNull(); spn = spn.nextSibling())
652 	{
653 		QString txt = "";
654 		QDomElement spEl = spn.toElement();
655 		if (spn.nodeName() == "#text")
656 			txt = spn.nodeValue();
657 		else if (spn.nodeName() == "text:span")
658 			parseTextSpan(spEl, item, tmpStyle, cStyle, odtStyle, posC);
659 		else if (spn.nodeName() == "text:s")
660 		{
661 			if (spEl.hasAttribute("text:c"))
662 			{
663 				int n = spEl.attribute("text:c").toInt();
664 				for (int nn = 0; nn < n; nn++)
665 				{
666 					txt += " ";
667 				}
668 			}
669 			else
670 				txt = " ";
671 		}
672 		else if (spn.nodeName() == "text:tab")
673 			txt = SpecialChars::TAB;
674 		else if (spn.nodeName() == "text:line-break")
675 			txt = SpecialChars::LINEBREAK;
676 		if (!txt.isEmpty())
677 		{
678 			txt.replace(QChar(0xAD), SpecialChars::SHYPHEN);
679 			txt.replace(QChar(0x2011), SpecialChars::NBHYPHEN);
680 			txt.replace(QChar(0xA0), SpecialChars::NBSPACE);
681 			insertChars(item, txt, tmpStyle, cStyle, posC);
682 		}
683 	}
684 
685 	if (textStyleName.length() > 0)
686 		m_textStylesStack.pop();
687 }
688 
parseTextParagraph(QDomNode & elem,PageItem * item,ParagraphStyle & newStyle,ObjStyleODT & tmpOStyle,int & posC)689 void ODTIm::parseTextParagraph(QDomNode &elem, PageItem* item, ParagraphStyle &newStyle, ObjStyleODT &tmpOStyle, int &posC)
690 {
691 	ParagraphStyle tmpStyle = newStyle;
692 	CharStyle tmpCStyle = tmpStyle.charStyle();
693 	ObjStyleODT pStyle = tmpOStyle;
694 	QString parStyleName = "";
695 
696 	QString pStyleName = elem.toElement().attribute("text:style-name");
697 	if (pStyleName.length() > 0)
698 	{
699 		resolveStyle(pStyle, pStyleName);
700 		if (m_Styles.contains(pStyleName))
701 		{
702 			DrawStyle currStyle = m_Styles[pStyleName];
703 			if (currStyle.styleOrigin.value == "styles")
704 			{
705 				if (m_prefixName)
706 				{
707 					parStyleName = m_item->itemName() + "_" + pStyleName;
708 					if (currStyle.displayName.valid)
709 						parStyleName = m_item->itemName() + "_" + currStyle.displayName.value;
710 				}
711 				else
712 				{
713 					parStyleName = pStyleName;
714 					if (currStyle.displayName.valid)
715 						parStyleName = currStyle.displayName.value;
716 				}
717 			}
718 		}
719 		m_textStylesStack.push(pStyleName);
720 	}
721 	if ((pStyle.breakBefore == "column") && (item->itemText.length() > 0))
722 	{
723 		QString txt = SpecialChars::COLBREAK;
724 		insertChars(item, txt, tmpStyle, tmpCStyle, posC);
725 	}
726 	else if ((pStyle.breakBefore == "page") && (item->itemText.length() > 0))
727 	{
728 		QString txt = SpecialChars::FRAMEBREAK;
729 		insertChars(item, txt, tmpStyle, tmpCStyle, posC);
730 	}
731 	applyParagraphStyle(tmpStyle, pStyle);
732 	if (elem.hasChildNodes())
733 	{
734 		for (QDomNode spn = elem.firstChild(); !spn.isNull(); spn = spn.nextSibling())
735 		{
736 			if (!parStyleName.isEmpty())
737 			{
738 				tmpStyle.setParent(parStyleName);
739 				applyParagraphStyle(tmpStyle, pStyle);
740 				tmpCStyle = tmpStyle.charStyle();
741 				applyCharacterStyle(tmpCStyle, pStyle);
742 			}
743 			else
744 			{
745 				tmpStyle = newStyle;
746 				applyParagraphStyle(tmpStyle, pStyle);
747 				tmpCStyle = tmpStyle.charStyle();
748 				applyCharacterStyle(tmpCStyle, pStyle);
749 			}
750 			QString txt = "";
751 			ObjStyleODT cStyle = pStyle;
752 			QDomElement spEl = spn.toElement();
753 			if (spn.nodeName() == "#text")
754 				txt = spn.nodeValue();
755 			else if (spn.nodeName() == "text:span")
756 				parseTextSpan(spEl, item, tmpStyle, tmpCStyle, cStyle, posC);
757 			else if (spn.nodeName() == "text:s")
758 			{
759 				if (spEl.hasAttribute("text:c"))
760 				{
761 					int n = spEl.attribute("text:c").toInt();
762 					for (int nn = 0; nn < n; nn++)
763 					{
764 						txt += " ";
765 					}
766 				}
767 				else
768 					txt = " ";
769 			}
770 			else if (spn.nodeName() == "text:tab")
771 				txt = SpecialChars::TAB;
772 			else if (spn.nodeName() == "text:line-break")
773 				txt = SpecialChars::LINEBREAK;
774 			if (!txt.isEmpty())
775 			{
776 				txt.replace(QChar(0xAD), SpecialChars::SHYPHEN);
777 				txt.replace(QChar(0x2011), SpecialChars::NBHYPHEN);
778 				txt.replace(QChar(0xA0), SpecialChars::NBSPACE);
779 				insertChars(item, txt, tmpStyle, tmpCStyle, posC);
780 			}
781 		}
782 	}
783 /*	if (pStyle.lineHeight < 0.0)
784 		tmpStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
785 	else
786 	{
787 		tmpStyle.setLineSpacingMode(ParagraphStyle::FixedLineSpacing);
788 		if (pStyle.absLineHeight)
789 			tmpStyle.setLineSpacing(tmpOStyle.lineHeight);
790 		else
791 			tmpStyle.setLineSpacing(tmpOStyle.lineHeight * tmpOStyle.fontSize);
792 	} */
793 	if (pStyle.breakAfter == "column")
794 	{
795 		QString txt = SpecialChars::COLBREAK;
796 		insertChars(item, txt, tmpStyle, tmpCStyle, posC);
797 	}
798 	else if (pStyle.breakAfter == "page")
799 	{
800 		QString txt = SpecialChars::FRAMEBREAK;
801 		insertChars(item, txt, tmpStyle, tmpCStyle, posC);
802 	}
803 	item->itemText.insertChars(posC, SpecialChars::PARSEP);
804 	item->itemText.applyStyle(posC, tmpStyle);
805 	posC = item->itemText.length();
806 
807 	if (pStyleName.length() > 0)
808 		m_textStylesStack.pop();
809 }
810 
parseText(QDomElement & elem,PageItem * item,ObjStyleODT & tmpOStyle)811 void ODTIm::parseText(QDomElement &elem, PageItem* item, ObjStyleODT &tmpOStyle)
812 {
813 	QString pStyleD = CommonStrings::DefaultParagraphStyle;
814 	ParagraphStyle newStyle;
815 	newStyle.setDefaultStyle(false);
816 	newStyle.setParent(pStyleD);
817 	ParagraphStyle ttx = m_Doc->paragraphStyle(pStyleD);
818 	CharStyle nstyle = ttx.charStyle();
819 	newStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
820 	newStyle.setLineSpacing(nstyle.fontSize() / 10.0);
821 	if (!m_append)
822 	{
823 		item->itemText.clear();
824 		item->itemText.setDefaultStyle(newStyle);
825 		item->setFirstLineOffset(FLOPFontAscent);
826 	}
827 	int posC = item->itemText.length();
828 	for (QDomNode para = elem.firstChild(); !para.isNull(); para = para.nextSibling())
829 	{
830 		if ((para.nodeName() == "text:p") || (para.nodeName() == "text:h"))
831 			parseTextParagraph(para, item, newStyle, tmpOStyle, posC);
832 		else if (para.nodeName() == "text:list")
833 		{
834 			if (!para.hasChildNodes())
835 				continue;
836 			for (QDomNode spn = para.firstChild(); !spn.isNull(); spn = spn.nextSibling())
837 			{
838 				if (spn.nodeName() == "text:list-item")
839 				{
840 					if (!spn.hasChildNodes())
841 						continue;
842 					for (QDomNode spp = spn.firstChild(); !spp.isNull(); spp = spp.nextSibling())
843 					{
844 						if (spp.nodeName() == "text:p")
845 						{
846 							parseTextParagraph(spp, item, newStyle, tmpOStyle, posC);
847 						}
848 					}
849 				}
850 			}
851 		}
852 		else if (para.nodeName() == "text:section")
853 		{
854 			if (!para.hasChildNodes())
855 				continue;
856 			for (QDomNode spn = para.firstChild(); !spn.isNull(); spn = spn.nextSibling())
857 			{
858 				if (spn.nodeName() == "text:p")
859 				{
860 					parseTextParagraph(spn, item, newStyle, tmpOStyle, posC);
861 				}
862 			}
863 		}
864 	}
865 }
866 
insertChars(PageItem * item,QString & txt,ParagraphStyle & tmpStyle,CharStyle & tmpCStyle,int & posC)867 void ODTIm::insertChars(PageItem *item, QString &txt, ParagraphStyle &tmpStyle, CharStyle &tmpCStyle, int &posC)
868 {
869 	if (txt.length() > 0)
870 	{
871 		item->itemText.insertChars(posC, txt);
872 		item->itemText.applyStyle(posC, tmpStyle);
873 		item->itemText.applyCharStyle(posC, txt.length(), tmpCStyle);
874 		posC = item->itemText.length();
875 		txt = "";
876 	}
877 }
878 
applyCharacterStyle(CharStyle & tmpCStyle,ObjStyleODT & oStyle)879 void ODTIm::applyCharacterStyle(CharStyle &tmpCStyle, ObjStyleODT &oStyle)
880 {
881 	tmpCStyle.setFont((*m_Doc->AllFonts)[oStyle.fontName]);
882 	tmpCStyle.setFontSize(oStyle.fontSize * 10);
883 	tmpCStyle.setFillColor(oStyle.CurrColorText);
884 	tmpCStyle.setBackColor(oStyle.CurrColorBText);
885 	StyleFlag styleEffects = tmpCStyle.effects();
886 	if ((oStyle.textPos.startsWith("super")) || (oStyle.textPos.startsWith("sub")))
887 	{
888 		if (oStyle.textPos.startsWith("super"))
889 			styleEffects |= ScStyle_Superscript;
890 		else
891 			styleEffects |= ScStyle_Subscript;
892 	}
893 	if (oStyle.textOutline == "true")
894 	{
895 		styleEffects |= ScStyle_Outline;
896 		tmpCStyle.setOutlineWidth(30);
897 		tmpCStyle.setFillColor("White");
898 		tmpCStyle.setStrokeColor(oStyle.CurrColorText);
899 	}
900 	if (oStyle.textUnderline)
901 	{
902 		styleEffects |= ScStyle_Underline;
903 		tmpCStyle.setUnderlineOffset(-1);
904 		tmpCStyle.setUnderlineWidth(-1);
905 		tmpCStyle.setStrokeColor(oStyle.textUnderlineColor);
906 	}
907 	if (oStyle.textStrikeThrough)
908 	{
909 		if (oStyle.textUnderlineWords)
910 			styleEffects |= ScStyle_UnderlineWords;
911 		else
912 			styleEffects |= ScStyle_Strikethrough;
913 		tmpCStyle.setStrikethruOffset(-1);
914 		tmpCStyle.setStrikethruWidth(-1);
915 		tmpCStyle.setStrokeColor(oStyle.CurrColorText);
916 	}
917 	if (oStyle.textShadow)
918 	{
919 		styleEffects |= ScStyle_Shadowed;
920 		tmpCStyle.setShadowXOffset(30);
921 		tmpCStyle.setShadowYOffset(-30);
922 		tmpCStyle.setStrokeColor(oStyle.CurrColorText);
923 	}
924 	if (oStyle.textSmallCaps)
925 	{
926 		styleEffects |= ScStyle_SmallCaps;
927 	}
928 	tmpCStyle.setFeatures(styleEffects.featureList());
929 	if ((oStyle.fontStyle == "italic") && (oStyle.fontWeight == "bold"))
930 		setFontstyle(tmpCStyle, 3);
931 	else if ((oStyle.fontStyle == "oblique") && (oStyle.fontWeight == "bold"))
932 		setFontstyle(tmpCStyle, 4);
933 	else if (oStyle.fontStyle == "italic")
934 		setFontstyle(tmpCStyle, 0);
935 	else if (oStyle.fontStyle == "oblique")
936 		setFontstyle(tmpCStyle, 1);
937 	else if (oStyle.fontWeight == "bold")
938 		setFontstyle(tmpCStyle, 2);
939 }
940 
applyParagraphStyle(ParagraphStyle & tmpStyle,ObjStyleODT & oStyle)941 void ODTIm::applyParagraphStyle(ParagraphStyle &tmpStyle, ObjStyleODT &oStyle)
942 {
943 	tmpStyle.setAlignment(oStyle.textAlign);
944 	tmpStyle.setLeftMargin(oStyle.margin_left);
945 	tmpStyle.setRightMargin(oStyle.margin_right);
946 	tmpStyle.setFirstIndent(oStyle.textIndent);
947 	tmpStyle.setGapAfter(oStyle.margin_bottom);
948 	tmpStyle.setGapBefore(oStyle.margin_top);
949 	tmpStyle.setBackgroundColor(oStyle.CurrColorBPara);
950 	tmpStyle.setTabValues(oStyle.tabStops);
951 }
952 
resolveStyle(ObjStyleODT & tmpOStyle,const QString & pAttrs)953 void ODTIm::resolveStyle(ObjStyleODT &tmpOStyle, const QString& pAttrs)
954 {
955 	if (m_Styles.contains(pAttrs))
956 	{
957 		DrawStyle actStyle;
958 		DrawStyle currStyle = m_Styles[pAttrs];
959 		QStringList parents;
960 		while (currStyle.parentStyle.valid)
961 		{
962 			if (m_Styles.contains(currStyle.parentStyle.value))
963 			{
964 				parents.prepend(currStyle.parentStyle.value);
965 				currStyle = m_Styles[currStyle.parentStyle.value];
966 			}
967 			else
968 				break;
969 		}
970 		parents.append(pAttrs);
971 		if (!parents.isEmpty())
972 		{
973 			for (int p = 0; p < parents.count(); p++)
974 			{
975 				currStyle = m_Styles[parents[p]];
976 				if (currStyle.fontName.valid)
977 					actStyle.fontName = AttributeValue(currStyle.fontName.value);
978 				if (currStyle.fontSize.valid)
979 				{
980 					if (currStyle.fontSize.value.right(1) == "%")
981 					{
982 						double perc = parseUnit(currStyle.fontSize.value);
983 						if (actStyle.fontSize.valid)
984 						{
985 							double value = parseUnit(actStyle.fontSize.value) * perc;
986 							actStyle.fontSize = AttributeValue(QString("%1pt").arg(value));
987 						}
988 					}
989 					else
990 						actStyle.fontSize = AttributeValue(currStyle.fontSize.value);
991 				}
992 				if (currStyle.fontStyle.valid)
993 					actStyle.fontStyle = AttributeValue(currStyle.fontStyle.value);
994 				if (currStyle.fontWeight.valid)
995 					actStyle.fontWeight = AttributeValue(currStyle.fontWeight.value);
996 				if (currStyle.margin_top.valid)
997 					actStyle.margin_top = AttributeValue(currStyle.margin_top.value);
998 				if (currStyle.margin_bottom.valid)
999 					actStyle.margin_bottom = AttributeValue(currStyle.margin_bottom.value);
1000 				if (currStyle.margin_left.valid)
1001 					actStyle.margin_left = AttributeValue(currStyle.margin_left.value);
1002 				if (currStyle.margin_right.valid)
1003 					actStyle.margin_right = AttributeValue(currStyle.margin_right.value);
1004 				if (currStyle.textIndent.valid)
1005 					actStyle.textIndent = AttributeValue(currStyle.textIndent.value);
1006 				if (currStyle.textAlign.valid)
1007 					actStyle.textAlign = AttributeValue(currStyle.textAlign.value);
1008 				if (currStyle.textPos.valid)
1009 					actStyle.textPos = AttributeValue(currStyle.textPos.value);
1010 				if (currStyle.textOutline.valid)
1011 					actStyle.textOutline = AttributeValue(currStyle.textOutline.value);
1012 				if (currStyle.textUnderline.valid)
1013 					actStyle.textUnderline = AttributeValue(currStyle.textUnderline.value);
1014 				if (currStyle.textUnderlineWords.valid)
1015 					actStyle.textUnderlineWords = AttributeValue(currStyle.textUnderlineWords.value);
1016 				if (currStyle.textUnderlineColor.valid)
1017 					actStyle.textUnderlineColor = AttributeValue(currStyle.textUnderlineColor.value);
1018 				if (currStyle.textStrikeThrough.valid)
1019 					actStyle.textStrikeThrough = AttributeValue(currStyle.textStrikeThrough.value);
1020 				if (currStyle.textShadow.valid)
1021 					actStyle.textShadow = AttributeValue(currStyle.textShadow.value);
1022 				if (currStyle.fontVariant.valid)
1023 					actStyle.fontVariant = AttributeValue(currStyle.fontVariant.value);
1024 				if (currStyle.lineHeight.valid)
1025 					actStyle.lineHeight = AttributeValue(currStyle.lineHeight.value);
1026 				if (currStyle.fontColor.valid)
1027 					actStyle.fontColor = AttributeValue(currStyle.fontColor.value);
1028 				if (currStyle.textBackgroundColor.valid)
1029 					actStyle.textBackgroundColor = AttributeValue(currStyle.textBackgroundColor.value);
1030 				if (currStyle.parBackgroundColor.valid)
1031 					actStyle.parBackgroundColor = AttributeValue(currStyle.parBackgroundColor.value);
1032 				if (currStyle.verticalAlignment.valid)
1033 					actStyle.verticalAlignment = AttributeValue(currStyle.verticalAlignment.value);
1034 				if (currStyle.tabDists.valid)
1035 					actStyle.tabDists = AttributeValue(currStyle.tabDists.value);
1036 				if (currStyle.tabTypes.valid)
1037 					actStyle.tabTypes = AttributeValue(currStyle.tabTypes.value);
1038 				if (currStyle.breakAfter.valid)
1039 					actStyle.breakAfter = AttributeValue(currStyle.breakAfter.value);
1040 				if (currStyle.breakBefore.valid)
1041 					actStyle.breakBefore = AttributeValue(currStyle.breakBefore.value);
1042 			}
1043 		}
1044 		if (actStyle.textBackgroundColor.valid)
1045 		{
1046 			if (actStyle.textBackgroundColor.value == "transparent")
1047 				tmpOStyle.CurrColorBText = CommonStrings::None;
1048 			else
1049 				tmpOStyle.CurrColorBText = parseColor(actStyle.textBackgroundColor.value);
1050 		}
1051 		else
1052 			tmpOStyle.CurrColorBText = CommonStrings::None;
1053 		if (actStyle.parBackgroundColor.valid)
1054 		{
1055 			if (actStyle.parBackgroundColor.value == "transparent")
1056 				tmpOStyle.CurrColorBPara = CommonStrings::None;
1057 			else
1058 				tmpOStyle.CurrColorBPara = parseColor(actStyle.parBackgroundColor.value);
1059 		}
1060 		else
1061 			tmpOStyle.CurrColorBPara = CommonStrings::None;
1062 		if (actStyle.fontName.valid)
1063 		{
1064 			if (m_fontMap.contains(actStyle.fontName.value))
1065 				tmpOStyle.fontName = m_fontMap[actStyle.fontName.value];
1066 			else
1067 				tmpOStyle.fontName = actStyle.fontName.value;
1068 			if (!PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.contains(tmpOStyle.fontName))
1069 			{
1070 				tmpOStyle.fontName = constructFontName(tmpOStyle.fontName, "");
1071 				m_fontMap[actStyle.fontName.value] = tmpOStyle.fontName;
1072 			}
1073 		}
1074 		else
1075 		{
1076 			QString fontName;
1077 			QStack<QString> textStyleStack = m_textStylesStack;
1078 			while (!textStyleStack.isEmpty())
1079 			{
1080 				QString styleName = textStyleStack.pop();
1081 				if (!m_Styles.contains(styleName))
1082 					continue;
1083 				const DrawStyle& odtStyle = m_Styles[styleName];
1084 				if (odtStyle.fontName.valid)
1085 				{
1086 					if (m_fontMap.contains(odtStyle.fontName.value))
1087 						tmpOStyle.fontName = m_fontMap[odtStyle.fontName.value];
1088 					else
1089 						tmpOStyle.fontName = constructFontName(odtStyle.fontName.value, "");
1090 					if (!PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.contains(tmpOStyle.fontName))
1091 					{
1092 						tmpOStyle.fontName = constructFontName(tmpOStyle.fontName, "");
1093 						m_fontMap[odtStyle.fontName.value] = tmpOStyle.fontName;
1094 					}
1095 					fontName = tmpOStyle.fontName;
1096 					break;
1097 				}
1098 				if (odtStyle.parentStyle.valid)
1099 				{
1100 					QVector<QString> parentStyles;
1101 					DrawStyle drawStyle = odtStyle;
1102 					while (drawStyle.parentStyle.valid)
1103 					{
1104 						if (!m_Styles.contains(drawStyle.parentStyle.value))
1105 							break;
1106 						parentStyles.prepend(drawStyle.parentStyle.value);
1107 						drawStyle = m_Styles[drawStyle.parentStyle.value];
1108 					}
1109 					if (parentStyles.count() > 0)
1110 						textStyleStack += parentStyles;
1111 				}
1112 			}
1113 			if (txtDefaultStyle.fontName.valid && fontName.isEmpty())
1114 			{
1115 				tmpOStyle.fontName = constructFontName(txtDefaultStyle.fontName.value, "");
1116 				m_fontMap[txtDefaultStyle.fontName.value] = tmpOStyle.fontName;
1117 				fontName = tmpOStyle.fontName;
1118 			}
1119 			if (parDefaultStyle.fontName.valid && fontName.isEmpty())
1120 			{
1121 				tmpOStyle.fontName = constructFontName(parDefaultStyle.fontName.value, "");
1122 				m_fontMap[parDefaultStyle.fontName.value] = tmpOStyle.fontName;
1123 				fontName = tmpOStyle.fontName;
1124 			}
1125 		}
1126 		if (actStyle.fontStyle.valid)
1127 			tmpOStyle.fontStyle = actStyle.fontStyle.value;
1128 		if (actStyle.fontWeight.valid)
1129 			tmpOStyle.fontWeight = actStyle.fontWeight.value;
1130 		if (actStyle.fontSize.valid)
1131 			tmpOStyle.fontSize = parseUnit(actStyle.fontSize.value);
1132 		if (actStyle.fontColor.valid)
1133 			tmpOStyle.CurrColorText = parseColor(actStyle.fontColor.value);
1134 		if (actStyle.margin_top.valid)
1135 			tmpOStyle.margin_top = parseUnit(actStyle.margin_top.value);
1136 		if (actStyle.margin_bottom.valid)
1137 			tmpOStyle.margin_bottom = parseUnit(actStyle.margin_bottom.value);
1138 		if (actStyle.margin_left.valid)
1139 			tmpOStyle.margin_left = parseUnit(actStyle.margin_left.value);
1140 		if (actStyle.margin_right.valid)
1141 			tmpOStyle.margin_right = parseUnit(actStyle.margin_right.value);
1142 		if (actStyle.textIndent.valid)
1143 			tmpOStyle.textIndent = parseUnit(actStyle.textIndent.value);
1144 		if (actStyle.textAlign.valid)
1145 		{
1146 			QString attValue = actStyle.textAlign.value;
1147 			if ((attValue == "left") || (attValue == "start"))
1148 				tmpOStyle.textAlign = ParagraphStyle::LeftAligned;
1149 			else if (attValue == "center")
1150 				tmpOStyle.textAlign = ParagraphStyle::Centered;
1151 			else if ((attValue == "right") || (attValue == "end"))
1152 				tmpOStyle.textAlign = ParagraphStyle::RightAligned;
1153 			else if (attValue == "justify")
1154 				tmpOStyle.textAlign = ParagraphStyle::Justified;
1155 		}
1156 		if (actStyle.verticalAlignment.valid)
1157 		{
1158 			if (actStyle.verticalAlignment.value == "middle")
1159 				tmpOStyle.verticalAlignment = 1;
1160 			else if (actStyle.verticalAlignment.value == "bottom")
1161 				tmpOStyle.verticalAlignment = 2;
1162 		}
1163 		if (actStyle.textPos.valid)
1164 			tmpOStyle.textPos = actStyle.textPos.value;
1165 		if (actStyle.textOutline.valid)
1166 			tmpOStyle.textOutline = actStyle.textOutline.value;
1167 		if (actStyle.textUnderline.valid)
1168 			tmpOStyle.textUnderline = actStyle.textUnderline.value != "none";
1169 		if (actStyle.textUnderlineWords.valid)
1170 			tmpOStyle.textUnderlineWords = actStyle.textUnderlineWords.value != "continuous";
1171 		if (actStyle.textUnderlineColor.valid)
1172 		{
1173 			if (actStyle.textUnderlineColor.value == "font-color")
1174 				tmpOStyle.textUnderlineColor = tmpOStyle.CurrColorText;
1175 			else
1176 				tmpOStyle.textUnderlineColor = parseColor(actStyle.textUnderlineColor.value);
1177 		}
1178 		if (actStyle.textStrikeThrough.valid)
1179 			tmpOStyle.textStrikeThrough = actStyle.textStrikeThrough.value != "none";
1180 		if (actStyle.textShadow.valid)
1181 			tmpOStyle.textShadow = actStyle.textShadow.value != "none";
1182 		if (actStyle.fontVariant.valid)
1183 			tmpOStyle.textSmallCaps = actStyle.fontVariant.value == "small-caps";
1184 		if (actStyle.lineHeight.valid)
1185 		{
1186 			if (actStyle.lineHeight.value == "normal")
1187 				tmpOStyle.lineHeight = -1.0;
1188 			else if (actStyle.lineHeight.value.right(1) != "%")
1189 			{
1190 				tmpOStyle.lineHeight = parseUnit(actStyle.lineHeight.value);
1191 				tmpOStyle.absLineHeight = true;
1192 			}
1193 			else
1194 			{
1195 				tmpOStyle.lineHeight = parseUnit(actStyle.lineHeight.value) * tmpOStyle.fontSize;
1196 				tmpOStyle.absLineHeight = false;
1197 			}
1198 		}
1199 		if ((actStyle.tabDists.valid) && (actStyle.tabTypes.valid))
1200 		{
1201 			QStringList dists = actStyle.tabDists.value.split(";", Qt::SkipEmptyParts);
1202 			QStringList types = actStyle.tabTypes.value.split(" ", Qt::SkipEmptyParts);
1203 			if (dists.count() == types.count())
1204 			{
1205 				tmpOStyle.tabStops.clear();
1206 				ParagraphStyle::TabRecord tb;
1207 				for (int a = 0; a < dists.count(); a++)
1208 				{
1209 					tb.tabPosition = parseUnit(dists[a]);
1210 					if (types[a] == "left")
1211 						tb.tabType = 0;
1212 					else if (types[a] == "center")
1213 						tb.tabType = 4;
1214 					else if (types[a] == "right")
1215 						tb.tabType = 1;
1216 					else if (types[a] == "char")
1217 						tb.tabType = 3;
1218 					tmpOStyle.tabStops.append(tb);
1219 				}
1220 			}
1221 		}
1222 		if (actStyle.breakAfter.valid)
1223 			tmpOStyle.breakAfter = actStyle.breakAfter.value;
1224 		if (actStyle.breakBefore.valid)
1225 			tmpOStyle.breakBefore = actStyle.breakBefore.value;
1226 	}
1227 }
1228 
parseUnit(const QString & unit)1229 double ODTIm::parseUnit(const QString &unit)
1230 {
1231 	QString unitval=unit;
1232 	if (unit.isEmpty())
1233 		return 0.0;
1234 	if (unit.right( 2 ) == "pt")
1235 		unitval.replace( "pt", "" );
1236 	else if (unit.right( 2 ) == "cm")
1237 		unitval.replace( "cm", "" );
1238 	else if (unit.right( 2 ) == "mm")
1239 		unitval.replace( "mm" , "" );
1240 	else if (unit.right( 2 ) == "in")
1241 		unitval.replace( "in", "" );
1242 	else if (unit.right( 2 ) == "px")
1243 		unitval.replace( "px", "" );
1244 	else if (unit.right( 1 ) == "%" )
1245 		unitval.replace( "%", "" );
1246 	double value = ScCLocale::toDoubleC(unitval);
1247 	if (unit.right( 2 ) == "pt" )
1248 		{}/* value = value; */ //no change
1249 	else if (unit.right( 2 ) == "cm")
1250 		value = ( value / 2.54 ) * 72;
1251 	else if (unit.right( 2 ) == "mm")
1252 		value = ( value / 25.4 ) * 72;
1253 	else if (unit.right( 2 ) == "in")
1254 		value = value * 72;
1255 	else if (unit.right( 2 ) == "px")
1256 		{}/* value = value; */ //no change
1257 	else if (unit.right( 1 ) == "%")
1258 		value = value / 100.0;
1259 	return value;
1260 }
1261 
parseColor(const QString & s)1262 QString ODTIm::parseColor( const QString &s )
1263 {
1264 	QColor c;
1265 	QString ret = CommonStrings::None;
1266 	if ((s == "") || s.isEmpty())
1267 		return ret;
1268 	if (s.startsWith( "rgb(" ))
1269 	{
1270 		QString parse = s.trimmed();
1271 		QStringList colors = parse.split( ',', Qt::SkipEmptyParts );
1272 		QString r = colors[0].right( ( colors[0].length() - 4 ) );
1273 		QString g = colors[1];
1274 		QString b = colors[2].left( ( colors[2].length() - 1 ) );
1275 		if (r.contains( "%" ))
1276 		{
1277 			r.chop(1);
1278 			r = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(r) ) / 100.0 ) ) );
1279 		}
1280 		if (g.contains( "%" ))
1281 		{
1282 			g.chop(1);
1283 			g = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(g) ) / 100.0 ) ) );
1284 		}
1285 		if (b.contains( "%" ))
1286 		{
1287 			b.chop(1);
1288 			b = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(b) ) / 100.0 ) ) );
1289 		}
1290 		c = QColor(r.toInt(), g.toInt(), b.toInt());
1291 	}
1292 	else
1293 		c.setNamedColor( s.trimmed() );
1294 	ScColor tmp;
1295 	tmp.fromQColor(c);
1296 	tmp.setSpotColor(false);
1297 	tmp.setRegistrationColor(false);
1298 	QString fNam = m_Doc->PageColors.tryAddColor("FromOdt"+c.name(), tmp);
1299 	ret = fNam;
1300 	return ret;
1301 }
1302 
constructFontName(const QString & fontBaseName,const QString & fontStyle)1303 QString ODTIm::constructFontName(const QString& fontBaseName, const QString& fontStyle)
1304 {
1305 	QString fontName;
1306 	SCFontsIterator it(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts);
1307 	for ( ; it.hasNext(); it.next())
1308 	{
1309 		if (fontBaseName.toLower() != it.current().family().toLower())
1310 			continue;
1311 
1312 		// found the font family, now go for the style
1313 		QStringList slist = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.fontMap[it.current().family()];
1314 		slist.sort();
1315 		if (slist.count() > 0)
1316 		{
1317 			for (int a = 0; a < slist.count(); a++)
1318 			{
1319 				if (fontStyle.toLower() == slist[a].toLower())
1320 				{
1321 					fontName = it.current().family() + " " + slist[a];
1322 					return fontName;
1323 				}
1324 			}
1325 			int reInd = slist.indexOf("Regular");
1326 			if (reInd < 0)
1327 				fontName = it.current().family() + " " + slist[0];
1328 			else
1329 				fontName = it.current().family() + " " + slist[reInd];
1330 			return fontName;
1331 		}
1332 		fontName = it.current().family();
1333 		return fontName;
1334 	}
1335 
1336 	// Still no font found
1337 	QString family = fontBaseName;
1338 	if (!fontStyle.isEmpty())
1339 		family += " " + fontStyle;
1340 	if (PrefsManager::instance().appPrefs.fontPrefs.GFontSub.contains(family))
1341 	{
1342 		fontName = PrefsManager::instance().appPrefs.fontPrefs.GFontSub[family];
1343 		return fontName;
1344 	}
1345 
1346 	qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
1347 	QScopedPointer<MissingFont> dia(new MissingFont(nullptr, family, m_Doc));
1348 	if (dia->exec())
1349 		fontName = dia->getReplacementFont();
1350 	else
1351 		fontName = m_Doc->itemToolPrefs().textFont;
1352 	PrefsManager::instance().appPrefs.fontPrefs.GFontSub[family] = fontName;
1353 	qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
1354 
1355 	return fontName;
1356 }
1357 
setFontstyle(CharStyle & tmpCStyle,int kind)1358 void ODTIm::setFontstyle(CharStyle &tmpCStyle, int kind)
1359 {
1360 	int posC = m_item->itemText.length();
1361 	m_item->itemText.insertChars(posC, "B");
1362 	m_item->itemText.applyCharStyle(posC, 1, tmpCStyle);
1363 	QString fam = m_item->itemText.charStyle(posC).font().family();
1364 	m_item->itemText.removeChars(posC, 1);
1365 	if (fam.isEmpty())
1366 		return;
1367 	QStringList slist = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.fontMap[fam];
1368 	if (kind == 0)
1369 	{
1370 		if (slist.contains("Italic"))
1371 			tmpCStyle.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[fam + " Italic"]);
1372 	}
1373 	else if (kind == 1)
1374 	{
1375 		if (slist.contains("Oblique"))
1376 			tmpCStyle.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[fam + " Oblique"]);
1377 	}
1378 	else if (kind == 2)
1379 	{
1380 		if (slist.contains("Bold"))
1381 			tmpCStyle.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[fam + " Bold"]);
1382 	}
1383 	else if (kind == 3)
1384 	{
1385 		if (slist.contains("Bold Italic"))
1386 			tmpCStyle.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[fam + " Bold Italic"]);
1387 	}
1388 	else if (kind == 4)
1389 	{
1390 		if (slist.contains("Bold Oblique"))
1391 			tmpCStyle.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[fam + " Bold Oblique"]);
1392 	}
1393 }
1394