1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* libodfgen
3  * Version: MPL 2.0 / LGPLv2.1+
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * Major Contributor(s):
10  * Copyright (C) 2002-2004 William Lachance (wrlach@gmail.com)
11  * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
12  *
13  * For minor contributions see the git repository.
14  *
15  * Alternatively, the contents of this file may be used under the terms
16  * of the GNU Lesser General Public License Version 2.1 or later
17  * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
18  * applicable instead of those above.
19  *
20  * For further information visit http://libwpd.sourceforge.net
21  */
22 
23 /* "This product is not manufactured, approved, or supported by
24  * Corel Corporation or Corel Corporation Limited."
25  */
26 
27 #include "OdcGenerator.hxx"
28 
29 #include <librevenge/librevenge.h>
30 
31 #include <map>
32 #include <stack>
33 #include <string>
34 
35 #include <libodfgen/libodfgen.hxx>
36 
37 #include "FilterInternal.hxx"
38 #include "InternalHandler.hxx"
39 
40 #include "DocumentElement.hxx"
41 #include "FontStyle.hxx"
42 #include "ListStyle.hxx"
43 #include "SheetStyle.hxx"
44 #include "TableStyle.hxx"
45 #include "TextRunStyle.hxx"
46 
47 #include "OdfGenerator.hxx"
48 
49 // the state we use for writing the final document
50 struct ChartDocumentState
51 {
52 	ChartDocumentState();
53 
54 	bool mbChartOpened;
55 	bool mbChartPlotAreaOpened;
56 	bool mbChartSerieOpened;
57 	bool mbChartTextObjectOpened;
58 	bool mbTableCellOpened;
59 
60 	std::string mCharTextObjectType;
61 };
62 
ChartDocumentState()63 ChartDocumentState::ChartDocumentState() :
64 	mbChartOpened(false), mbChartPlotAreaOpened(false), mbChartSerieOpened(false), mbChartTextObjectOpened(false),
65 	mbTableCellOpened(false),
66 	mCharTextObjectType("")
67 {
68 }
69 
70 class OdcGeneratorPrivate : public OdfGenerator
71 {
72 public:
73 	OdcGeneratorPrivate();
74 	~OdcGeneratorPrivate() override;
75 
76 	bool writeTargetDocument(OdfDocumentHandler *pHandler, OdfStreamType streamType) override;
77 	void _writeStyles(OdfDocumentHandler *pHandler);
78 	void _writeAutomaticStyles(OdfDocumentHandler *pHandler, OdfStreamType streamType);
79 
canWriteText() const80 	bool canWriteText() const
81 	{
82 		return mChartDocumentStates.top().mbChartTextObjectOpened ||
83 		       mChartDocumentStates.top().mbTableCellOpened;
84 	}
85 
86 	librevenge::RVNGString getChartStyleName(int id);
87 	void writeChartStyle(librevenge::RVNGPropertyList const &style, OdfDocumentHandler *pHandler);
88 	static librevenge::RVNGString getAddressString(librevenge::RVNGPropertyListVector const *vector);
89 	std::stack<ChartDocumentState> mChartDocumentStates;
90 
91 protected:
92 	// hash key -> name
93 	std::map<librevenge::RVNGString, librevenge::RVNGString> mHashChartNameMap;
94 	// style name -> chart style
95 	std::map<librevenge::RVNGString, librevenge::RVNGPropertyList> mChartStyleHash;
96 
97 private:
98 	OdcGeneratorPrivate(const OdcGeneratorPrivate &);
99 	OdcGeneratorPrivate &operator=(const OdcGeneratorPrivate &);
100 
101 };
102 
OdcGeneratorPrivate()103 OdcGeneratorPrivate::OdcGeneratorPrivate() :
104 	mChartDocumentStates(), mHashChartNameMap(), mChartStyleHash()
105 {
106 	mChartDocumentStates.push(ChartDocumentState());
107 }
108 
~OdcGeneratorPrivate()109 OdcGeneratorPrivate::~OdcGeneratorPrivate()
110 {
111 	// clean up the mess we made
112 	ODFGEN_DEBUG_MSG(("OdcGenerator: Cleaning up our mess..\n"));
113 }
114 
getChartStyleName(int id)115 librevenge::RVNGString OdcGeneratorPrivate::getChartStyleName(int id)
116 {
117 	if (mIdChartNameMap.find(id)!=mIdChartNameMap.end())
118 		return mIdChartNameMap.find(id)->second;
119 
120 	librevenge::RVNGPropertyList pList;
121 	if (mIdChartMap.find(id)!=mIdChartMap.end())
122 		pList=mIdChartMap.find(id)->second;
123 	else
124 	{
125 		ODFGEN_DEBUG_MSG(("OdcGeneratorPrivate::getChartStyleName: can not find the style %d\n", id));
126 		pList.clear();
127 	}
128 
129 	librevenge::RVNGString hashKey = pList.getPropString();
130 	std::map<librevenge::RVNGString, librevenge::RVNGString>::const_iterator iter =
131 	    mHashChartNameMap.find(hashKey);
132 	if (iter!=mHashChartNameMap.end())
133 	{
134 		mIdChartNameMap[id]=iter->second;
135 		return iter->second;
136 	}
137 
138 	// ok create a new list
139 	librevenge::RVNGString sName("");
140 	sName.sprintf("Chart%i", (int)mChartStyleHash.size());
141 	pList.insert("style:name", sName);
142 	mChartStyleHash[sName] =pList;
143 	mHashChartNameMap[hashKey] = sName;
144 
145 	return sName;
146 }
147 
writeChartStyle(librevenge::RVNGPropertyList const & style,OdfDocumentHandler * pHandler)148 void OdcGeneratorPrivate::writeChartStyle(librevenge::RVNGPropertyList const &style, OdfDocumentHandler *pHandler)
149 {
150 	if (!style["style:name"])
151 	{
152 		ODFGEN_DEBUG_MSG(("OdcGeneratorPrivate::writeChartStyle: can not find the style name\n"));
153 		return;
154 	}
155 
156 	librevenge::RVNGPropertyList styleOpenList;
157 	styleOpenList.insert("style:name", style["style:name"]->clone());
158 	if (style["style:display-name"])
159 		styleOpenList.insert("style:display-name", style["style:display-name"]->clone());
160 	styleOpenList.insert("style:family", "chart");
161 	pHandler->startElement("style:style", styleOpenList);
162 
163 	librevenge::RVNGPropertyList chartProp;
164 	librevenge::RVNGPropertyList::Iter i(style);
165 	for (i.rewind(); i.next();)
166 	{
167 		if (i.child()) continue;
168 		if (!strncmp(i.key(), "chart:", 6) || !strcmp(i.key(), "style:direction") ||
169 		        !strcmp(i.key(), "style:rotation-angle")  || !strcmp(i.key(), "text:line-break"))
170 			chartProp.insert(i.key(),i()->clone());
171 	}
172 	if (!chartProp.empty())
173 	{
174 		pHandler->startElement("style:chart-properties", chartProp);
175 		pHandler->endElement("style:chart-properties");
176 	}
177 	librevenge::RVNGPropertyList textProp;
178 	SpanStyleManager::addSpanProperties(style, textProp);
179 	if (!textProp.empty())
180 	{
181 		if (textProp["style:font-name"])
182 			mFontManager.findOrAdd(textProp["style:font-name"]->getStr().cstr());
183 		pHandler->startElement("style:text-properties", textProp);
184 		pHandler->endElement("style:text-properties");
185 	}
186 	librevenge::RVNGPropertyList graphProp;
187 	mGraphicManager.addGraphicProperties(style,graphProp);
188 	GraphicStyleManager::addFrameProperties(style,graphProp);
189 	if (!style["fo:min-width"] && graphProp["fo:min-width"])
190 		graphProp.remove("fo:min-width");
191 	if (!graphProp.empty())
192 	{
193 		pHandler->startElement("style:graphic-properties", graphProp);
194 		pHandler->endElement("style:graphic-properties");
195 	}
196 	pHandler->endElement("style:style");
197 
198 }
199 
getAddressString(librevenge::RVNGPropertyListVector const * vector)200 librevenge::RVNGString OdcGeneratorPrivate::getAddressString(librevenge::RVNGPropertyListVector const *vector)
201 {
202 	librevenge::RVNGString res("");
203 	if (!vector)
204 	{
205 		ODFGEN_DEBUG_MSG(("OdcGenerator::getAddressString: can not find the address propertyList..\n"));
206 		return res;
207 	}
208 	librevenge::RVNGPropertyListVector::Iter i(*vector);
209 	for (i.rewind(); i.next();)
210 	{
211 		librevenge::RVNGString cells;
212 		if (i()["librevenge:row"])
213 			cells=SheetManager::convertCellRange(i());
214 		else
215 			cells=SheetManager::convertCellsRange(i());
216 		if (!cells.empty())
217 		{
218 			if (!res.empty())
219 				res.append(' ');
220 			res.append(cells);
221 		}
222 	}
223 	return res;
224 }
225 
_writeAutomaticStyles(OdfDocumentHandler * pHandler,OdfStreamType streamType)226 void OdcGeneratorPrivate::_writeAutomaticStyles(OdfDocumentHandler *pHandler, OdfStreamType streamType)
227 {
228 	TagOpenElement("office:automatic-styles").write(pHandler);
229 
230 	if ((streamType == ODF_FLAT_XML) || (streamType == ODF_STYLES_XML))
231 	{
232 		mSpanManager.write(pHandler, Style::Z_StyleAutomatic);
233 		mParagraphManager.write(pHandler, Style::Z_StyleAutomatic);
234 		mListManager.write(pHandler, Style::Z_StyleAutomatic);
235 		mGraphicManager.write(pHandler, Style::Z_StyleAutomatic);
236 		mTableManager.write(pHandler, Style::Z_StyleAutomatic);
237 	}
238 
239 	if ((streamType == ODF_FLAT_XML) || (streamType == ODF_CONTENT_XML))
240 	{
241 		mSpanManager.write(pHandler, Style::Z_ContentAutomatic);
242 		mParagraphManager.write(pHandler, Style::Z_ContentAutomatic);
243 		mListManager.write(pHandler, Style::Z_ContentAutomatic);
244 		mGraphicManager.write(pHandler, Style::Z_ContentAutomatic);
245 		mTableManager.write(pHandler, Style::Z_ContentAutomatic);
246 
247 		std::map<librevenge::RVNGString, librevenge::RVNGPropertyList>::const_iterator iterChartStyles;
248 		for (iterChartStyles=mChartStyleHash.begin(); iterChartStyles!=mChartStyleHash.end(); ++iterChartStyles)
249 			writeChartStyle(iterChartStyles->second,pHandler);
250 	}
251 
252 	pHandler->endElement("office:automatic-styles");
253 }
254 
_writeStyles(OdfDocumentHandler * pHandler)255 void OdcGeneratorPrivate::_writeStyles(OdfDocumentHandler *pHandler)
256 {
257 	TagOpenElement("office:styles").write(pHandler);
258 
259 	// style:default-style
260 
261 	// graphic
262 	TagOpenElement defaultGraphicStyleOpenElement("style:default-style");
263 	defaultGraphicStyleOpenElement.addAttribute("style:family", "graphic");
264 	defaultGraphicStyleOpenElement.write(pHandler);
265 	pHandler->endElement("style:default-style");
266 
267 	// paragraph
268 	TagOpenElement defaultParagraphStyleOpenElement("style:default-style");
269 	defaultParagraphStyleOpenElement.addAttribute("style:family", "paragraph");
270 	defaultParagraphStyleOpenElement.write(pHandler);
271 	TagOpenElement defaultParagraphStylePropertiesOpenElement("style:paragraph-properties");
272 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:use-window-font-color", "true");
273 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:line-break", "strict");
274 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:tab-stop-distance", "0.5in");
275 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:text-autospace", "ideograph-alpha");
276 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:punctuation-wrap", "hanging");
277 	defaultParagraphStylePropertiesOpenElement.addAttribute("style:writing-mode", "page");
278 	defaultParagraphStylePropertiesOpenElement.write(pHandler);
279 	pHandler->endElement("style:paragraph-properties");
280 	pHandler->endElement("style:default-style");
281 
282 	// table
283 	TagOpenElement defaultTableStyleOpenElement("style:default-style");
284 	defaultTableStyleOpenElement.addAttribute("style:family", "table");
285 	defaultTableStyleOpenElement.write(pHandler);
286 	pHandler->endElement("style:default-style");
287 
288 	// table-row
289 	TagOpenElement defaultTableRowStyleOpenElement("style:default-style");
290 	defaultTableRowStyleOpenElement.addAttribute("style:family", "table-row");
291 	defaultTableRowStyleOpenElement.write(pHandler);
292 	TagOpenElement defaultTableRowPropertiesOpenElement("style:table-row-properties");
293 	defaultTableRowPropertiesOpenElement.addAttribute("fo:keep-together", "auto");
294 	defaultTableRowPropertiesOpenElement.write(pHandler);
295 	pHandler->endElement("style:table-row-properties");
296 	pHandler->endElement("style:default-style");
297 
298 	// table-column
299 	TagOpenElement defaultTableColumnStyleOpenElement("style:default-style");
300 	defaultTableColumnStyleOpenElement.addAttribute("style:family", "table-column");
301 	defaultTableColumnStyleOpenElement.write(pHandler);
302 	pHandler->endElement("style:default-style");
303 
304 	// table-cell
305 	TagOpenElement defaultTableCellStyleOpenElement("style:default-style");
306 	defaultTableCellStyleOpenElement.addAttribute("style:family", "table-cell");
307 	defaultTableCellStyleOpenElement.write(pHandler);
308 	pHandler->endElement("style:default-style");
309 
310 	// basic style
311 
312 	TagOpenElement standardStyleOpenElement("style:style");
313 	standardStyleOpenElement.addAttribute("style:name", "Standard");
314 	standardStyleOpenElement.addAttribute("style:family", "paragraph");
315 	standardStyleOpenElement.addAttribute("style:class", "text");
316 	standardStyleOpenElement.write(pHandler);
317 	pHandler->endElement("style:style");
318 
319 	static char const *s_paraStyle[4*4] =
320 	{
321 		"Text_Body", "Text Body", "Standard", "text",
322 		"Table_Contents", "Table Contents", "Text_Body", "extra",
323 		"Table_Heading", "Table Heading", "Table_Contents", "extra",
324 		"List", "List", "Text_Body", "list"
325 	};
326 	for (int i=0; i<4; ++i)
327 	{
328 		TagOpenElement paraOpenElement("style:style");
329 		paraOpenElement.addAttribute("style:name", s_paraStyle[4*i]);
330 		paraOpenElement.addAttribute("style:display-name", s_paraStyle[4*i+1]);
331 		paraOpenElement.addAttribute("style:family", "paragraph");
332 		paraOpenElement.addAttribute("style:parent-style-name", s_paraStyle[4*i+2]);
333 		paraOpenElement.addAttribute("style:class", s_paraStyle[4*i+3]);
334 		paraOpenElement.write(pHandler);
335 		pHandler->endElement("style:style");
336 	}
337 
338 	mSpanManager.write(pHandler, Style::Z_Style);
339 	mParagraphManager.write(pHandler, Style::Z_Style);
340 	mListManager.write(pHandler, Style::Z_Style);
341 	mFillManager.write(pHandler);
342 	mGraphicManager.write(pHandler, Style::Z_Style);
343 	pHandler->endElement("office:styles");
344 }
345 
writeTargetDocument(OdfDocumentHandler * pHandler,OdfStreamType streamType)346 bool OdcGeneratorPrivate::writeTargetDocument(OdfDocumentHandler *pHandler, OdfStreamType streamType)
347 {
348 	if (streamType == ODF_MANIFEST_XML)
349 	{
350 		pHandler->startDocument();
351 		TagOpenElement manifestElement("manifest:manifest");
352 		manifestElement.addAttribute("xmlns:manifest", "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0");
353 		manifestElement.addAttribute("manifest:version", "1.2", true);
354 		manifestElement.write(pHandler);
355 
356 		TagOpenElement mainFile("manifest:file-entry");
357 		mainFile.addAttribute("manifest:media-type", "application/vnd.oasis.opendocument.chart");
358 		mainFile.addAttribute("manifest:full-path", "/");
359 		mainFile.write(pHandler);
360 		TagCloseElement("manifest:file-entry").write(pHandler);
361 		appendFilesInManifest(pHandler);
362 
363 		TagCloseElement("manifest:manifest").write(pHandler);
364 		pHandler->endDocument();
365 		return true;
366 	}
367 
368 	ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: Printing out the header stuff..\n"));
369 
370 	ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: Start Document\n"));
371 	pHandler->startDocument();
372 
373 	ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: preamble\n"));
374 	std::string const documentType=getDocumentType(streamType);
375 	librevenge::RVNGPropertyList docContentPropList;
376 	docContentPropList.insert("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
377 	docContentPropList.insert("xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
378 	docContentPropList.insert("xmlns:dc", "http://purl.org/dc/elements/1.1/");
379 	docContentPropList.insert("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
380 	docContentPropList.insert("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
381 	docContentPropList.insert("xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0");
382 	docContentPropList.insert("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
383 	docContentPropList.insert("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
384 	docContentPropList.insert("xmlns:xlink", "http://www.w3.org/1999/xlink");
385 	docContentPropList.insert("xmlns:number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
386 	docContentPropList.insert("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
387 	docContentPropList.insert("xmlns:chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0");
388 	docContentPropList.insert("xmlns:dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0");
389 	docContentPropList.insert("xmlns:math", "http://www.w3.org/1998/Math/MathML");
390 	docContentPropList.insert("xmlns:form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0");
391 	docContentPropList.insert("xmlns:script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0");
392 	docContentPropList.insert("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
393 	docContentPropList.insert("office:version", librevenge::RVNGPropertyFactory::newStringProp("1.2"));
394 	docContentPropList.insert("xmlns:loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0");
395 	if (streamType == ODF_FLAT_XML)
396 		docContentPropList.insert("office:mimetype", "application/vnd.oasis.opendocument.chart");
397 	pHandler->startElement(documentType.c_str(), docContentPropList);
398 
399 	// write out the metadata
400 	if (streamType == ODF_FLAT_XML || streamType == ODF_META_XML)
401 		writeDocumentMetaData(pHandler);
402 
403 	// write out the font styles
404 	if (streamType == ODF_FLAT_XML || streamType == ODF_STYLES_XML || streamType == ODF_CONTENT_XML)
405 	{
406 		TagOpenElement("office:font-face-decls").write(pHandler);
407 		mFontManager.write(pHandler, Style::Z_Font);
408 		TagCloseElement("office:font-face-decls").write(pHandler);
409 	}
410 	ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: Writing out the styles..\n"));
411 
412 	// write default styles
413 	if (streamType == ODF_FLAT_XML || streamType == ODF_STYLES_XML)
414 		_writeStyles(pHandler);
415 
416 	if (streamType == ODF_FLAT_XML || streamType == ODF_STYLES_XML || streamType == ODF_CONTENT_XML)
417 		_writeAutomaticStyles(pHandler, streamType);
418 
419 	if (streamType == ODF_FLAT_XML || streamType == ODF_CONTENT_XML)
420 	{
421 		ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: Writing out the document..\n"));
422 		// writing out the document
423 		TagOpenElement("office:body").write(pHandler);
424 		TagOpenElement("office:chart").write(pHandler);
425 		sendStorage(mpBodyStorage.get(), pHandler);
426 		ODFGEN_DEBUG_MSG(("OdcGenerator: Document Body: Finished writing all doc els..\n"));
427 
428 		pHandler->endElement("office:chart");
429 		pHandler->endElement("office:body");
430 	}
431 
432 	pHandler->endElement(documentType.c_str());
433 
434 	pHandler->endDocument();
435 
436 	return true;
437 }
438 
OdcGenerator()439 OdcGenerator::OdcGenerator() : mpImpl(new OdcGeneratorPrivate)
440 {
441 }
442 
~OdcGenerator()443 OdcGenerator::~OdcGenerator()
444 {
445 }
446 
addDocumentHandler(OdfDocumentHandler * pHandler,const OdfStreamType streamType)447 void OdcGenerator::addDocumentHandler(OdfDocumentHandler *pHandler, const OdfStreamType streamType)
448 {
449 	if (mpImpl)
450 		mpImpl->addDocumentHandler(pHandler, streamType);
451 }
452 
getObjectNames() const453 librevenge::RVNGStringVector OdcGenerator::getObjectNames() const
454 {
455 	if (mpImpl)
456 		return mpImpl->getObjectNames();
457 	return librevenge::RVNGStringVector();
458 }
459 
getObjectContent(librevenge::RVNGString const & objectName,OdfDocumentHandler * pHandler)460 bool OdcGenerator::getObjectContent(librevenge::RVNGString const &objectName, OdfDocumentHandler *pHandler)
461 {
462 	if (!mpImpl)
463 		return false;
464 	return mpImpl->getObjectContent(objectName, pHandler);
465 }
466 
setDocumentMetaData(const librevenge::RVNGPropertyList & propList)467 void OdcGenerator::setDocumentMetaData(const librevenge::RVNGPropertyList &propList)
468 {
469 	mpImpl->setDocumentMetaData(propList);
470 }
471 
defineParagraphStyle(librevenge::RVNGPropertyList const & propList)472 void OdcGenerator::defineParagraphStyle(librevenge::RVNGPropertyList const &propList)
473 {
474 	mpImpl->defineParagraphStyle(propList);
475 }
476 
openParagraph(const librevenge::RVNGPropertyList & propList)477 void OdcGenerator::openParagraph(const librevenge::RVNGPropertyList &propList)
478 {
479 	if (!mpImpl->canWriteText()) return;
480 	mpImpl->openParagraph(propList);
481 }
482 
closeParagraph()483 void OdcGenerator::closeParagraph()
484 {
485 	if (!mpImpl->canWriteText()) return;
486 	mpImpl->closeParagraph();
487 }
488 
defineCharacterStyle(librevenge::RVNGPropertyList const & propList)489 void OdcGenerator::defineCharacterStyle(librevenge::RVNGPropertyList const &propList)
490 {
491 	mpImpl->defineCharacterStyle(propList);
492 }
493 
openSpan(const librevenge::RVNGPropertyList & propList)494 void OdcGenerator::openSpan(const librevenge::RVNGPropertyList &propList)
495 {
496 	if (!mpImpl->canWriteText() || mpImpl->mChartDocumentStates.top().mbChartTextObjectOpened) return;
497 	mpImpl->openSpan(propList);
498 }
499 
closeSpan()500 void OdcGenerator::closeSpan()
501 {
502 	if (!mpImpl->canWriteText() || mpImpl->mChartDocumentStates.top().mbChartTextObjectOpened) return;
503 	mpImpl->closeSpan();
504 }
505 
openLink(const librevenge::RVNGPropertyList & propList)506 void OdcGenerator::openLink(const librevenge::RVNGPropertyList &propList)
507 {
508 	if (!mpImpl->canWriteText()) return;
509 	mpImpl->openLink(propList);
510 }
511 
closeLink()512 void OdcGenerator::closeLink()
513 {
514 	if (!mpImpl->canWriteText()) return;
515 	mpImpl->closeLink();
516 }
517 
518 // -------------------------------
519 //      list
520 // -------------------------------
openOrderedListLevel(const librevenge::RVNGPropertyList & propList)521 void OdcGenerator::openOrderedListLevel(const librevenge::RVNGPropertyList &propList)
522 {
523 	if (!mpImpl->canWriteText()) return;
524 	mpImpl->openListLevel(propList, true);
525 }
526 
openUnorderedListLevel(const librevenge::RVNGPropertyList & propList)527 void OdcGenerator::openUnorderedListLevel(const librevenge::RVNGPropertyList &propList)
528 {
529 	if (!mpImpl->canWriteText()) return;
530 	mpImpl->openListLevel(propList, false);
531 }
532 
closeOrderedListLevel()533 void OdcGenerator::closeOrderedListLevel()
534 {
535 	if (!mpImpl->canWriteText()) return;
536 	mpImpl->closeListLevel();
537 }
538 
closeUnorderedListLevel()539 void OdcGenerator::closeUnorderedListLevel()
540 {
541 	if (!mpImpl->canWriteText()) return;
542 	mpImpl->closeListLevel();
543 }
544 
openListElement(const librevenge::RVNGPropertyList & propList)545 void OdcGenerator::openListElement(const librevenge::RVNGPropertyList &propList)
546 {
547 	if (!mpImpl->canWriteText()) return;
548 	mpImpl->openListElement(propList);
549 }
550 
closeListElement()551 void OdcGenerator::closeListElement()
552 {
553 	if (!mpImpl->canWriteText()) return;
554 	mpImpl->closeListElement();
555 }
556 
557 // -------------------------------
558 //      chart
559 // -------------------------------
560 
defineChartStyle(const librevenge::RVNGPropertyList & propList)561 void OdcGenerator::defineChartStyle(const librevenge::RVNGPropertyList &propList)
562 {
563 	mpImpl->defineChartStyle(propList);
564 }
565 
openChart(const librevenge::RVNGPropertyList & propList)566 void OdcGenerator::openChart(const librevenge::RVNGPropertyList &propList)
567 {
568 	if (mpImpl->mChartDocumentStates.top().mbChartOpened)
569 	{
570 		ODFGEN_DEBUG_MSG(("OdcGenerator::openChart: a chart is already opened\n"));
571 		return;
572 	}
573 	mpImpl->mChartDocumentStates.push(ChartDocumentState());
574 	mpImpl->mChartDocumentStates.top().mbChartOpened=true;
575 
576 	auto openElement = std::make_shared<TagOpenElement>("chart:chart");
577 	for (int i=0; i<8; ++i)
578 	{
579 		static char const *wh[8] =
580 		{
581 			"chart:class", "chart:column-mapping", "chart:row-mapping",
582 			"svg:height", "svg:width", "xlink:href", "xlink:type", "xml:id"
583 		};
584 		if (propList[wh[i]])
585 			openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
586 	}
587 	if (!propList["xlink:href"])
588 	{
589 		openElement->addAttribute("xlink:href","..");
590 		openElement->addAttribute("xlink:type", "simple");
591 	}
592 
593 	if (propList["librevenge:chart-id"])
594 		openElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(propList["librevenge:chart-id"]->getInt()));
595 	mpImpl->getCurrentStorage()->push_back(openElement);
596 }
597 
closeChart()598 void OdcGenerator::closeChart()
599 {
600 	if (!mpImpl->mChartDocumentStates.top().mbChartOpened)
601 		return;
602 	mpImpl->mChartDocumentStates.pop();
603 	mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:chart"));
604 }
605 
openChartTextObject(const librevenge::RVNGPropertyList & propList)606 void OdcGenerator::openChartTextObject(const librevenge::RVNGPropertyList &propList)
607 {
608 	ChartDocumentState state=mpImpl->mChartDocumentStates.top();
609 	std::string type("");
610 	if (propList["librevenge:zone-type"]) type=propList["librevenge:zone-type"]->getStr().cstr();
611 	if (type!="footer" && type!="legend" && type!="subtitle" && type!="title")
612 	{
613 		ODFGEN_DEBUG_MSG(("OdcGenerator::openChartTextObject: unknown zone type\n"));
614 		return;
615 	}
616 	if (!state.mbChartOpened || state.mbChartTextObjectOpened ||
617 	        (type!="label" && state.mbChartPlotAreaOpened) ||
618 	        (type=="label" && !state.mbChartSerieOpened))
619 	{
620 		ODFGEN_DEBUG_MSG(("OdcGenerator::openChartTextObject: can not open a text zone\n"));
621 		return;
622 	}
623 
624 	std::string what="chart:"+type;
625 	state.mbChartTextObjectOpened=true;
626 	state.mCharTextObjectType=what;
627 	mpImpl->mChartDocumentStates.push(state);
628 
629 	auto openElement = std::make_shared<TagOpenElement>(what.c_str());
630 	for (int i=0; i<4; ++i)
631 	{
632 		static char const *wh[4] =
633 		{
634 			"svg:x", "svg:y", "svg:width", "svg:height"
635 		};
636 		if (propList[wh[i]])
637 			openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
638 	}
639 	if (propList["librevenge:chart-id"])
640 		openElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(propList["librevenge:chart-id"]->getInt()));
641 
642 	if (type=="legend")
643 	{
644 		for (int i=0; i<4; ++i)
645 		{
646 			static char const *wh[4] =
647 			{
648 				"chart:legend-align", "chart:legend-position",
649 				"style:legend-expansion",  "style:legend-expansion-aspect-ratio"
650 			};
651 			if (propList[wh[i]])
652 				openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
653 		}
654 	}
655 	else if (type!="label")
656 	{
657 		if (propList.child("table:cell-range"))
658 		{
659 			librevenge::RVNGString range=
660 			    mpImpl->getAddressString(propList.child("table:cell-range"));
661 			if (!range.empty())
662 				openElement->addAttribute("table:cell-range", range);
663 		}
664 	}
665 	mpImpl->getCurrentStorage()->push_back(openElement);
666 }
667 
closeChartTextObject()668 void OdcGenerator::closeChartTextObject()
669 {
670 	if (!mpImpl->mChartDocumentStates.top().mbChartTextObjectOpened)
671 		return;
672 	std::string wh = mpImpl->mChartDocumentStates.top().mCharTextObjectType;
673 	mpImpl->mChartDocumentStates.pop();
674 	mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>(wh.c_str()));
675 }
676 
openChartPlotArea(const librevenge::RVNGPropertyList & propList)677 void OdcGenerator::openChartPlotArea(const librevenge::RVNGPropertyList &propList)
678 {
679 	ChartDocumentState state=mpImpl->mChartDocumentStates.top();
680 	if (!state.mbChartOpened || state.mbChartTextObjectOpened || state.mbChartPlotAreaOpened)
681 	{
682 		ODFGEN_DEBUG_MSG(("OdcGenerator::openChartPlotArea: can not open the plot area\n"));
683 		return;
684 	}
685 	state.mbChartPlotAreaOpened=true;
686 	mpImpl->mChartDocumentStates.push(state);
687 
688 	auto openElement = std::make_shared<TagOpenElement>("chart:plot-area");
689 	for (int i=0; i<17; ++i)
690 	{
691 		static char const *wh[17] =
692 		{
693 			"chart:data-source-has-labels",
694 			"dr3d:ambient-color", "dr3d:distance", "dr3d:focal-length", "dr3d:lighting-mode",
695 			"dr3d:projection", "dr3d:shade-mode", "dr3d:shadow-slant", "dr3d:transform",
696 			"dr3d:vpn", "dr3d:vrp",
697 			"dr3d:vup", "svg:height", "svg:width", "svg:x", "svg:y",
698 			"xml:id"
699 		};
700 		if (propList[wh[i]])
701 			openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
702 	}
703 	if (propList.child("table:cell-range-address"))
704 	{
705 		librevenge::RVNGString range=
706 		    mpImpl->getAddressString(propList.child("table:cell-range-address"));
707 		if (!range.empty())
708 			openElement->addAttribute("table:cell-range-address", range);
709 	}
710 	if (propList["librevenge:chart-id"])
711 		openElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(propList["librevenge:chart-id"]->getInt()));
712 	mpImpl->getCurrentStorage()->push_back(openElement);
713 
714 	const librevenge::RVNGPropertyListVector *childs=propList.child("librevenge:childs");
715 	for (unsigned long c=0; c<(childs ? childs->count() : 0); ++c)
716 	{
717 		const librevenge::RVNGPropertyList &child=(*childs)[c];
718 		std::string type("");
719 		if (child["librevenge:type"])
720 			type=child["librevenge:type"]->getStr().cstr();
721 		if (type=="stock-gain-marker" || type=="stock-loss-marker" || type=="stock-range-line")
722 		{
723 			std::string what="chart:"+type;
724 			auto childElement = std::make_shared<TagOpenElement>(what.c_str());
725 			if (child["librevenge:chart-id"])
726 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
727 			mpImpl->getCurrentStorage()->push_back(childElement);
728 		}
729 		else if (type=="floor" || type=="wall")
730 		{
731 			std::string what="chart:"+type;
732 			auto childElement = std::make_shared<TagOpenElement>(what.c_str());
733 			if (child["svg:width"])
734 				childElement->addAttribute("svg:width",child["svg:width"]->getStr());
735 			if (child["librevenge:chart-id"])
736 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
737 			mpImpl->getCurrentStorage()->push_back(childElement);
738 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>(what.c_str()));
739 		}
740 		else
741 		{
742 			ODFGEN_DEBUG_MSG(("OdcGenerator::openChartPlotArea: can not find type of child %d\n", int(c)));
743 		}
744 	}
745 }
746 
closeChartPlotArea()747 void OdcGenerator::closeChartPlotArea()
748 {
749 	if (!mpImpl->mChartDocumentStates.top().mbChartPlotAreaOpened)
750 		return;
751 	mpImpl->mChartDocumentStates.pop();
752 	mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:plot-area"));
753 }
754 
insertChartAxis(const librevenge::RVNGPropertyList & propList)755 void OdcGenerator::insertChartAxis(const librevenge::RVNGPropertyList &propList)
756 {
757 	ChartDocumentState state=mpImpl->mChartDocumentStates.top();
758 	if (!state.mbChartPlotAreaOpened)
759 	{
760 		ODFGEN_DEBUG_MSG(("OdcGenerator::insertChartAxis: can not insert axis outside the plot area\n"));
761 		return;
762 	}
763 	auto openElement = std::make_shared<TagOpenElement>("chart:axis");
764 	for (int i=0; i<2; ++i)
765 	{
766 		static char const *wh[2] =
767 		{
768 			"chart:dimension", "chart:name"
769 		};
770 		if (propList[wh[i]])
771 			openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
772 	}
773 	if (propList["librevenge:chart-id"])
774 		openElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(propList["librevenge:chart-id"]->getInt()));
775 	mpImpl->getCurrentStorage()->push_back(openElement);
776 	const librevenge::RVNGPropertyListVector *childs=propList.child("librevenge:childs");
777 	for (unsigned long c=0; c<(childs ? childs->count() : 0); ++c)
778 	{
779 		const librevenge::RVNGPropertyList &child=(*childs)[c];
780 		std::string type("");
781 		if (child["librevenge:type"])
782 			type=child["librevenge:type"]->getStr().cstr();
783 		if (type=="categories")
784 		{
785 			auto childElement = std::make_shared<TagOpenElement>("chart:categories");
786 			if (child.child("table:cell-range-address"))
787 			{
788 				librevenge::RVNGString range=
789 				    mpImpl->getAddressString(child.child("table:cell-range-address"));
790 				if (!range.empty())
791 					childElement->addAttribute("table:cell-range-address", range);
792 			}
793 			mpImpl->getCurrentStorage()->push_back(childElement);
794 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:categories"));
795 		}
796 		else if (type=="grid")
797 		{
798 			auto childElement = std::make_shared<TagOpenElement>("chart:grid");
799 			if (child["chart:class"])
800 				childElement->addAttribute("chart:class",child["chart:class"]->getStr());
801 			if (child["librevenge:chart-id"])
802 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
803 			mpImpl->getCurrentStorage()->push_back(childElement);
804 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:grid"));
805 		}
806 		else if (type=="title")
807 		{
808 			auto childElement = std::make_shared<TagOpenElement>("chart:title");
809 			for (int i=0; i<2; ++i)
810 			{
811 				static char const *wh[2] =
812 				{
813 					"svg:x", "svg:y"
814 				};
815 				if (child[wh[i]])
816 					childElement->addAttribute(wh[i], child[wh[i]]->getStr());
817 			}
818 			if (child["librevenge:chart-id"])
819 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
820 			if (child.child("table:cell-range"))
821 			{
822 				// checkme: does not seem to work
823 				librevenge::RVNGString range=
824 				    mpImpl->getAddressString(child.child("table:cell-range"));
825 				if (!range.empty())
826 					childElement->addAttribute("table:cell-range", range);
827 			}
828 			mpImpl->getCurrentStorage()->push_back(childElement);
829 			if (child["librevenge:text"])
830 			{
831 				mpImpl->getCurrentStorage()->push_back(std::make_shared<TagOpenElement>("text:p"));
832 				mpImpl->getCurrentStorage()->push_back(std::make_shared<TextElement>(child["librevenge:text"]->getStr()));
833 				mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("text:p"));
834 			}
835 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:title"));
836 		}
837 		else
838 		{
839 			ODFGEN_DEBUG_MSG(("OdcGenerator::insertChartAxis: can not find type of child %d\n", int(c)));
840 		}
841 	}
842 	mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:axis"));
843 }
844 
openChartSerie(const librevenge::RVNGPropertyList & propList)845 void OdcGenerator::openChartSerie(const librevenge::RVNGPropertyList &propList)
846 {
847 	ChartDocumentState &state=mpImpl->mChartDocumentStates.top();
848 	if (!state.mbChartPlotAreaOpened || state.mbChartSerieOpened)
849 	{
850 		ODFGEN_DEBUG_MSG(("OdcGenerator::openChartSerie: can not insert serie outside the plot area\n"));
851 		return;
852 	}
853 	state.mbChartSerieOpened=true;
854 	auto openElement = std::make_shared<TagOpenElement>("chart:series");
855 	for (int i=0; i<4; ++i)
856 	{
857 		static char const *wh[4] =
858 		{
859 			"chart:attached-axis", "chart:class", "xml:id", "chart:label-string"
860 		};
861 		if (!propList[wh[i]]) continue;
862 		if (i==3)
863 			openElement->addAttribute("loext:label-string", propList[wh[i]]->getStr());
864 		else
865 			openElement->addAttribute(wh[i], propList[wh[i]]->getStr());
866 	}
867 	if (propList["librevenge:chart-id"])
868 		openElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(propList["librevenge:chart-id"]->getInt()));
869 	for (int i=0; i<2; ++i)
870 	{
871 		static char const *wh[2] =
872 		{
873 			"chart:label-cell-address", "chart:values-cell-range-address"
874 		};
875 		if (propList.child(wh[i]))
876 		{
877 			librevenge::RVNGString range=
878 			    mpImpl->getAddressString(propList.child(wh[i]));
879 			if (!range.empty())
880 				openElement->addAttribute(wh[i], range);
881 		}
882 	}
883 	mpImpl->getCurrentStorage()->push_back(openElement);
884 	const librevenge::RVNGPropertyListVector *childs=propList.child("librevenge:childs");
885 	for (unsigned long c=0; c<(childs ? childs->count() : 0); ++c)
886 	{
887 		const librevenge::RVNGPropertyList &child=(*childs)[c];
888 		std::string type("");
889 		if (child["librevenge:type"])
890 			type=child["librevenge:type"]->getStr().cstr();
891 		if (type=="data-point")
892 		{
893 			auto childElement = std::make_shared<TagOpenElement>("chart:data-point");
894 			for (int i=0; i<2; ++i)
895 			{
896 				static char const *wh[2] =
897 				{
898 					"chart:repeated", "xml:id"
899 				};
900 				if (child[wh[i]])
901 					childElement->addAttribute(wh[i], child[wh[i]]->getStr());
902 			}
903 			if (child["librevenge:chart-id"])
904 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
905 			mpImpl->getCurrentStorage()->push_back(childElement);
906 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:data-point"));
907 		}
908 		else if (type=="domain")
909 		{
910 			auto childElement = std::make_shared<TagOpenElement>("chart:domain");
911 			if (child.child("table:cell-range-address"))
912 			{
913 				librevenge::RVNGString range=
914 				    mpImpl->getAddressString(child.child("table:cell-range-address"));
915 				if (!range.empty())
916 					childElement->addAttribute("table:cell-range-address", range);
917 			}
918 			mpImpl->getCurrentStorage()->push_back(childElement);
919 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:domain"));
920 		}
921 		else if (type=="error-indicator")
922 		{
923 			auto childElement = std::make_shared<TagOpenElement>("chart:error-indicator");
924 			if (child["chart:dimension"])
925 				childElement->addAttribute("chart:dimension", child["chart:dimension"]->getStr());
926 			if (child["librevenge:chart-id"])
927 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
928 			mpImpl->getCurrentStorage()->push_back(childElement);
929 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:error-indicator"));
930 		}
931 		else if (type=="mean-value")
932 		{
933 			auto childElement = std::make_shared<TagOpenElement>("chart:mean-value");
934 			if (child["librevenge:chart-id"])
935 				childElement->addAttribute("chart:style-name",mpImpl->getChartStyleName(child["librevenge:chart-id"]->getInt()));
936 			mpImpl->getCurrentStorage()->push_back(childElement);
937 			mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:mean-value"));
938 		}
939 		else
940 		{
941 			ODFGEN_DEBUG_MSG(("OdcGenerator::openChartSerie: can not find type of child %d\n", int(c)));
942 		}
943 	}
944 }
945 
closeChartSerie()946 void OdcGenerator::closeChartSerie()
947 {
948 	ChartDocumentState &state=mpImpl->mChartDocumentStates.top();
949 	if (!state.mbChartSerieOpened)
950 		return;
951 	state.mbChartSerieOpened=false;
952 	mpImpl->getCurrentStorage()->push_back(std::make_shared<TagCloseElement>("chart:series"));
953 }
954 
955 // -------------------------------
956 //      table
957 // -------------------------------
openTable(const librevenge::RVNGPropertyList & propList)958 void OdcGenerator::openTable(const librevenge::RVNGPropertyList &propList)
959 {
960 	mpImpl->openTable(propList);
961 }
962 
closeTable()963 void OdcGenerator::closeTable()
964 {
965 	mpImpl->closeTable();
966 }
967 
openTableRow(const librevenge::RVNGPropertyList & propList)968 void OdcGenerator::openTableRow(const librevenge::RVNGPropertyList &propList)
969 {
970 	mpImpl->openTableRow(propList);
971 }
972 
closeTableRow()973 void OdcGenerator::closeTableRow()
974 {
975 	if (!mpImpl->canWriteText()) return;
976 	mpImpl->closeTableRow();
977 }
978 
openTableCell(const librevenge::RVNGPropertyList & propList)979 void OdcGenerator::openTableCell(const librevenge::RVNGPropertyList &propList)
980 {
981 	mpImpl->mChartDocumentStates.top().mbTableCellOpened = mpImpl->openTableCell(propList);
982 }
983 
closeTableCell()984 void OdcGenerator::closeTableCell()
985 {
986 	mpImpl->closeTableCell();
987 	mpImpl->mChartDocumentStates.top().mbTableCellOpened = false;
988 }
989 
insertCoveredTableCell(const librevenge::RVNGPropertyList & propList)990 void OdcGenerator::insertCoveredTableCell(const librevenge::RVNGPropertyList &propList)
991 {
992 	mpImpl->insertCoveredTableCell(propList);
993 }
994 
insertTab()995 void OdcGenerator::insertTab()
996 {
997 	if (!mpImpl->canWriteText()) return;
998 	mpImpl->insertTab();
999 }
1000 
insertSpace()1001 void OdcGenerator::insertSpace()
1002 {
1003 	if (!mpImpl->canWriteText()) return;
1004 	mpImpl->insertSpace();
1005 }
1006 
insertLineBreak()1007 void OdcGenerator::insertLineBreak()
1008 {
1009 	if (!mpImpl->canWriteText()) return;
1010 	mpImpl->insertLineBreak();
1011 }
1012 
insertField(const librevenge::RVNGPropertyList & propList)1013 void OdcGenerator::insertField(const librevenge::RVNGPropertyList &propList)
1014 {
1015 	if (!mpImpl->canWriteText()) return;
1016 	mpImpl->insertField(propList);
1017 }
1018 
insertText(const librevenge::RVNGString & text)1019 void OdcGenerator::insertText(const librevenge::RVNGString &text)
1020 {
1021 	if (!mpImpl->canWriteText()) return;
1022 	mpImpl->insertText(text);
1023 }
1024 
endDocument()1025 void OdcGenerator::endDocument()
1026 {
1027 	// Write out the collected document
1028 	mpImpl->writeTargetDocuments();
1029 }
1030 
startDocument(const librevenge::RVNGPropertyList & propList)1031 void OdcGenerator::startDocument(const librevenge::RVNGPropertyList &propList)
1032 {
1033 	mpImpl->appendBodySettings(propList);
1034 }
1035 
initStateWith(OdfGenerator const & orig)1036 void OdcGenerator::initStateWith(OdfGenerator const &orig)
1037 {
1038 	mpImpl->initStateWith(orig);
1039 }
1040 
1041 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
1042