1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2 
3 /* libmwaw
4 * Version: MPL 2.0 / LGPLv2+
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 2.0 (the "License"); you may not use this file except in compliance with
8 * the License or as specified alternatively below. You may obtain a copy of
9 * the License at http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Major Contributor(s):
17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20 * Copyright (C) 2006, 2007 Andrew Ziem
21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22 *
23 *
24 * All Rights Reserved.
25 *
26 * For minor contributions see the git repository.
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30 * in which case the provisions of the LGPLv2+ are applicable
31 * instead of those above.
32 */
33 
34 #include <cstring>
35 #include <iomanip>
36 #include <sstream>
37 #include <time.h>
38 
39 #include <librevenge/librevenge.h>
40 
41 #include "libmwaw/libmwaw.hxx"
42 #include "libmwaw_internal.hxx"
43 
44 #include "MWAWCell.hxx"
45 #include "MWAWFont.hxx"
46 #include "MWAWFontConverter.hxx"
47 #include "MWAWGraphicEncoder.hxx"
48 #include "MWAWGraphicStyle.hxx"
49 #include "MWAWGraphicShape.hxx"
50 #include "MWAWInputStream.hxx"
51 #include "MWAWList.hxx"
52 #include "MWAWParagraph.hxx"
53 #include "MWAWParser.hxx"
54 #include "MWAWPosition.hxx"
55 #include "MWAWSection.hxx"
56 #include "MWAWSubDocument.hxx"
57 #include "MWAWTable.hxx"
58 
59 #include "MWAWPresentationListener.hxx"
60 
61 //! Internal and low level namespace to define the states of MWAWPresentationListener
62 namespace MWAWPresentationListenerInternal
63 {
64 /** the global graphic state of MWAWPresentationListener */
65 struct GraphicState {
66   //! constructor
GraphicStateMWAWPresentationListenerInternal::GraphicState67   explicit GraphicState(std::vector<MWAWPageSpan> const &pageList)
68     : m_pageList(pageList)
69     , m_metaData()
70     , m_isDocumentStarted(false)
71     , m_isPageSpanOpened(false)
72     , m_isMasterPageSpanOpened(false)
73     , m_isAtLeastOnePageOpened(false)
74     , m_isHeaderFooterStarted(false)
75     , m_pageSpan()
76     , m_sentListMarkers()
77     , m_subDocuments()
78     , m_section()
79   {
80   }
81   GraphicState &operator=(GraphicState const &)=default;
82   GraphicState &operator=(GraphicState &&)=default;
83   //! destructor
~GraphicStateMWAWPresentationListenerInternal::GraphicState84   ~GraphicState()
85   {
86   }
87   //! the pages definition
88   std::vector<MWAWPageSpan> m_pageList;
89   //! the document meta data
90   librevenge::RVNGPropertyList m_metaData;
91   /** a flag to know if the document is open */
92   bool m_isDocumentStarted;
93   //! true if a page is open
94   bool m_isPageSpanOpened;
95   //! true if a masterpage is open
96   bool m_isMasterPageSpanOpened;
97   /** true if the first page has been open */
98   bool m_isAtLeastOnePageOpened;
99   /** a flag to know if the header footer is started */
100   bool m_isHeaderFooterStarted;
101   ///! the current page span
102   MWAWPageSpan m_pageSpan;
103   /// the list of marker corresponding to sent list
104   std::vector<int> m_sentListMarkers;
105   //! the list of actual subdocument
106   std::vector<MWAWSubDocumentPtr> m_subDocuments;
107   //! empty section used to return a section in getSection
108   MWAWSection m_section;
109 };
110 
111 /** the state of a MWAWPresentationListener */
112 struct State {
113   //! constructor
114   State();
115   //! destructor
~StateMWAWPresentationListenerInternal::State116   ~State() { }
117 
118 //! returns true if we are in a text zone, ie. either in a textbox or a table cell
isInTextZoneMWAWPresentationListenerInternal::State119   bool isInTextZone() const
120   {
121     return m_inNote || m_inLink || m_isTextBoxOpened || m_isTableCellOpened;
122   }
123   //! the origin position
124   MWAWVec2f m_origin;
125   //! a buffer to stored the text
126   librevenge::RVNGString m_textBuffer;
127 
128   //! the font
129   MWAWFont m_font;
130   //! the paragraph
131   MWAWParagraph m_paragraph;
132   //! the list of list
133   std::shared_ptr<MWAWList> m_list;
134 
135   //! a flag to know if openFrame was called
136   bool m_isFrameOpened;
137   //! the frame position
138   MWAWPosition m_framePosition;
139   //! the frame style
140   MWAWGraphicStyle m_frameStyle;
141 
142   //! a flag to know if we are in a textbox
143   bool m_isTextBoxOpened;
144   //! a flag to know if openGroup was called
145   bool m_isGroupOpened;
146   //! a flag to know if openLayer was called
147   bool m_isLayerOpened;
148   bool m_isSpanOpened;
149   bool m_isParagraphOpened;
150   bool m_isListElementOpened;
151 
152   bool m_firstParagraphInPageSpan;
153 
154   std::vector<bool> m_listOrderedLevels; //! a stack used to know what is open
155 
156   bool m_isTableOpened;
157   bool m_isTableRowOpened;
158   bool m_isTableColumnOpened;
159   bool m_isTableCellOpened;
160 
161   unsigned m_currentPage;
162   int m_numPagesRemainingInSpan;
163   int m_currentPageNumber;
164 
165   bool m_inLink;
166   bool m_inNote;
167   bool m_inSubDocument;
168   libmwaw::SubDocumentType m_subDocumentType;
169 
170 private:
171   State(const State &) = delete;
172   State &operator=(const State &) = delete;
173 };
174 
State()175 State::State()
176   : m_origin(0,0)
177   , m_textBuffer("")
178   , m_font(20,12)/* default time 12 */
179   , m_paragraph()
180   , m_list()
181   , m_isFrameOpened(false)
182   , m_framePosition()
183   , m_frameStyle()
184   , m_isTextBoxOpened(false)
185   , m_isGroupOpened(false)
186   , m_isLayerOpened(false)
187   , m_isSpanOpened(false)
188   , m_isParagraphOpened(false)
189   , m_isListElementOpened(false)
190   , m_firstParagraphInPageSpan(true)
191   , m_listOrderedLevels()
192   , m_isTableOpened(false)
193   , m_isTableRowOpened(false)
194   , m_isTableColumnOpened(false)
195   , m_isTableCellOpened(false)
196   , m_currentPage(0)
197   , m_numPagesRemainingInSpan(0)
198   , m_currentPageNumber(1)
199   , m_inLink(false)
200   , m_inNote(false)
201   , m_inSubDocument(false)
202   , m_subDocumentType(libmwaw::DOC_NONE)
203 {
204 }
205 }
206 
MWAWPresentationListener(MWAWParserState & parserState,std::vector<MWAWPageSpan> const & pageList,librevenge::RVNGPresentationInterface * documentInterface)207 MWAWPresentationListener::MWAWPresentationListener(MWAWParserState &parserState, std::vector<MWAWPageSpan> const &pageList, librevenge::RVNGPresentationInterface *documentInterface)
208   : MWAWListener()
209   , m_ds(new MWAWPresentationListenerInternal::GraphicState(pageList))
210   , m_ps(new MWAWPresentationListenerInternal::State)
211   , m_psStack()
212   , m_parserState(parserState)
213   , m_documentInterface(documentInterface)
214 {
215 }
216 
~MWAWPresentationListener()217 MWAWPresentationListener::~MWAWPresentationListener()
218 {
219 }
220 
221 ///////////////////
222 // text data
223 ///////////////////
insertChar(uint8_t character)224 void MWAWPresentationListener::insertChar(uint8_t character)
225 {
226   if (!m_ps->isInTextZone()) {
227     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: called outside a text zone\n"));
228     return;
229   }
230   if (character >= 0x80) {
231     MWAWPresentationListener::insertUnicode(character);
232     return;
233   }
234   if (!m_ps->m_isSpanOpened) _openSpan();
235   m_ps->m_textBuffer.append(char(character));
236 }
237 
insertCharacter(unsigned char c)238 void MWAWPresentationListener::insertCharacter(unsigned char c)
239 {
240   if (!m_ps->isInTextZone()) {
241     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: called outside a text zone\n"));
242     return;
243   }
244   int unicode = m_parserState.m_fontConverter->unicode(m_ps->m_font.id(), c);
245   if (unicode == -1) {
246     if (c < 0x20) {
247       MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: Find odd char %x\n", static_cast<unsigned int>(c)));
248     }
249     else
250       MWAWPresentationListener::insertChar(static_cast<uint8_t>(c));
251   }
252   else
253     MWAWPresentationListener::insertUnicode(static_cast<uint32_t>(unicode));
254 }
255 
insertCharacter(unsigned char c,MWAWInputStreamPtr & input,long endPos)256 int MWAWPresentationListener::insertCharacter(unsigned char c, MWAWInputStreamPtr &input, long endPos)
257 {
258   if (!m_ps->isInTextZone()) {
259     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: called outside a text zone\n"));
260     return 0;
261   }
262   if (!input || !m_parserState.m_fontConverter) {
263     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: input or font converter does not exist!!!!\n"));
264     return 0;
265   }
266   long debPos=input->tell();
267   int fId = m_ps->m_font.id();
268   int unicode = endPos==debPos ?
269                 m_parserState.m_fontConverter->unicode(fId, c) :
270                 m_parserState.m_fontConverter->unicode(fId, c, input);
271 
272   long pos=input->tell();
273   if (endPos > 0 && pos > endPos) {
274     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: problem reading a character\n"));
275     pos = debPos;
276     input->seek(pos, librevenge::RVNG_SEEK_SET);
277     unicode = m_parserState.m_fontConverter->unicode(fId, c);
278   }
279   if (unicode == -1) {
280     if (c < 0x20) {
281       MWAW_DEBUG_MSG(("MWAWPresentationListener::insertCharacter: Find odd char %x\n", static_cast<unsigned int>(c)));
282     }
283     else
284       MWAWPresentationListener::insertChar(static_cast<uint8_t>(c));
285   }
286   else
287     MWAWPresentationListener::insertUnicode(static_cast<uint32_t>(unicode));
288 
289   return int(pos-debPos);
290 }
291 
insertUnicode(uint32_t val)292 void MWAWPresentationListener::insertUnicode(uint32_t val)
293 {
294   if (!m_ps->isInTextZone()) {
295     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertUnicode: called outside a text zone\n"));
296     return;
297   }
298   // undef character, we skip it
299   if (val == 0xfffd) return;
300 
301   if (!m_ps->m_isSpanOpened) _openSpan();
302   libmwaw::appendUnicode(val, m_ps->m_textBuffer);
303 }
304 
insertUnicodeString(librevenge::RVNGString const & str)305 void MWAWPresentationListener::insertUnicodeString(librevenge::RVNGString const &str)
306 {
307   if (!m_ps->isInTextZone()) {
308     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertUnicodeString: called outside a text zone\n"));
309     return;
310   }
311   if (!m_ps->m_isSpanOpened) _openSpan();
312   m_ps->m_textBuffer.append(str);
313 }
314 
insertEOL(bool soft)315 void MWAWPresentationListener::insertEOL(bool soft)
316 {
317   if (!m_ps->isInTextZone()) {
318     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertEOL: called outside a text zone\n"));
319     return;
320   }
321   if (!m_ps->m_isParagraphOpened && !m_ps->m_isListElementOpened)
322     _openSpan();
323   if (soft) {
324     _flushText();
325     m_documentInterface->insertLineBreak();
326   }
327   else if (m_ps->m_isParagraphOpened)
328     _closeParagraph();
329 
330   // sub/superscript must not survive a new line
331   m_ps->m_font.set(MWAWFont::Script());
332 }
333 
insertTab()334 void MWAWPresentationListener::insertTab()
335 {
336   if (!m_ps->isInTextZone()) {
337     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertTab: called outside a text zone\n"));
338     return;
339   }
340   if (!m_ps->m_isSpanOpened) _openSpan();
341   _flushText();
342   m_documentInterface->insertTab();
343 }
344 
345 ///////////////////
346 // font/paragraph function
347 ///////////////////
setFont(MWAWFont const & font)348 void MWAWPresentationListener::setFont(MWAWFont const &font)
349 {
350   if (!m_ps->isInTextZone()) {
351     MWAW_DEBUG_MSG(("MWAWPresentationListener::setFont: called outside a text zone\n"));
352     return;
353   }
354   if (font == m_ps->m_font) return;
355 
356   // check if id and size are defined, if not used the previous fields
357   MWAWFont finalFont(font);
358   if (font.id() == -1)
359     finalFont.setId(m_ps->m_font.id());
360   if (font.size() <= 0)
361     finalFont.setSize(m_ps->m_font.size());
362   if (finalFont == m_ps->m_font) return;
363 
364   _closeSpan();
365   m_ps->m_font = finalFont;
366 }
367 
getFont() const368 MWAWFont const &MWAWPresentationListener::getFont() const
369 {
370   return m_ps->m_font;
371 }
372 
isParagraphOpened() const373 bool MWAWPresentationListener::isParagraphOpened() const
374 {
375   return m_ps->m_isParagraphOpened;
376 }
377 
setParagraph(MWAWParagraph const & para)378 void MWAWPresentationListener::setParagraph(MWAWParagraph const &para)
379 {
380   if (!m_ps->isInTextZone()) {
381     MWAW_DEBUG_MSG(("MWAWPresentationListener::setParagraph: called outside a text zone\n"));
382     return;
383   }
384   if (para==m_ps->m_paragraph) return;
385 
386   m_ps->m_paragraph=para;
387 }
388 
getParagraph() const389 MWAWParagraph const &MWAWPresentationListener::getParagraph() const
390 {
391   return m_ps->m_paragraph;
392 }
393 
394 ///////////////////
395 // field/link :
396 ///////////////////
insertField(MWAWField const & field)397 void MWAWPresentationListener::insertField(MWAWField const &field)
398 {
399   if (!m_ps->isInTextZone()) {
400     MWAW_DEBUG_MSG(("MWAWPresentationListener::setParagraph: called outside a text zone\n"));
401     return;
402   }
403   librevenge::RVNGPropertyList propList;
404   if (field.addTo(propList)) {
405     _flushText();
406     _openSpan();
407     m_documentInterface->insertField(propList);
408     return;
409   }
410   librevenge::RVNGString text=field.getString();
411   if (!text.empty())
412     MWAWPresentationListener::insertUnicodeString(text);
413   else {
414     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertField: must not be called with type=%d\n", int(field.m_type)));
415   }
416 }
417 
openLink(MWAWLink const & link)418 void MWAWPresentationListener::openLink(MWAWLink const &link)
419 {
420   if (!m_ps->isInTextZone()) {
421     MWAW_DEBUG_MSG(("MWAWPresentationListener::openLink: called outside a textbox\n"));
422     return;
423   }
424   if (m_ps->m_inLink) {
425     MWAW_DEBUG_MSG(("MWAWPresentationListener::openLink: called inside a link\n"));
426     return;
427   }
428   if (!m_ps->m_isSpanOpened) _openSpan();
429   librevenge::RVNGPropertyList propList;
430   link.addTo(propList);
431   m_documentInterface->openLink(propList);
432   _pushParsingState();
433   m_ps->m_inLink=true;
434   // we do not want any close open paragraph in a link
435   m_ps->m_isParagraphOpened=true;
436 }
437 
closeLink()438 void MWAWPresentationListener::closeLink()
439 {
440   if (!m_ps->m_inLink) {
441     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeLink: closed outside a link\n"));
442     return;
443   }
444   _flushText();
445   m_documentInterface->closeLink();
446   _popParsingState();
447 }
448 
449 ///////////////////
450 // document
451 ///////////////////
startDocument()452 void MWAWPresentationListener::startDocument()
453 {
454   if (m_ds->m_isDocumentStarted) {
455     MWAW_DEBUG_MSG(("MWAWPresentationListener::startDocument: the document is already started\n"));
456     return;
457   }
458   m_ds->m_isDocumentStarted=true;
459   m_documentInterface->startDocument(librevenge::RVNGPropertyList());
460   m_documentInterface->setDocumentMetaData(m_ds->m_metaData);
461 }
462 
endDocument(bool)463 void MWAWPresentationListener::endDocument(bool /*delayed*/)
464 {
465   if (!m_ds->m_isDocumentStarted) {
466     MWAW_DEBUG_MSG(("MWAWPresentationListener::endDocument: the document is not started\n"));
467     return;
468   }
469   if (!m_ds->m_isAtLeastOnePageOpened) {
470     MWAW_DEBUG_MSG(("MWAWPresentationListener::endDocument: no data have been send\n"));
471     _openPageSpan();
472   }
473   if (m_ds->m_isPageSpanOpened)
474     _closePageSpan(m_ds->m_isMasterPageSpanOpened);
475   m_documentInterface->endDocument();
476   m_ds->m_isDocumentStarted=false;
477   *m_ds=MWAWPresentationListenerInternal::GraphicState(std::vector<MWAWPageSpan>());
478 }
479 
480 ///////////////////
481 // document
482 ///////////////////
setDocumentMetaData(librevenge::RVNGPropertyList const & meta)483 void MWAWPresentationListener::setDocumentMetaData(librevenge::RVNGPropertyList const &meta)
484 {
485   librevenge::RVNGPropertyList::Iter i(meta);
486   for (i.rewind(); i.next();)
487     m_ds->m_metaData.insert(i.key(), i()->getStr());
488 }
489 
setDocumentLanguage(std::string const & locale)490 void MWAWPresentationListener::setDocumentLanguage(std::string const &locale)
491 {
492   if (!locale.length()) return;
493   m_ds->m_metaData.insert("librevenge:language", locale.c_str());
494 }
495 
isDocumentStarted() const496 bool MWAWPresentationListener::isDocumentStarted() const
497 {
498   return m_ds->m_isDocumentStarted;
499 }
500 
canWriteText() const501 bool MWAWPresentationListener::canWriteText() const
502 {
503   return m_ds->m_isPageSpanOpened && m_ps->isInTextZone();
504 }
505 
506 ///////////////////
507 // page
508 ///////////////////
isPageSpanOpened() const509 bool MWAWPresentationListener::isPageSpanOpened() const
510 {
511   return m_ds->m_isPageSpanOpened;
512 }
513 
getPageSpan()514 MWAWPageSpan const &MWAWPresentationListener::getPageSpan()
515 {
516   if (!m_ds->m_isPageSpanOpened)
517     _openPageSpan();
518   return m_ds->m_pageSpan;
519 }
520 
openMasterPage(MWAWPageSpan & masterPage)521 bool MWAWPresentationListener::openMasterPage(MWAWPageSpan &masterPage)
522 {
523   if (m_ds->m_isMasterPageSpanOpened) {
524     MWAW_DEBUG_MSG(("MWAWPresentationListener::openMasterPage: a master page is already opened\n"));
525     return false;
526   }
527   if (!m_ds->m_isDocumentStarted)
528     startDocument();
529   if (m_ds->m_isPageSpanOpened)
530     _closePageSpan();
531 
532   librevenge::RVNGPropertyList propList;
533   masterPage.getPageProperty(propList, true);
534   propList.insert("svg:width",72.*masterPage.getFormWidth(), librevenge::RVNG_POINT);
535   propList.insert("svg:height",72.*masterPage.getFormLength(), librevenge::RVNG_POINT);
536 
537   m_documentInterface->startMasterSlide(propList);
538   m_ds->m_isPageSpanOpened = m_ds->m_isMasterPageSpanOpened = true;
539 
540   // checkme: can we send some header/footer if some exists
541   return true;
542 }
543 
_openPageSpan(bool sendHeaderFooters)544 void MWAWPresentationListener::_openPageSpan(bool sendHeaderFooters)
545 {
546   if (m_ds->m_isPageSpanOpened)
547     return;
548 
549   if (!m_ds->m_isDocumentStarted)
550     startDocument();
551 
552   if (m_ds->m_pageList.size()==0) {
553     MWAW_DEBUG_MSG(("MWAWPresentationListener::_openPageSpan: can not find any page\n"));
554     throw libmwaw::ParseException();
555   }
556   m_ds->m_isAtLeastOnePageOpened=true;
557   unsigned actPage = 0;
558   auto it = m_ds->m_pageList.begin();
559   m_ps->m_currentPage++;
560   while (true) {
561     actPage+=static_cast<unsigned>(it->getPageSpan());
562     if (actPage >= m_ps->m_currentPage) break;
563     if (++it == m_ds->m_pageList.end()) {
564       MWAW_DEBUG_MSG(("MWAWPresentationListener::_openPageSpan: can not find current page, use the previous one\n"));
565       --it;
566       break;
567     }
568   }
569 
570   MWAWPageSpan &currentPage = *it;
571   librevenge::RVNGPropertyList propList;
572   currentPage.getPageProperty(propList, true);
573   propList.insert("librevenge:is-last-page-span", ++it == m_ds->m_pageList.end());
574   // now add data for embedded graph
575   propList.insert("svg:x",double(m_ps->m_origin.x()), librevenge::RVNG_POINT);
576   propList.insert("svg:y",double(m_ps->m_origin.y()), librevenge::RVNG_POINT);
577   propList.insert("svg:width",72.*currentPage.getFormWidth(), librevenge::RVNG_POINT);
578   propList.insert("svg:height",72.*currentPage.getFormLength(), librevenge::RVNG_POINT);
579   propList.insert("librevenge:enforce-frame",true);
580 
581   if (!m_ds->m_isPageSpanOpened)
582     m_documentInterface->startSlide(propList);
583   m_ds->m_isPageSpanOpened = true;
584   m_ds->m_pageSpan = currentPage;
585 
586   // we insert the header footer
587   if (sendHeaderFooters)
588     currentPage.sendHeaderFooters(this, (m_ps->m_currentPage%2) ? MWAWHeaderFooter::EVEN : MWAWHeaderFooter::ODD);
589 
590   // first paragraph in span (necessary for resetting page number)
591   m_ps->m_firstParagraphInPageSpan = true;
592   m_ps->m_numPagesRemainingInSpan = (currentPage.getPageSpan() - 1);
593 }
594 
_closePageSpan(bool masterPage)595 void MWAWPresentationListener::_closePageSpan(bool masterPage)
596 {
597   if (!m_ds->m_isPageSpanOpened)
598     return;
599 
600   if (masterPage && !m_ds->m_isMasterPageSpanOpened) {
601     MWAW_DEBUG_MSG(("MWAWPresentationListener::endDocument:no master page are opened\n"));
602     return;
603   }
604   if (!masterPage && m_ds->m_isMasterPageSpanOpened) {
605     MWAW_DEBUG_MSG(("MWAWPresentationListener::endDocument:a master page are opened\n"));
606     return;
607   }
608   if (m_ps->m_inSubDocument) {
609     MWAW_DEBUG_MSG(("MWAWPresentationListener::endDocument: we are in a sub document\n"));
610     _endSubDocument();
611     _popParsingState();
612   }
613   if (m_ps->m_isTableOpened) {
614     MWAW_DEBUG_MSG(("MWAWPresentationListener::_closePageSpan: we are in a table zone\n"));
615     closeTable();
616   }
617   if (m_ps->isInTextZone()) {
618     MWAW_DEBUG_MSG(("MWAWPresentationListener::_closePageSpan: we are in a text zone\n"));
619     if (m_ps->m_isParagraphOpened)
620       _closeParagraph();
621     m_ps->m_paragraph.m_listLevelIndex = 0;
622     _changeList(); // flush the list exterior
623   }
624   m_ds->m_isPageSpanOpened = m_ds->m_isMasterPageSpanOpened = false;
625   if (masterPage)
626     m_documentInterface->endMasterSlide();
627   else
628     m_documentInterface->endSlide();
629 }
630 
631 ///////////////////
632 // paragraph
633 ///////////////////
_openParagraph()634 void MWAWPresentationListener::_openParagraph()
635 {
636   if (m_ps->m_inNote || (m_ps->m_isTableOpened && !m_ps->m_isTableCellOpened))
637     return;
638   if (!m_ps->isInTextZone()) {
639     MWAW_DEBUG_MSG(("MWAWPresentationListener::_openParagraph: called outsize a text zone\n"));
640     return;
641   }
642   if (m_ps->m_isParagraphOpened || m_ps->m_isListElementOpened) {
643     MWAW_DEBUG_MSG(("MWAWPresentationListener::_openParagraph: a paragraph (or a list) is already opened"));
644     return;
645   }
646 
647   librevenge::RVNGPropertyList propList;
648   m_ps->m_paragraph.addTo(propList, m_ps->m_isTableCellOpened);
649   m_documentInterface->openParagraph(propList);
650 
651   _resetParagraphState();
652   m_ps->m_firstParagraphInPageSpan = false;
653 }
654 
_closeParagraph()655 void MWAWPresentationListener::_closeParagraph()
656 {
657   if (!m_ps->isInTextZone()) {
658     MWAW_DEBUG_MSG(("MWAWPresentationListener::_closeParagraph: called outsize a text zone\n"));
659     return;
660   }
661   if (m_ps->m_inLink) return;
662   if (m_ps->m_isListElementOpened) {
663     _closeListElement();
664     return;
665   }
666 
667   if (m_ps->m_isParagraphOpened) {
668     if (m_ps->m_isSpanOpened)
669       _closeSpan();
670     m_documentInterface->closeParagraph();
671   }
672 
673   m_ps->m_isParagraphOpened = false;
674   m_ps->m_paragraph.m_listLevelIndex = 0;
675 }
676 
_resetParagraphState(const bool isListElement)677 void MWAWPresentationListener::_resetParagraphState(const bool isListElement)
678 {
679   m_ps->m_isListElementOpened = isListElement;
680   m_ps->m_isParagraphOpened = true;
681 }
682 
683 ///////////////////
684 // list
685 ///////////////////
_openListElement()686 void MWAWPresentationListener::_openListElement()
687 {
688   if (m_ps->m_inNote || (m_ps->m_isTableOpened && !m_ps->m_isTableCellOpened))
689     return;
690   if (!m_ps->isInTextZone()) {
691     MWAW_DEBUG_MSG(("MWAWPresentationListener::_openListElement: called outsize a text zone\n"));
692     return;
693   }
694   if (m_ps->m_isParagraphOpened || m_ps->m_isListElementOpened)
695     return;
696 
697   librevenge::RVNGPropertyList propList;
698   m_ps->m_paragraph.addTo(propList,m_ps->m_isTableOpened);
699 
700   // check if we must change the start value
701   int startValue=m_ps->m_paragraph.m_listStartValue.get();
702   if (startValue > 0 && m_ps->m_list && m_ps->m_list->getStartValueForNextElement() != startValue) {
703     propList.insert("text:start-value", startValue);
704     m_ps->m_list->setStartValueForNextElement(startValue);
705   }
706 
707   if (m_ps->m_list) m_ps->m_list->openElement();
708   m_documentInterface->openListElement(propList);
709   _resetParagraphState(true);
710 }
711 
_closeListElement()712 void MWAWPresentationListener::_closeListElement()
713 {
714   if (m_ps->m_isListElementOpened) {
715     if (m_ps->m_isSpanOpened)
716       _closeSpan();
717 
718     if (m_ps->m_list) m_ps->m_list->closeElement();
719     m_documentInterface->closeListElement();
720   }
721 
722   m_ps->m_isListElementOpened = m_ps->m_isParagraphOpened = false;
723 }
724 
_getListId() const725 int MWAWPresentationListener::_getListId() const
726 {
727   auto newLevel= size_t(m_ps->m_paragraph.m_listLevelIndex.get());
728   if (newLevel == 0) return -1;
729   int newListId = m_ps->m_paragraph.m_listId.get();
730   if (newListId > 0) return newListId;
731   static bool first = true;
732   if (first) {
733     MWAW_DEBUG_MSG(("MWAWPresentationListener::_getListId: the list id is not set, try to find a new one\n"));
734     first = false;
735   }
736   auto list=m_parserState.m_listManager->getNewList(m_ps->m_list, int(newLevel), *m_ps->m_paragraph.m_listLevel);
737   if (!list) return -1;
738   return list->getId();
739 }
740 
_changeList()741 void MWAWPresentationListener::_changeList()
742 {
743   if (m_ps->m_inNote || !m_ps->isInTextZone()) {
744     MWAW_DEBUG_MSG(("MWAWPresentationListener::_changeList: called outsize a text zone\n"));
745     return;
746   }
747   if (m_ps->m_isParagraphOpened)
748     _closeParagraph();
749 
750   size_t actualLevel = m_ps->m_listOrderedLevels.size();
751   auto newLevel= size_t(m_ps->m_paragraph.m_listLevelIndex.get());
752   if (newLevel>100) {
753     MWAW_DEBUG_MSG(("MWAWPresentationListener::_changeList: find level=%d, set it to 100\n", static_cast<int>(newLevel)));
754     newLevel=100;
755   }
756   int newListId = newLevel>0 ? _getListId() : -1;
757   bool changeList = newLevel &&
758                     (m_ps->m_list && m_ps->m_list->getId()!=newListId);
759   size_t minLevel = changeList ? 0 : newLevel;
760   while (actualLevel > minLevel) {
761     if (m_ps->m_listOrderedLevels[--actualLevel])
762       m_documentInterface->closeOrderedListLevel();
763     else
764       m_documentInterface->closeUnorderedListLevel();
765   }
766 
767   if (newLevel) {
768     std::shared_ptr<MWAWList> theList;
769 
770     theList=m_parserState.m_listManager->getList(newListId);
771     if (!theList) {
772       MWAW_DEBUG_MSG(("MWAWPresentationListener::_changeList: can not find any list\n"));
773       m_ps->m_listOrderedLevels.resize(actualLevel);
774       return;
775     }
776     m_parserState.m_listManager->needToSend(newListId, m_ds->m_sentListMarkers);
777     m_ps->m_list = theList;
778     m_ps->m_list->setLevel(static_cast<int>(newLevel));
779   }
780 
781   m_ps->m_listOrderedLevels.resize(newLevel, false);
782   if (actualLevel == newLevel) return;
783 
784   librevenge::RVNGPropertyList propList;
785   propList.insert("librevenge:list-id", m_ps->m_list->getId());
786   for (size_t i=actualLevel+1; i<= newLevel; i++) {
787     bool ordered = m_ps->m_list->isNumeric(int(i));
788     m_ps->m_listOrderedLevels[i-1] = ordered;
789 
790     librevenge::RVNGPropertyList level;
791     m_ps->m_list->addTo(int(i), level, m_parserState.m_fontManager);
792     if (ordered)
793       m_documentInterface->openOrderedListLevel(level);
794     else
795       m_documentInterface->openUnorderedListLevel(level);
796   }
797 }
798 
799 ///////////////////
800 // span
801 ///////////////////
_openSpan()802 void MWAWPresentationListener::_openSpan()
803 {
804   if (m_ps->m_isTableOpened && !m_ps->m_isTableCellOpened)
805     return;
806   if (m_ps->m_inLink)
807     return;
808   if (!m_ps->isInTextZone()) {
809     MWAW_DEBUG_MSG(("MWAWPresentationListener::_openSpan: called outsize a text zone\n"));
810     return;
811   }
812   if (m_ps->m_isSpanOpened)
813     return;
814 
815   if (!m_ps->m_isParagraphOpened && !m_ps->m_isListElementOpened) {
816     _changeList();
817     if (*m_ps->m_paragraph.m_listLevelIndex == 0)
818       _openParagraph();
819     else
820       _openListElement();
821   }
822 
823   librevenge::RVNGPropertyList propList;
824   m_ps->m_font.addTo(propList, m_parserState.m_fontConverter);
825 
826   m_documentInterface->openSpan(propList);
827 
828   m_ps->m_isSpanOpened = true;
829 }
830 
_closeSpan()831 void MWAWPresentationListener::_closeSpan()
832 {
833   if (m_ps->m_isTableOpened && !m_ps->m_isTableCellOpened)
834     return;
835   if (!m_ps->isInTextZone()) {
836     MWAW_DEBUG_MSG(("MWAWPresentationListener::_closeSpan: called outsize a text zone\n"));
837     return;
838   }
839   if (!m_ps->m_isSpanOpened)
840     return;
841 
842   _flushText();
843   m_documentInterface->closeSpan();
844   m_ps->m_isSpanOpened = false;
845 }
846 
847 ///////////////////
848 // text (send data)
849 ///////////////////
_flushText()850 void MWAWPresentationListener::_flushText()
851 {
852   if (m_ps->m_textBuffer.len() == 0) return;
853 
854   // when some many ' ' follows each other, call insertSpace
855   librevenge::RVNGString tmpText("");
856   int numConsecutiveSpaces = 0;
857   librevenge::RVNGString::Iter i(m_ps->m_textBuffer);
858   for (i.rewind(); i.next();) {
859     if (*(i()) == 0x20) // this test is compatible with unicode format
860       numConsecutiveSpaces++;
861     else
862       numConsecutiveSpaces = 0;
863 
864     if (numConsecutiveSpaces > 1) {
865       if (tmpText.len() > 0) {
866         m_documentInterface->insertText(tmpText);
867         tmpText.clear();
868       }
869       m_documentInterface->insertSpace();
870     }
871     else
872       tmpText.append(i());
873   }
874   m_documentInterface->insertText(tmpText);
875   m_ps->m_textBuffer.clear();
876 }
877 
878 ///////////////////
879 // header/footer
880 ///////////////////
isHeaderFooterOpened() const881 bool MWAWPresentationListener::isHeaderFooterOpened() const
882 {
883   return m_ds->m_isHeaderFooterStarted;
884 }
885 
insertHeader(MWAWSubDocumentPtr const & subDocument,librevenge::RVNGPropertyList const & extras)886 bool MWAWPresentationListener::insertHeader(MWAWSubDocumentPtr const &subDocument, librevenge::RVNGPropertyList const &extras)
887 {
888   if (m_ds->m_isHeaderFooterStarted) {
889     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertHeader: Oops a header/footer is already opened\n"));
890     return false;
891   }
892   // we do not have any header interface, so mimick it by creating a textbox
893   MWAWPosition pos(MWAWVec2f(20,20), MWAWVec2f(-20,-10), librevenge::RVNG_POINT); // fixme
894   pos.m_anchorTo=MWAWPosition::Page;
895   if (!openFrame(pos))
896     return false;
897   librevenge::RVNGPropertyList propList(extras);
898   _handleFrameParameters(propList, pos, MWAWGraphicStyle::emptyStyle());
899 
900   m_documentInterface->startTextObject(propList);
901   handleSubDocument(pos.origin(), subDocument, libmwaw::DOC_HEADER_FOOTER);
902   m_documentInterface->endTextObject();
903   closeFrame();
904   return true;
905 }
906 
insertFooter(MWAWSubDocumentPtr const & subDocument,librevenge::RVNGPropertyList const & extras)907 bool MWAWPresentationListener::insertFooter(MWAWSubDocumentPtr const &subDocument, librevenge::RVNGPropertyList const &extras)
908 {
909   if (m_ds->m_isHeaderFooterStarted) {
910     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertFooter: Oops a header/footer is already opened\n"));
911     return false;
912   }
913   MWAW_DEBUG_MSG(("MWAWPresentationListener::insertFooter: inserting footer is very experimental\n"));
914 
915   // we do not have any header interface, so mimick it by creating a textbox
916   MWAWPageSpan page(getPageSpan()); // fixme
917   MWAWPosition pos(MWAWVec2f(20,72.f*float(page.getFormLength())-40.f), MWAWVec2f(-20,-10), librevenge::RVNG_POINT);
918   pos.m_anchorTo=MWAWPosition::Page;
919   if (!openFrame(pos))
920     return false;
921   librevenge::RVNGPropertyList propList(extras);
922   _handleFrameParameters(propList, pos, MWAWGraphicStyle::emptyStyle());
923 
924   m_documentInterface->startTextObject(propList);
925   handleSubDocument(pos.origin(), subDocument, libmwaw::DOC_HEADER_FOOTER);
926   m_documentInterface->endTextObject();
927   closeFrame();
928   return true;
929 }
930 
931 ///////////////////
932 // section
933 ///////////////////
getSection() const934 MWAWSection const &MWAWPresentationListener::getSection() const
935 {
936   MWAW_DEBUG_MSG(("MWAWPresentationListener::getSection: must not be called\n"));
937   return m_ds->m_section;
938 }
939 
openSection(MWAWSection const &)940 bool MWAWPresentationListener::openSection(MWAWSection const &)
941 {
942   MWAW_DEBUG_MSG(("MWAWPresentationListener::openSection: must not be called\n"));
943   return false;
944 }
945 
insertBreak(BreakType breakType)946 void MWAWPresentationListener::insertBreak(BreakType breakType)
947 {
948   if (m_ps->m_inSubDocument)
949     return;
950 
951   switch (breakType) {
952   case ColumnBreak:
953     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertBreak: must not be called on column\n"));
954     break;
955   case SoftPageBreak:
956   case PageBreak:
957     if (m_ds->m_isMasterPageSpanOpened) {
958       MWAW_DEBUG_MSG(("MWAWPresentationListener::insertBreak: can not insert a page break in master page definition\n"));
959       break;
960     }
961     if (!m_ds->m_isPageSpanOpened)
962       _openPageSpan();
963     _closePageSpan();
964     break;
965 #if !defined(__clang__)
966   default:
967     break;
968 #endif
969   }
970 }
971 
972 ///////////////////
973 // note/comment ( we inserted them as text between -- -- )
974 ///////////////////
insertComment(MWAWSubDocumentPtr & subDocument)975 void MWAWPresentationListener::insertComment(MWAWSubDocumentPtr &subDocument)
976 {
977   if (!canWriteText() || m_ps->m_inNote) {
978     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertComment try to insert recursively or outside a text zone\n"));
979     return;
980   }
981   // first check that a paragraph is already open
982   if (!m_ps->m_isParagraphOpened && !m_ps->m_isListElementOpened)
983     _openParagraph();
984   insertChar(' ');
985   insertUnicode(0x2014); // -
986   insertChar(' ');
987   handleSubDocument(subDocument, libmwaw::DOC_COMMENT_ANNOTATION);
988   insertChar(' ');
989   insertUnicode(0x2014); // -
990   insertChar(' ');
991 }
992 
insertNote(MWAWNote const &,MWAWSubDocumentPtr & subDocument)993 void MWAWPresentationListener::insertNote(MWAWNote const &, MWAWSubDocumentPtr &subDocument)
994 {
995   if (!canWriteText() || m_ps->m_inNote) {
996     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertNote try to insert recursively or outside a text zone\n"));
997     return;
998   }
999   // first check that a paragraph is already open
1000   if (!m_ps->m_isParagraphOpened && !m_ps->m_isListElementOpened)
1001     _openParagraph();
1002   insertChar(' ');
1003   insertUnicode(0x2014); // -
1004   insertChar(' ');
1005   handleSubDocument(subDocument, libmwaw::DOC_NOTE);
1006   insertChar(' ');
1007   insertUnicode(0x2014); // -
1008   insertChar(' ');
1009 }
1010 
1011 ///////////////////
1012 // picture/textbox
1013 ///////////////////
1014 
insertShape(MWAWPosition const & pos,MWAWGraphicShape const & shape,MWAWGraphicStyle const & style)1015 void MWAWPresentationListener::insertShape
1016 (MWAWPosition const &pos, MWAWGraphicShape const &shape, MWAWGraphicStyle const &style)
1017 {
1018   if (!m_ds->m_isDocumentStarted) {
1019     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertShape: the document is not started\n"));
1020     return;
1021   }
1022   if (!m_ds->m_isPageSpanOpened)
1023     _openPageSpan();
1024   if (m_ps->m_isFrameOpened) {
1025     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertShape: a frame is already open\n"));
1026     return;
1027   }
1028 
1029   librevenge::RVNGPropertyList list, shapePList;
1030   style.addTo(list, shape.getType()==MWAWGraphicShape::Line);
1031   m_documentInterface->setStyle(list);
1032   switch (shape.addTo(1.f/pos.getInvUnitScale(librevenge::RVNG_POINT)*pos.origin()-m_ps->m_origin, style.hasSurface(), shapePList)) {
1033   case MWAWGraphicShape::C_Ellipse:
1034     m_documentInterface->drawEllipse(shapePList);
1035     break;
1036   case MWAWGraphicShape::C_Path:
1037     m_documentInterface->drawPath(shapePList);
1038     break;
1039   case MWAWGraphicShape::C_Polyline:
1040     m_documentInterface->drawPolyline(shapePList);
1041     break;
1042   case MWAWGraphicShape::C_Polygon:
1043     m_documentInterface->drawPolygon(shapePList);
1044     break;
1045   case MWAWGraphicShape::C_Rectangle:
1046     m_documentInterface->drawRectangle(shapePList);
1047     break;
1048   case MWAWGraphicShape::C_Bad:
1049     break;
1050 #if !defined(__clang__)
1051   default:
1052     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertShape: unexpected shape\n"));
1053     break;
1054 #endif
1055   }
1056 }
1057 
insertPicture(MWAWPosition const & pos,MWAWEmbeddedObject const & picture,MWAWGraphicStyle const & style)1058 void MWAWPresentationListener::insertPicture(MWAWPosition const &pos, MWAWEmbeddedObject const &picture, MWAWGraphicStyle const &style)
1059 {
1060   if (!m_ds->m_isDocumentStarted) {
1061     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertPicture: the document is not started\n"));
1062     return;
1063   }
1064   if (m_ps->m_isFrameOpened) {
1065     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertPicture: a frame is already open\n"));
1066     return;
1067   }
1068   if (!m_ds->m_isPageSpanOpened)
1069     _openPageSpan();
1070   librevenge::RVNGPropertyList list;
1071   style.addTo(list);
1072   m_documentInterface->setStyle(list);
1073 
1074   list.clear();
1075   _handleFrameParameters(list, pos, style);
1076   float rotate = style.m_rotate;
1077   if (style.m_flip[0]&&style.m_flip[1]) rotate += 180.f;
1078   if (rotate<0||rotate>0) {
1079     list.insert("librevenge:rotate", double(rotate), librevenge::RVNG_GENERIC);
1080     float pointFactor =1.f/pos.getInvUnitScale(librevenge::RVNG_POINT);
1081     MWAWVec2f size=pointFactor*pos.size();
1082     if (size[0]<0) size[0]=-size[0];
1083     if (size[1]<0) size[1]=-size[1];
1084     MWAWVec2f center=pointFactor*pos.origin()-m_ps->m_origin+0.5f*size;
1085     list.insert("librevenge:rotate-cx",double(center[0]), librevenge::RVNG_POINT);
1086     list.insert("librevenge:rotate-cy",double(center[1]), librevenge::RVNG_POINT);
1087   }
1088   if (picture.addTo(list))
1089     m_documentInterface->drawGraphicObject(list);
1090 }
1091 
insertTextBox(MWAWPosition const & pos,MWAWSubDocumentPtr const & subDocument,MWAWGraphicStyle const & style)1092 void MWAWPresentationListener::insertTextBox
1093 (MWAWPosition const &pos, MWAWSubDocumentPtr const &subDocument, MWAWGraphicStyle const &style)
1094 {
1095   if (!m_ds->m_isDocumentStarted) {
1096     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertTextBox: the document is not started\n"));
1097     return;
1098   }
1099   if (!m_ds->m_isPageSpanOpened)
1100     _openPageSpan();
1101   float pointFactor =1.f/pos.getInvUnitScale(librevenge::RVNG_POINT);
1102   if (m_ps->m_isTextBoxOpened) {
1103     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertTextBox: can not insert a textbox in a textbox\n"));
1104     handleSubDocument(pointFactor*pos.origin(), subDocument, libmwaw::DOC_TEXT_BOX);
1105     return;
1106   }
1107   if (!openFrame(pos))
1108     return;
1109   librevenge::RVNGPropertyList propList;
1110   _handleFrameParameters(propList, pos, style);
1111   float rotate = style.m_rotate;
1112   // flip does not works on text, so we ignore it...
1113   if (style.m_flip[0]&&style.m_flip[1]) rotate += 180.f;
1114   if (rotate<0||rotate>0) {
1115     propList.insert("librevenge:rotate", double(rotate), librevenge::RVNG_GENERIC);
1116     MWAWVec2f size=pointFactor*pos.size();
1117     if (size[0]<0) size[0]=-size[0];
1118     if (size[1]<0) size[1]=-size[1];
1119     MWAWVec2f center=pointFactor*pos.origin()-m_ps->m_origin+0.5f*size;
1120     propList.insert("librevenge:rotate-cx", double(center[0]), librevenge::RVNG_POINT);
1121     propList.insert("librevenge:rotate-cy", double(center[1]), librevenge::RVNG_POINT);
1122   }
1123   m_documentInterface->startTextObject(propList);
1124   handleSubDocument(pointFactor*pos.origin(), subDocument, libmwaw::DOC_TEXT_BOX);
1125   m_documentInterface->endTextObject();
1126   closeFrame();
1127 }
1128 
insertSlideNote(MWAWPosition const & pos,MWAWSubDocumentPtr & subDocument)1129 void MWAWPresentationListener::insertSlideNote(MWAWPosition const &pos, MWAWSubDocumentPtr &subDocument)
1130 {
1131   if (!m_ds->m_isDocumentStarted) {
1132     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertSlideNote: the document is not started\n"));
1133     return;
1134   }
1135   if (!m_ds->m_isPageSpanOpened)
1136     _openPageSpan();
1137   float pointFactor =1.f/pos.getInvUnitScale(librevenge::RVNG_POINT);
1138   if (m_ps->m_isTextBoxOpened) {
1139     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertSlideNote: can not insert a textbox in a textbox\n"));
1140     handleSubDocument(pointFactor*pos.origin(), subDocument, libmwaw::DOC_TEXT_BOX);
1141     return;
1142   }
1143   if (!openFrame(pos))
1144     return;
1145   librevenge::RVNGPropertyList propList;
1146   _handleFrameParameters(propList, pos, MWAWGraphicStyle::emptyStyle());
1147   m_documentInterface->startNotes(propList);
1148   handleSubDocument(pointFactor*pos.origin(), subDocument, libmwaw::DOC_TEXT_BOX);
1149   m_documentInterface->endNotes();
1150   closeFrame();
1151 }
1152 
insertGroup(MWAWBox2f const & bdbox,MWAWSubDocumentPtr const & subDocument)1153 void MWAWPresentationListener::insertGroup(MWAWBox2f const &bdbox, MWAWSubDocumentPtr const &subDocument)
1154 {
1155   if (!m_ds->m_isDocumentStarted || m_ps->isInTextZone()) {
1156     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertGroup: can not insert a group\n"));
1157     return;
1158   }
1159   if (!m_ds->m_isPageSpanOpened)
1160     _openPageSpan();
1161   handleSubDocument(bdbox[0], subDocument, libmwaw::DOC_GRAPHIC_GROUP);
1162 }
1163 
1164 ///////////////////
1165 // table
1166 ///////////////////
insertTable(MWAWPosition const & pos,MWAWTable & table,MWAWGraphicStyle const & style)1167 void MWAWPresentationListener::insertTable
1168 (MWAWPosition const &pos, MWAWTable &table, MWAWGraphicStyle const &style)
1169 {
1170   if (!m_ds->m_isDocumentStarted || m_ps->m_inSubDocument) {
1171     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertTable insert a table in a subdocument is not implemented\n"));
1172     return;
1173   }
1174   if (!openFrame(pos, style)) return;
1175 
1176   _pushParsingState();
1177   _startSubDocument();
1178   m_ps->m_subDocumentType = libmwaw::DOC_TABLE;
1179 
1180   std::shared_ptr<MWAWListener> listen(this, MWAW_shared_ptr_noop_deleter<MWAWPresentationListener>());
1181   try {
1182     table.sendTable(listen);
1183   }
1184   catch (...) {
1185     MWAW_DEBUG_MSG(("MWAWPresentationListener::insertTable exception catched \n"));
1186   }
1187   _endSubDocument();
1188   _popParsingState();
1189 
1190   closeFrame();
1191 }
1192 
openTable(MWAWTable const & table)1193 void MWAWPresentationListener::openTable(MWAWTable const &table)
1194 {
1195   if (!m_ps->m_isFrameOpened) {
1196     if (m_ps->m_isTextBoxOpened) {
1197       MWAW_DEBUG_MSG(("MWAWPresentationListener::openTable: must not be called inside a textbox\n"));
1198       MWAWPosition pos(m_ps->m_origin, MWAWVec2f(400,100), librevenge::RVNG_POINT);
1199       pos.m_anchorTo=MWAWPosition::Page;
1200       openTable(pos, table, MWAWGraphicStyle::emptyStyle());
1201       return;
1202     }
1203     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTable: called outside openFrame\n"));
1204     return;
1205   }
1206   openTable(m_ps->m_framePosition, table, m_ps->m_frameStyle);
1207 }
1208 
openTable(MWAWPosition const & pos,MWAWTable const & table,MWAWGraphicStyle const & style)1209 void MWAWPresentationListener::openTable(MWAWPosition const &pos, MWAWTable const &table, MWAWGraphicStyle const &style)
1210 {
1211   if (!m_ps->m_isFrameOpened || m_ps->m_isTableOpened) {
1212     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTable: no frame is already open...\n"));
1213     return;
1214   }
1215 
1216   if (m_ps->m_isParagraphOpened)
1217     _closeParagraph();
1218 
1219   librevenge::RVNGPropertyList propList;
1220   // default value: which can be redefined by table
1221   propList.insert("table:align", "left");
1222   propList.insert("fo:margin-left", *m_ps->m_paragraph.m_margins[1], *m_ps->m_paragraph.m_marginsUnit);
1223   _pushParsingState();
1224   _startSubDocument();
1225   m_ps->m_subDocumentType = libmwaw::DOC_TABLE;
1226 
1227   _handleFrameParameters(propList, pos, style);
1228   table.addTablePropertiesTo(propList);
1229   m_documentInterface->startTableObject(propList);
1230   m_ps->m_isTableOpened = true;
1231 }
1232 
closeTable()1233 void MWAWPresentationListener::closeTable()
1234 {
1235   if (!m_ps->m_isTableOpened) {
1236     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeTable: called with m_isTableOpened=false\n"));
1237     return;
1238   }
1239 
1240   m_ps->m_isTableOpened = false;
1241   _endSubDocument();
1242   m_documentInterface->endTableObject();
1243 
1244   _popParsingState();
1245 }
1246 
openTableRow(float h,librevenge::RVNGUnit unit,bool headerRow)1247 void MWAWPresentationListener::openTableRow(float h, librevenge::RVNGUnit unit, bool headerRow)
1248 {
1249   if (m_ps->m_isTableRowOpened) {
1250     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTableRow: called with m_isTableRowOpened=true\n"));
1251     return;
1252   }
1253   if (!m_ps->m_isTableOpened) {
1254     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTableRow: called with m_isTableOpened=false\n"));
1255     return;
1256   }
1257   librevenge::RVNGPropertyList propList;
1258   propList.insert("librevenge:is-header-row", headerRow);
1259 
1260   if (h > 0)
1261     propList.insert("style:row-height", double(h), unit);
1262   else if (h < 0)
1263     propList.insert("style:min-row-height", double(-h), unit);
1264   m_documentInterface->openTableRow(propList);
1265   m_ps->m_isTableRowOpened = true;
1266 }
1267 
closeTableRow()1268 void MWAWPresentationListener::closeTableRow()
1269 {
1270   if (!m_ps->m_isTableRowOpened) {
1271     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeTableRow: called with m_isTableRowOpened=false\n"));
1272     return;
1273   }
1274   m_ps->m_isTableRowOpened = false;
1275   m_documentInterface->closeTableRow();
1276 }
1277 
addEmptyTableCell(MWAWVec2i const & pos,MWAWVec2i span)1278 void MWAWPresentationListener::addEmptyTableCell(MWAWVec2i const &pos, MWAWVec2i span)
1279 {
1280   if (!m_ps->m_isTableRowOpened) {
1281     MWAW_DEBUG_MSG(("MWAWPresentationListener::addEmptyTableCell: called with m_isTableRowOpened=false\n"));
1282     return;
1283   }
1284   if (m_ps->m_isTableCellOpened) {
1285     MWAW_DEBUG_MSG(("MWAWPresentationListener::addEmptyTableCell: called with m_isTableCellOpened=true\n"));
1286     closeTableCell();
1287   }
1288   librevenge::RVNGPropertyList propList;
1289   propList.insert("librevenge:column", pos[0]);
1290   propList.insert("librevenge:row", pos[1]);
1291   propList.insert("table:number-columns-spanned", span[0]);
1292   propList.insert("table:number-rows-spanned", span[1]);
1293   m_documentInterface->openTableCell(propList);
1294   m_documentInterface->closeTableCell();
1295 }
1296 
openTableCell(MWAWCell const & cell)1297 void MWAWPresentationListener::openTableCell(MWAWCell const &cell)
1298 {
1299   if (!m_ps->m_isTableRowOpened) {
1300     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTableCell: called with m_isTableRowOpened=false\n"));
1301     return;
1302   }
1303   if (m_ps->m_isTableCellOpened) {
1304     MWAW_DEBUG_MSG(("MWAWPresentationListener::openTableCell: called with m_isTableCellOpened=true\n"));
1305     closeTableCell();
1306   }
1307 
1308   librevenge::RVNGPropertyList propList;
1309   cell.addTo(propList, m_parserState.m_fontConverter);
1310   m_ps->m_isTableCellOpened = true;
1311   m_documentInterface->openTableCell(propList);
1312 }
1313 
closeTableCell()1314 void MWAWPresentationListener::closeTableCell()
1315 {
1316   if (!m_ps->m_isTableCellOpened) {
1317     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeTableCell: called with m_isTableCellOpened=false\n"));
1318     return;
1319   }
1320 
1321   _closeParagraph();
1322   m_ps->m_paragraph.m_listLevelIndex=0;
1323   _changeList(); // flush the list exterior
1324 
1325   m_documentInterface->closeTableCell();
1326   m_ps->m_isTableCellOpened = false;
1327 }
1328 
1329 ///////////////////
1330 // frame/group
1331 ///////////////////
openFrame(MWAWPosition const & pos,MWAWGraphicStyle const & style)1332 bool MWAWPresentationListener::openFrame(MWAWPosition const &pos, MWAWGraphicStyle const &style)
1333 {
1334   if (!m_ds->m_isDocumentStarted) {
1335     MWAW_DEBUG_MSG(("MWAWPresentationListener::openFrame: the document is not started\n"));
1336     return false;
1337   }
1338   if (m_ps->m_isTableOpened && !m_ps->m_isTableCellOpened) {
1339     MWAW_DEBUG_MSG(("MWAWPresentationListener::openFrame: called in table but cell is not opened\n"));
1340     return false;
1341   }
1342   if (m_ps->m_isFrameOpened) {
1343     MWAW_DEBUG_MSG(("MWAWPresentationListener::openFrame: called but a frame is already opened\n"));
1344     return false;
1345   }
1346   if (!m_ds->m_isPageSpanOpened)
1347     _openPageSpan();
1348   m_ps->m_isFrameOpened = true;
1349   m_ps->m_framePosition=pos;
1350   m_ps->m_frameStyle=style;
1351   return true;
1352 }
1353 
closeFrame()1354 void MWAWPresentationListener::closeFrame()
1355 {
1356   if (!m_ps->m_isFrameOpened) {
1357     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeFrame: called but no frame is already opened\n"));
1358     return;
1359   }
1360   m_ps->m_isFrameOpened = false;
1361 }
1362 
openGroup(MWAWPosition const & pos)1363 bool  MWAWPresentationListener::openGroup(MWAWPosition const &pos)
1364 {
1365   if (!m_ds->m_isDocumentStarted) {
1366     MWAW_DEBUG_MSG(("MWAWPresentationListener::openGroup: the document is not started\n"));
1367     return false;
1368   }
1369   if (m_ps->m_isTableOpened || m_ps->isInTextZone()) {
1370     MWAW_DEBUG_MSG(("MWAWPresentationListener::openGroup: called in table or in a text zone\n"));
1371     return false;
1372   }
1373   if (!m_ds->m_isPageSpanOpened)
1374     _openPageSpan();
1375 
1376   librevenge::RVNGPropertyList propList;
1377   _handleFrameParameters(propList, pos, MWAWGraphicStyle::emptyStyle());
1378 
1379   _pushParsingState();
1380   _startSubDocument();
1381   m_ps->m_isGroupOpened = true;
1382 
1383   m_documentInterface->openGroup(propList);
1384 
1385   return true;
1386 }
1387 
closeGroup()1388 void  MWAWPresentationListener::closeGroup()
1389 {
1390   if (!m_ps->m_isGroupOpened) {
1391     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeGroup: called but no group is already opened\n"));
1392     return;
1393   }
1394   _endSubDocument();
1395   _popParsingState();
1396   m_documentInterface->closeGroup();
1397 }
1398 
openLayer(librevenge::RVNGString const & layerName)1399 bool MWAWPresentationListener::openLayer(librevenge::RVNGString const &layerName)
1400 {
1401   if (!m_ds->m_isDocumentStarted) {
1402     MWAW_DEBUG_MSG(("MWAWPresentationListener::openLayer: the document is not started\n"));
1403     return false;
1404   }
1405   if (m_ps->m_isTableOpened || m_ps->isInTextZone()) {
1406     MWAW_DEBUG_MSG(("MWAWPresentationListener::openLayer: called in table or in a text zone\n"));
1407     return false;
1408   }
1409   if (m_ps->m_isLayerOpened) {
1410     MWAW_DEBUG_MSG(("MWAWPresentationListener::openLayer: called but layer is already opened\n"));
1411     return false;
1412   }
1413   if (!m_ds->m_isPageSpanOpened)
1414     _openPageSpan();
1415 
1416   _pushParsingState();
1417   _startSubDocument();
1418   m_ps->m_isLayerOpened = true;
1419 
1420   librevenge::RVNGPropertyList propList;
1421   propList.insert("draw:layer", layerName);
1422   m_documentInterface->startLayer(propList);
1423   return true;
1424 }
1425 
closeLayer()1426 void  MWAWPresentationListener::closeLayer()
1427 {
1428   if (!m_ps->m_isLayerOpened) {
1429     MWAW_DEBUG_MSG(("MWAWPresentationListener::closeLayer: called but no layer is already opened\n"));
1430     return;
1431   }
1432   m_documentInterface->endLayer();
1433   _endSubDocument();
1434   _popParsingState();
1435 }
1436 
_handleFrameParameters(librevenge::RVNGPropertyList & list,MWAWPosition const & pos,MWAWGraphicStyle const & style)1437 void MWAWPresentationListener::_handleFrameParameters(librevenge::RVNGPropertyList &list, MWAWPosition const &pos, MWAWGraphicStyle const &style)
1438 {
1439   if (!m_ds->m_isDocumentStarted)
1440     return;
1441 
1442   librevenge::RVNGUnit unit = pos.unit();
1443   float pointFactor = pos.getInvUnitScale(librevenge::RVNG_POINT);
1444   float inchFactor=pos.getInvUnitScale(librevenge::RVNG_INCH);
1445   // first compute the origin ( in given unit and in point)
1446   MWAWVec2f origin = pos.origin()-pointFactor*m_ps->m_origin;
1447   MWAWVec2f originPt = (1.f/pointFactor)*pos.origin()-m_ps->m_origin;
1448   MWAWVec2f size = pos.size();
1449   // checkme: do we still need to do that ?
1450   if (style.hasGradient(true)) {
1451     if (style.m_rotate<0 || style.m_rotate>0) {
1452       MWAW_DEBUG_MSG(("MWAWPresentationListener::_handleFrameParameters: rotation is not implemented\n"));
1453     }
1454     // ok, first send a background rectangle
1455     librevenge::RVNGPropertyList rectList;
1456     m_documentInterface->setStyle(rectList);
1457     rectList.clear();
1458     rectList.insert("svg:x",double(originPt[0]), librevenge::RVNG_POINT);
1459     rectList.insert("svg:y",double(originPt[1]), librevenge::RVNG_POINT);
1460     rectList.insert("svg:width",size.x()>0 ? double(size.x()) : double(-size.x()), unit);
1461     rectList.insert("svg:height",size.y()>0 ? double(size.y()) : double(-size.y()), unit);
1462     m_documentInterface->drawRectangle(rectList);
1463 
1464     list.insert("draw:stroke", "none");
1465     list.insert("draw:fill", "none");
1466   }
1467   else
1468     style.addTo(list);
1469 
1470   list.insert("svg:x", double(originPt[0]), librevenge::RVNG_POINT);
1471   list.insert("svg:y", double(originPt[1]), librevenge::RVNG_POINT);
1472   if (size.x()>0)
1473     list.insert("svg:width", double(size.x()), unit);
1474   else if (size.x()<0)
1475     list.insert("fo:min-width", double(-size.x()), unit);
1476   if (size.y()>0)
1477     list.insert("svg:height", double(size.y()), unit);
1478   else if (size.y()<0)
1479     list.insert("fo:min-height", double(-size.y()), unit);
1480   if (pos.order() > 0)
1481     list.insert("draw:z-index", pos.order());
1482   if (pos.naturalSize().x() > 4*pointFactor && pos.naturalSize().y() > 4*pointFactor) {
1483     list.insert("librevenge:naturalWidth", double(pos.naturalSize().x()), pos.unit());
1484     list.insert("librevenge:naturalHeight", double(pos.naturalSize().y()), pos.unit());
1485   }
1486   MWAWVec2f TLClip = (1.f/pointFactor)*pos.leftTopClipping();
1487   MWAWVec2f RBClip = (1.f/pointFactor)*pos.rightBottomClipping();
1488   if (TLClip[0] > 0 || TLClip[1] > 0 || RBClip[0] > 0 || RBClip[1] > 0) {
1489     // in ODF1.2 we need to separate the value with ,
1490     std::stringstream s;
1491     s << "rect(" << TLClip[1] << "pt " << RBClip[0] << "pt "
1492       <<  RBClip[1] << "pt " << TLClip[0] << "pt)";
1493     list.insert("fo:clip", s.str().c_str());
1494   }
1495 
1496   if (pos.m_wrapping ==  MWAWPosition::WDynamic)
1497     list.insert("style:wrap", "dynamic");
1498   else if (pos.m_wrapping ==  MWAWPosition::WBackground) {
1499     list.insert("style:wrap", "run-through");
1500     list.insert("style:run-through", "background");
1501   }
1502   else if (pos.m_wrapping ==  MWAWPosition::WForeground) {
1503     list.insert("style:wrap", "run-through");
1504     list.insert("style:run-through", "foreground");
1505   }
1506   else if (pos.m_wrapping ==  MWAWPosition::WParallel) {
1507     list.insert("style:wrap", "parallel");
1508     list.insert("style:run-through", "foreground");
1509   }
1510   else if (pos.m_wrapping ==  MWAWPosition::WRunThrough)
1511     list.insert("style:wrap", "run-through");
1512   else
1513     list.insert("style:wrap", "none");
1514   if (pos.m_anchorTo != MWAWPosition::Page) {
1515     MWAW_DEBUG_MSG(("MWAWPresentationListener::_handleFrameParameters: only page anchor is implemented\n"));
1516   }
1517   else {
1518     double w = m_ds->m_pageSpan.getFormWidth();
1519     double h = m_ds->m_pageSpan.getFormLength();
1520     w *= double(inchFactor);
1521     h *= double(inchFactor);
1522     double newPosition;
1523     switch (pos.m_yPos) {
1524     case MWAWPosition::YFull:
1525       list.insert("svg:height", double(h), unit);
1526       MWAW_FALLTHROUGH;
1527     case MWAWPosition::YTop:
1528       if (origin[1] < 0 || origin[1] > 0) {
1529         list.insert("style:vertical-pos", "from-top");
1530         newPosition = double(origin[1]);
1531         if (newPosition > h -double(pos.size()[1]))
1532           newPosition = h - double(pos.size()[1]);
1533         list.insert("svg:y", double(newPosition), unit);
1534       }
1535       else
1536         list.insert("style:vertical-pos", "top");
1537       break;
1538     case MWAWPosition::YCenter:
1539       if (origin[1] < 0 || origin[1] > 0) {
1540         list.insert("style:vertical-pos", "from-top");
1541         newPosition = (h - double(pos.size()[1]))/2.0;
1542         if (newPosition > h -double(pos.size()[1])) newPosition = h - double(pos.size()[1]);
1543         list.insert("svg:y", double(newPosition), unit);
1544       }
1545       else
1546         list.insert("style:vertical-pos", "middle");
1547       break;
1548     case MWAWPosition::YBottom:
1549       if (origin[1] < 0 || origin[1] > 0) {
1550         list.insert("style:vertical-pos", "from-top");
1551         newPosition = h - double(pos.size()[1])-double(origin[1]);
1552         if (newPosition > h -double(pos.size()[1])) newPosition = h -double(pos.size()[1]);
1553         else if (newPosition < 0) newPosition = 0;
1554         list.insert("svg:y", double(newPosition), unit);
1555       }
1556       else
1557         list.insert("style:vertical-pos", "bottom");
1558       break;
1559 #if !defined(__clang__)
1560     default:
1561       break;
1562 #endif
1563     }
1564 
1565     switch (pos.m_xPos) {
1566     case MWAWPosition::XFull:
1567       list.insert("svg:width", double(w), unit);
1568       MWAW_FALLTHROUGH;
1569     case MWAWPosition::XLeft:
1570       if (origin[0] < 0 || origin[0] > 0) {
1571         list.insert("style:horizontal-pos", "from-left");
1572         list.insert("svg:x", double(origin[0]), unit);
1573       }
1574       else
1575         list.insert("style:horizontal-pos", "left");
1576       break;
1577     case MWAWPosition::XRight:
1578       if (origin[0] < 0 || origin[0] > 0) {
1579         list.insert("style:horizontal-pos", "from-left");
1580         list.insert("svg:x",w - double(pos.size()[0]) + double(origin[0]), unit);
1581       }
1582       else
1583         list.insert("style:horizontal-pos", "right");
1584       break;
1585     case MWAWPosition::XCenter:
1586       if (origin[0] < 0 || origin[0] > 0) {
1587         list.insert("style:horizontal-pos", "from-left");
1588         list.insert("svg:x", (w - double(pos.size()[0]))/2. + double(origin[0]), unit);
1589       }
1590       else
1591         list.insert("style:horizontal-pos", "center");
1592       break;
1593 #if !defined(__clang__)
1594     default:
1595       break;
1596 #endif
1597     }
1598 
1599   }
1600   float const padding = 0; // fillme
1601   list.insert("fo:padding-top", double(padding), librevenge::RVNG_POINT);
1602   list.insert("fo:padding-bottom", double(padding), librevenge::RVNG_POINT);
1603   list.insert("fo:padding-left", double(padding), librevenge::RVNG_POINT);
1604   list.insert("fo:padding-right", double(padding), librevenge::RVNG_POINT);
1605 }
1606 
1607 ///////////////////
1608 // subdocument
1609 ///////////////////
handleSubDocument(MWAWVec2f const & orig,MWAWSubDocumentPtr const & subDocument,libmwaw::SubDocumentType subDocumentType)1610 void MWAWPresentationListener::handleSubDocument(MWAWVec2f const &orig, MWAWSubDocumentPtr const &subDocument, libmwaw::SubDocumentType subDocumentType)
1611 {
1612   if (!m_ds->m_isDocumentStarted) {
1613     MWAW_DEBUG_MSG(("MWAWPresentationListener::handleSubDocument: the graphic is not started\n"));
1614     return;
1615   }
1616   if (!m_ds->m_isPageSpanOpened)
1617     _openPageSpan();
1618   MWAWVec2f actOrigin=m_ps->m_origin;
1619   _pushParsingState();
1620   m_ps->m_origin=actOrigin-orig;
1621   _startSubDocument();
1622   m_ps->m_subDocumentType = subDocumentType;
1623 
1624   m_ps->m_list.reset();
1625   if (subDocumentType==libmwaw::DOC_TEXT_BOX)
1626     m_ps->m_isTextBoxOpened=true;
1627   else if (subDocumentType==libmwaw::DOC_HEADER_FOOTER) {
1628     m_ps->m_isTextBoxOpened=true;
1629     m_ds->m_isHeaderFooterStarted = true;
1630   }
1631   else if (subDocumentType==libmwaw::DOC_COMMENT_ANNOTATION || subDocumentType==libmwaw::DOC_NOTE)
1632     m_ps->m_inNote=true;
1633   // Check whether the document is calling itself
1634   bool sendDoc = true;
1635   for (auto doc : m_ds->m_subDocuments) {
1636     if (!subDocument)
1637       break;
1638     if (!doc) continue;
1639     if (*subDocument == *doc) {
1640       MWAW_DEBUG_MSG(("MWAWPresentationListener::handleSubDocument: recursif call, stop...\n"));
1641       sendDoc = false;
1642       break;
1643     }
1644   }
1645   if (sendDoc) {
1646     if (subDocument) {
1647       m_ds->m_subDocuments.push_back(subDocument);
1648       std::shared_ptr<MWAWListener> listen(this, MWAW_shared_ptr_noop_deleter<MWAWListener>());
1649       try {
1650         subDocument->parse(listen, subDocumentType);
1651       }
1652       catch (...) {
1653         MWAW_DEBUG_MSG(("MWAWPresentationListener::handleSubDocument exception catched\n"));
1654       }
1655       m_ds->m_subDocuments.pop_back();
1656     }
1657   }
1658 
1659   _endSubDocument();
1660   _popParsingState();
1661 
1662   if (subDocumentType==libmwaw::DOC_HEADER_FOOTER)
1663     m_ds->m_isHeaderFooterStarted = false;
1664 }
1665 
isSubDocumentOpened(libmwaw::SubDocumentType & subdocType) const1666 bool MWAWPresentationListener::isSubDocumentOpened(libmwaw::SubDocumentType &subdocType) const
1667 {
1668   if (!m_ds->m_isDocumentStarted || !m_ps->m_inSubDocument)
1669     return false;
1670   subdocType = m_ps->m_subDocumentType;
1671   return true;
1672 }
1673 
_startSubDocument()1674 void MWAWPresentationListener::_startSubDocument()
1675 {
1676   if (!m_ds->m_isDocumentStarted) return;
1677   m_ps->m_inSubDocument = true;
1678 }
1679 
_endSubDocument()1680 void MWAWPresentationListener::_endSubDocument()
1681 {
1682   if (!m_ds->m_isDocumentStarted) return;
1683   if (m_ps->m_isTableOpened)
1684     closeTable();
1685   if (m_ps->m_isParagraphOpened)
1686     _closeParagraph();
1687   if (m_ps->isInTextZone()) {
1688     m_ps->m_paragraph.m_listLevelIndex=0;
1689     _changeList(); // flush the list exterior
1690   }
1691 }
1692 
1693 ///////////////////
1694 // others
1695 ///////////////////
1696 
1697 // ---------- state stack ------------------
_pushParsingState()1698 std::shared_ptr<MWAWPresentationListenerInternal::State> MWAWPresentationListener::_pushParsingState()
1699 {
1700   auto actual = m_ps;
1701   m_psStack.push_back(actual);
1702   m_ps.reset(new MWAWPresentationListenerInternal::State);
1703   m_ps->m_origin=actual->m_origin;
1704   return actual;
1705 }
1706 
_popParsingState()1707 void MWAWPresentationListener::_popParsingState()
1708 {
1709   if (m_psStack.size()==0) {
1710     MWAW_DEBUG_MSG(("MWAWPresentationListener::_popParsingState: psStack is empty()\n"));
1711     throw libmwaw::ParseException();
1712   }
1713   m_ps = m_psStack.back();
1714   m_psStack.pop_back();
1715 }
1716 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
1717