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