1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * This file is part of the libetonyek project.
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 
10 #include "PAG1TextStorageElement.h"
11 
12 #include <cassert>
13 #include <string>
14 
15 #include <boost/optional.hpp>
16 
17 #include <librevenge/librevenge.h>
18 
19 #include "IWORKGroupElement.h"
20 #include "IWORKLayoutElement.h"
21 #include "IWORKLinkElement.h"
22 #include "IWORKMediaElement.h"
23 #include "IWORKPElement.h"
24 #include "IWORKPositionElement.h"
25 #include "IWORKRefContext.h"
26 #include "IWORKSizeElement.h"
27 #include "IWORKShapeContext.h"
28 #include "IWORKSpanElement.h"
29 #include "IWORKTabularInfoElement.h"
30 #include "IWORKText.h"
31 #include "IWORKTextBodyElement.h"
32 #include "IWORKToken.h"
33 #include "PAG1AnnotationElement.h"
34 #include "PAG1Dictionary.h"
35 #include "PAG1FootnotesElement.h"
36 #include "PAG1ParserState.h"
37 #include "PAGCollector.h"
38 #include "libetonyek_xml.h"
39 
40 namespace libetonyek
41 {
42 
43 using boost::optional;
44 
45 using std::string;
46 
47 namespace
48 {
49 
50 struct ContainerFrame
51 {
52   ContainerFrame();
53 
54   optional<double> m_w;
55   optional<double> m_h;
56   optional<double> m_x;
57   optional<double> m_y;
58 };
59 
ContainerFrame()60 ContainerFrame::ContainerFrame()
61   : m_w()
62   , m_h()
63   , m_x()
64   , m_y()
65 {
66 }
67 
68 }
69 
70 namespace
71 {
72 
73 class AttachmentElement : public PAG1XMLElementContextBase
74 {
75 public:
76   explicit AttachmentElement(PAG1ParserState &state);
77 
78 private:
79   void attribute(int name, const char *value) override;
80   void startOfElement() override;
81   IWORKXMLContextPtr_t element(int name) override;
82   void endOfElement() override;
83 
84 private:
85   bool m_known;
86   bool m_block;
87   optional<IWORKPosition> m_position;
88   optional<IWORKSize> m_originalSize;
89   std::shared_ptr<IWORKText> m_savedText;
90 };
91 
AttachmentElement(PAG1ParserState & state)92 AttachmentElement::AttachmentElement(PAG1ParserState &state)
93   : PAG1XMLElementContextBase(state)
94   , m_known(false)
95   , m_block(false)
96   , m_position()
97   , m_originalSize()
98   , m_savedText()
99 {
100 }
101 
attribute(const int name,const char * const value)102 void AttachmentElement::attribute(const int name, const char *const value)
103 {
104   switch (name)
105   {
106   case IWORKToken::NS_URI_SFA | IWORKToken::sfclass :
107   case IWORKToken::NS_URI_SF | IWORKToken::kind :
108     break;
109   case IWORKToken::NS_URI_SFA | IWORKToken::ID :
110     return PAG1XMLElementContextBase::attribute(name, value);
111   default:
112     ETONYEK_DEBUG_MSG(("AttachmentElement::attribute[PAG1TextStorageElement]: find some unknown attribute\n"));
113     break;
114   }
115 }
116 
startOfElement()117 void AttachmentElement::startOfElement()
118 {
119   // saved the current zone of text
120   m_savedText=getState().m_currentText;
121   getState().m_currentText.reset();
122 
123   if (isCollector())
124     getCollector().startAttachment();
125 }
126 
element(const int name)127 IWORKXMLContextPtr_t AttachmentElement::element(const int name)
128 {
129   IWORKXMLContextPtr_t context;
130 
131   switch (name)
132   {
133   case IWORKToken::NS_URI_SF | IWORKToken::drawable_shape :
134   {
135     m_block = false;
136     context = std::make_shared<IWORKShapeContext>(getState());
137     break;
138   }
139   case IWORKToken::NS_URI_SF | IWORKToken::group :
140   {
141     static bool first=true;
142     if (first)
143     {
144       ETONYEK_DEBUG_MSG(("AttachmentElement::attribute[PAG1TextStorageElement]: find some groups attached in textbox, not implemented\n"));
145       first=false;
146     }
147     //m_block = true;
148     //context = std::make_shared<IWORKGroupElement>(getState());
149     break;
150   }
151   case IWORKToken::NS_URI_SF | IWORKToken::media :
152     m_block = false;
153     context = std::make_shared<IWORKMediaElement>(getState());
154     break;
155   case IWORKToken::NS_URI_SF | IWORKToken::original_size :
156     return std::make_shared<IWORKSizeElement>(getState(), m_originalSize);
157   case IWORKToken::NS_URI_SF | IWORKToken::position :
158     return std::make_shared<IWORKPositionElement>(getState(), m_position);
159   case IWORKToken::NS_URI_SF | IWORKToken::tabular_info :
160     m_block = true;
161     context = std::make_shared<IWORKTabularInfoElement>(getState());
162     break;
163   default:
164     ETONYEK_DEBUG_MSG(("AttachmentElement::element[PAG1TextStorageElement]: find some unknown element\n"));
165   }
166 
167   if (bool(context))
168   {
169     m_known = true;
170     if (isCollector())
171       getCollector().getOutputManager().push();
172   }
173 
174   return context;
175 }
176 
endOfElement()177 void AttachmentElement::endOfElement()
178 {
179   if (isCollector())
180   {
181     if (m_known)
182     {
183       if (m_position)
184         getCollector().collectAttachmentPosition(get(m_position));
185       if (getId())
186         getState().getDictionary().m_attachments[get(getId())] = PAGAttachment(getCollector().getOutputManager().save(), m_block);
187       getCollector().getOutputManager().pop();
188     }
189     getCollector().endAttachment();
190   }
191   // reset the current zone of text
192   getState().m_currentText=m_savedText;
193 }
194 
195 }
196 
197 namespace
198 {
199 
200 class AttachmentsElement : public PAG1XMLElementContextBase
201 {
202 public:
203   explicit AttachmentsElement(PAG1ParserState &state);
204 
205 private:
206   void startOfElement() override;
207   IWORKXMLContextPtr_t element(int name) override;
208   void endOfElement() override;
209 };
210 
AttachmentsElement(PAG1ParserState & state)211 AttachmentsElement::AttachmentsElement(PAG1ParserState &state)
212   : PAG1XMLElementContextBase(state)
213 {
214 }
215 
startOfElement()216 void AttachmentsElement::startOfElement()
217 {
218   if (isCollector())
219     getCollector().startAttachments();
220 }
221 
element(const int name)222 IWORKXMLContextPtr_t AttachmentsElement::element(const int name)
223 {
224   if (name == (IWORKToken::NS_URI_SF | IWORKToken::attachment))
225     return std::make_shared<AttachmentElement>(getState());
226   return IWORKXMLContextPtr_t();
227 }
228 
endOfElement()229 void AttachmentsElement::endOfElement()
230 {
231   if (isCollector())
232     getCollector().endAttachments();
233 }
234 
235 }
236 
237 namespace
238 {
239 class AttachmentRef  : public PAG1XMLElementContextBase
240 {
241 public:
242   explicit AttachmentRef(PAG1ParserState &state);
243 
244 private:
245   void attribute(const int name, const char *const value) override;
246   IWORKXMLContextPtr_t element(int name) override;
247   void endOfElement() override;
248 
249   boost::optional<ID_t> m_ref;
250   boost::optional<std::string> m_kind;
251 };
252 
AttachmentRef(PAG1ParserState & state)253 AttachmentRef::AttachmentRef(PAG1ParserState &state)
254   : PAG1XMLElementContextBase(state)
255   , m_ref()
256   , m_kind()
257 {
258 }
259 
attribute(const int name,const char * const value)260 void AttachmentRef::attribute(const int name, const char *const value)
261 {
262   switch (name)
263   {
264   case IWORKToken::NS_URI_SFA | IWORKToken::IDREF :
265     m_ref = value;
266     break;
267   case IWORKToken::NS_URI_SF | IWORKToken::kind :
268     m_kind = value;
269     break;
270   default:
271     ETONYEK_DEBUG_MSG(("AttachmentRef::attribute[PAG1TextStorageElement]: find unexpected attribute\n"));
272   }
273 }
274 
element(int)275 IWORKXMLContextPtr_t AttachmentRef::element(int /*name*/)
276 {
277   ETONYEK_DEBUG_MSG(("AttachmentRef::element[PAG1TextStorageElement]: find unexpected element\n"));
278   return IWORKXMLContextPtr_t();
279 }
280 
endOfElement()281 void AttachmentRef::endOfElement()
282 {
283   if (!isCollector())
284     return;
285   if (!m_ref)
286   {
287     ETONYEK_DEBUG_MSG(("AttachmentRef::endOfElement[PAG1TextStorageElement]: called without ref\n"));
288     return;
289   }
290   if (!getState().m_currentText)
291   {
292     ETONYEK_DEBUG_MSG(("AttachmentRef::endOfElement[PAG1TextStorageElement]: can not find attachment current text\n"));
293     return;
294   }
295 
296   const PAGAttachmentMap_t::const_iterator it = getState().getDictionary().m_attachments.find(get(m_ref));
297   if (it != getState().getDictionary().m_attachments.end())
298   {
299     const IWORKOutputElements &content = getCollector().getOutputManager().get(it->second.m_id);
300     if (it->second.m_block)
301       getState().m_currentText->insertBlockContent(content);
302     else
303       getState().m_currentText->insertInlineContent(content);
304   }
305   else
306   {
307     ETONYEK_DEBUG_MSG(("AttachmentRef::endOfElement[PAG1TextStorageElement]: can not find attachment %s\n", get(m_ref).c_str()));
308   }
309 }
310 
311 }
312 
313 namespace
314 {
315 
316 class FootnoteElement : public PAG1XMLEmptyContextBase
317 {
318 public:
319   explicit FootnoteElement(PAG1ParserState &state);
320 
321 private:
322   void endOfElement() override;
323 };
324 
FootnoteElement(PAG1ParserState & state)325 FootnoteElement::FootnoteElement(PAG1ParserState &state)
326   : PAG1XMLEmptyContextBase(state)
327 {
328 }
329 
endOfElement()330 void FootnoteElement::endOfElement()
331 {
332   if (getState().m_footnoteState.m_nextFootnote != getState().m_footnoteState.m_footnotes.end())
333   {
334     if (bool(getState().m_currentText))
335       getState().m_currentText->insertInlineContent(*getState().m_footnoteState.m_nextFootnote);
336     ++getState().m_footnoteState.m_nextFootnote;
337   }
338 }
339 
340 }
341 
342 namespace
343 {
344 
345 class FootnotebrElement : public PAG1XMLEmptyContextBase
346 {
347 public:
348   explicit FootnotebrElement(PAG1ParserState &state);
349 
350 private:
351   void endOfElement() override;
352 };
353 
FootnotebrElement(PAG1ParserState & state)354 FootnotebrElement::FootnotebrElement(PAG1ParserState &state)
355   : PAG1XMLEmptyContextBase(state)
356 {
357 }
358 
endOfElement()359 void FootnotebrElement::endOfElement()
360 {
361   getState().m_footnoteState.m_pending = true;
362 }
363 
364 }
365 
366 namespace
367 {
368 
369 class FootnoteMarkElement : public PAG1XMLEmptyContextBase
370 {
371 public:
372   explicit FootnoteMarkElement(PAG1ParserState &state);
373 
374 private:
375   void attribute(int name, const char *value) override;
376   void endOfElement() override;
377 };
378 
FootnoteMarkElement(PAG1ParserState & state)379 FootnoteMarkElement::FootnoteMarkElement(PAG1ParserState &state)
380   : PAG1XMLEmptyContextBase(state)
381 {
382 }
383 
attribute(const int name,const char * const value)384 void FootnoteMarkElement::attribute(const int name, const char *const value)
385 {
386   if (name == (IWORKToken::NS_URI_SF | IWORKToken::mark))
387     m_state.m_footnoteState.m_mark = value;
388   else
389   {
390     ETONYEK_DEBUG_MSG(("FootnoteMarkElement::attribute[PAG1TextStorageElement]: find some unknown attribute\n"));
391   }
392 }
393 
endOfElement()394 void FootnoteMarkElement::endOfElement()
395 {
396   m_state.m_footnoteState.m_firstTextAfterMark = true;
397 }
398 
399 }
400 
401 namespace
402 {
403 
404 class FootnoteHelper
405 {
406 public:
407   explicit FootnoteHelper(PAG1ParserState &state);
408 
409   IWORKXMLContextPtr_t element(int name);
410   const char *text(const char *value);
411 
412 private:
413   PAG1ParserState &m_state;
414 };
415 
FootnoteHelper(PAG1ParserState & state)416 FootnoteHelper::FootnoteHelper(PAG1ParserState &state)
417   : m_state(state)
418 {
419 }
420 
element(const int name)421 IWORKXMLContextPtr_t FootnoteHelper::element(const int name)
422 {
423   switch (name)
424   {
425   case IWORKToken::NS_URI_SF | IWORKToken::footnote :
426     return std::make_shared<FootnoteElement>(m_state);
427   case IWORKToken::NS_URI_SF | IWORKToken::footnotebr :
428     return std::make_shared<FootnotebrElement>(m_state);
429   case IWORKToken::NS_URI_SF | IWORKToken::footnote_mark :
430     return std::make_shared<FootnoteMarkElement>(m_state);
431   default:
432     break;
433   }
434 
435   return IWORKXMLContextPtr_t();
436 }
437 
text(const char * const value)438 const char *FootnoteHelper::text(const char *const value)
439 {
440   if (m_state.m_footnoteState.m_firstTextAfterMark && value && (value[0] == ' '))
441   {
442     m_state.m_footnoteState.m_firstTextAfterMark = false;
443     return value + 1;
444   }
445   return value;
446 }
447 
448 }
449 
450 namespace
451 {
452 
453 class SpanElement : public PAG1XMLContextBase<IWORKSpanElement>
454 {
455 public:
456   explicit SpanElement(PAG1ParserState &state);
457 
458 private:
459   IWORKXMLContextPtr_t element(int name) override;
460   void text(const char *value) override;
461 
462 private:
463   FootnoteHelper m_footnoteHelper;
464 };
465 
SpanElement(PAG1ParserState & state)466 SpanElement::SpanElement(PAG1ParserState &state)
467   : PAG1XMLContextBase<IWORKSpanElement>(state)
468   , m_footnoteHelper(state)
469 {
470 }
471 
element(const int name)472 IWORKXMLContextPtr_t SpanElement::element(const int name)
473 {
474   const IWORKXMLContextPtr_t context = m_footnoteHelper.element(name);
475   if (bool(context))
476     return context;
477   if (name==(IWORKToken::NS_URI_SF | IWORKToken::attachment_ref))
478     return std::make_shared<AttachmentRef>(getState());
479   return IWORKSpanElement::element(name);
480 }
481 
text(const char * value)482 void SpanElement::text(const char *value)
483 {
484   PAG1XMLContextBase<IWORKSpanElement>::text(m_footnoteHelper.text(value));
485 }
486 
487 }
488 
489 namespace
490 {
491 
492 class LinkElement : public PAG1XMLContextBase<IWORKLinkElement>
493 {
494 public:
495   explicit LinkElement(PAG1ParserState &state);
496 
497 private:
498   IWORKXMLContextPtr_t element(int name) override;
499   void text(const char *value) override;
500 
501 private:
502   FootnoteHelper m_footnoteHelper;
503 };
504 
LinkElement(PAG1ParserState & state)505 LinkElement::LinkElement(PAG1ParserState &state)
506   : PAG1XMLContextBase<IWORKLinkElement>(state)
507   , m_footnoteHelper(state)
508 {
509 }
510 
element(const int name)511 IWORKXMLContextPtr_t LinkElement::element(const int name)
512 {
513   if (name == (IWORKToken::NS_URI_SF | IWORKToken::span))
514     return std::make_shared<SpanElement>(m_state);
515   const IWORKXMLContextPtr_t context = m_footnoteHelper.element(name);
516   if (bool(context))
517     return context;
518   return IWORKLinkElement::element(name);
519 }
520 
text(const char * value)521 void LinkElement::text(const char *value)
522 {
523   PAG1XMLContextBase<IWORKLinkElement>::text(m_footnoteHelper.text(value));
524 }
525 
526 }
527 
528 namespace
529 {
530 
531 class PElement : public PAG1XMLContextBase<IWORKPElement>
532 {
533 public:
534   explicit PElement(PAG1ParserState &state);
535 
536 private:
537   IWORKXMLContextPtr_t element(int name) override;
538   void text(const char *value) override;
539   void endOfElement() override;
540 
541 private:
542   FootnoteHelper m_footnoteHelper;
543 };
544 
PElement(PAG1ParserState & state)545 PElement::PElement(PAG1ParserState &state)
546   : PAG1XMLContextBase<IWORKPElement>(state)
547   , m_footnoteHelper(state)
548 {
549 }
550 
element(const int name)551 IWORKXMLContextPtr_t PElement::element(const int name)
552 {
553   ensureOpened();
554 
555   switch (name)
556   {
557   case IWORKToken::NS_URI_SF | IWORKToken::attachment_ref :
558     return std::make_shared<AttachmentRef>(getState());
559   case IWORKToken::NS_URI_SF | IWORKToken::link :
560     return std::make_shared<LinkElement>(getState());
561   case IWORKToken::NS_URI_SF | IWORKToken::span :
562     return std::make_shared<SpanElement>(getState());
563   case IWORKToken::NS_URI_SF | IWORKToken::annotation_field :
564     return std::make_shared<PAG1AnnotationElement>(getState(),*this);
565   case IWORKToken::NS_URI_SF | IWORKToken::annotation_field_ref :
566     return std::make_shared<PAG1AnnotationElement>(getState(),*this,true);
567   default:
568     break;
569   }
570 
571   const IWORKXMLContextPtr_t context = m_footnoteHelper.element(name);
572   if (bool(context))
573     return context;
574 
575   return IWORKPElement::element(name);
576 }
577 
text(const char * value)578 void PElement::text(const char *value)
579 {
580   PAG1XMLContextBase<IWORKPElement>::text(m_footnoteHelper.text(value));
581 }
582 
endOfElement()583 void PElement::endOfElement()
584 {
585   IWORKPElement::endOfElement();
586 
587   if (getState().m_footnoteState.m_pending)
588   {
589     PAGFootnoteState &fs = getState().m_footnoteState;
590     const bool firstFootnote = fs.m_footnotes.empty();
591     fs.m_footnotes.push_back(IWORKOutputElements());
592     if (firstFootnote) // We can init. insertion iterator now
593       fs.m_nextFootnote = fs.m_footnotes.begin();
594     librevenge::RVNGPropertyList props;
595     if (!fs.m_mark.empty())
596       props.insert("text:label", fs.m_mark.c_str());
597     if (getCollector().getFootnoteKind() == PAG_FOOTNOTE_KIND_FOOTNOTE)
598       fs.m_footnotes.back().addOpenFootnote(props);
599     else
600       fs.m_footnotes.back().addOpenEndnote(props);
601     getState().m_currentText->draw(fs.m_footnotes.back());
602     // prepare for possible next footnote
603     // TODO: introduce IN_FOOTNOTES state and move this to startOfElement
604     getState().m_currentText = getCollector().createText(getState().m_langManager, false, false);
605 
606     if (getCollector().getFootnoteKind() == PAG_FOOTNOTE_KIND_FOOTNOTE)
607       fs.m_footnotes.back().addCloseFootnote();
608     else
609       fs.m_footnotes.back().addCloseEndnote();
610 
611     fs.m_pending = false;
612     fs.m_firstTextAfterMark = false;
613     fs.m_mark.clear();
614   }
615 }
616 
617 }
618 
619 namespace
620 {
621 
622 class LayoutElement : public PAG1XMLContextBase<IWORKLayoutElement>
623 {
624 public:
625   explicit LayoutElement(PAG1ParserState &state);
626 
627 private:
628   IWORKXMLContextPtr_t element(int name) override;
629 };
630 
LayoutElement(PAG1ParserState & state)631 LayoutElement::LayoutElement(PAG1ParserState &state)
632   : PAG1XMLContextBase<IWORKLayoutElement>(state)
633 {
634 }
635 
element(const int name)636 IWORKXMLContextPtr_t LayoutElement::element(const int name)
637 {
638   if (!m_opened)
639     open();
640 
641   if (name == (IWORKToken::NS_URI_SF | IWORKToken::p))
642     return std::make_shared<PElement>(getState());
643 
644   return IWORKLayoutElement::element(name);
645 }
646 
647 }
648 
649 namespace
650 {
651 
652 class SectionElement : public PAG1XMLElementContextBase
653 {
654 public:
655   explicit SectionElement(PAG1ParserState &state);
656 
657 private:
658   void open();
659 
660   void startOfElement() override;
661   void attribute(int name, const char *value) override;
662   IWORKXMLContextPtr_t element(int name) override;
663   void endOfElement() override;
664 
665 private:
666   bool m_opened;
667   optional<string> m_style;
668 };
669 
SectionElement(PAG1ParserState & state)670 SectionElement::SectionElement(PAG1ParserState &state)
671   : PAG1XMLElementContextBase(state)
672   , m_opened(false)
673   , m_style()
674 {
675 }
676 
open()677 void SectionElement::open()
678 {
679   assert(!m_opened);
680 
681   if (isCollector())
682     getCollector().openSection(get_optional_value_or(m_style, ""));
683 
684   m_opened = true;
685 }
686 
startOfElement()687 void SectionElement::startOfElement()
688 {
689   if (isCollector())
690   {
691     // This should not happen in normal files, but better be safe than sorry
692     if (bool(getState().m_currentText) && !getState().m_currentText->empty())
693     {
694       getCollector().collectText(getState().m_currentText);
695       getState().m_currentText = getCollector().createText(getState().m_langManager);
696       getCollector().collectTextBody();
697     }
698   }
699 }
700 
attribute(const int name,const char * const value)701 void SectionElement::attribute(const int name, const char *const value)
702 {
703   if (name == (IWORKToken::NS_URI_SF | IWORKToken::style))
704     m_style = value;
705   else
706     PAG1XMLElementContextBase::attribute(name, value);
707 }
708 
element(const int name)709 IWORKXMLContextPtr_t SectionElement::element(const int name)
710 {
711   if (!m_opened)
712     open();
713 
714   if ((IWORKToken::NS_URI_SF | IWORKToken::layout) == name)
715     return std::make_shared<LayoutElement>(getState());
716 
717   return IWORKXMLContextPtr_t();
718 }
719 
endOfElement()720 void SectionElement::endOfElement()
721 {
722   if (isCollector())
723   {
724     if (!m_opened)
725       open();
726     getCollector().collectText(getState().m_currentText);
727     // In case there's non-section text following. Again, this should not happen in normal files.
728     getState().m_currentText = getCollector().createText(getState().m_langManager);
729     getCollector().closeSection();
730   }
731 }
732 
733 }
734 
735 namespace
736 {
737 
738 class ContainerHintElement : public PAG1XMLEmptyContextBase
739 {
740 public:
741   ContainerHintElement(PAG1ParserState &state, ContainerFrame &containerFrame);
742 
743 private:
744   void attribute(int name, const char *value) override;
745 
746 private:
747   ContainerFrame &m_containerFrame;
748 };
749 
ContainerHintElement(PAG1ParserState & state,ContainerFrame & containerFrame)750 ContainerHintElement::ContainerHintElement(PAG1ParserState &state, ContainerFrame &containerFrame)
751   : PAG1XMLEmptyContextBase(state)
752   , m_containerFrame(containerFrame)
753 {
754 }
755 
attribute(const int name,const char * const value)756 void ContainerHintElement::attribute(const int name, const char *const value)
757 {
758   switch (name)
759   {
760   case IWORKToken::NS_URI_SF | IWORKToken::frame_h :
761     m_containerFrame.m_h = double_cast(value);
762     break;
763   case IWORKToken::NS_URI_SF | IWORKToken::frame_w :
764     m_containerFrame.m_w = double_cast(value);
765     break;
766   case IWORKToken::NS_URI_SF | IWORKToken::frame_x :
767     m_containerFrame.m_x = double_cast(value);
768     break;
769   case IWORKToken::NS_URI_SF | IWORKToken::frame_y :
770     m_containerFrame.m_y = double_cast(value);
771     break;
772   // also page-index, cindex, sindex, lindex, anchor-loc, nlabel=true/false
773   default:
774     break;
775   }
776 }
777 
778 }
779 
780 namespace
781 {
782 
783 class TextBodyElement : public PAG1XMLContextBase<IWORKTextBodyElement>
784 {
785 public:
786   explicit TextBodyElement(PAG1ParserState &state);
787 
788 private:
789   IWORKXMLContextPtr_t element(int name) override;
790 
791 private:
792   ContainerFrame m_containerFrame;
793 };
794 
TextBodyElement(PAG1ParserState & state)795 TextBodyElement::TextBodyElement(PAG1ParserState &state)
796   : PAG1XMLContextBase<IWORKTextBodyElement>(state)
797   , m_containerFrame()
798 {
799 }
800 
element(const int name)801 IWORKXMLContextPtr_t TextBodyElement::element(const int name)
802 {
803   switch (name)
804   {
805   case IWORKToken::NS_URI_SF | IWORKToken::container_hint :
806     return std::make_shared<ContainerHintElement>(getState(), m_containerFrame);
807   case IWORKToken::NS_URI_SF | IWORKToken::p : // for footnotes
808     return std::make_shared<PElement>(getState());
809   case IWORKToken::NS_URI_SF | IWORKToken::section :
810     return std::make_shared<SectionElement>(getState());
811   default:
812     break;
813   }
814 
815   return IWORKTextBodyElement::element(name);
816 }
817 
818 }
819 
PAG1TextStorageElement(PAG1ParserState & state,PAGTextStorageKind kind)820 PAG1TextStorageElement::PAG1TextStorageElement(PAG1ParserState &state, PAGTextStorageKind kind)
821   : PAG1XMLContextBase<IWORKTextStorageElement>(state)
822   , m_kind(kind)
823   , m_textOpened(false)
824 {
825   if (m_kind==PAG_TEXTSTORAGE_KIND_TEXTBOX)
826   {
827     m_textOpened=true;
828     if (!bool(getState().m_currentText))
829     {
830       ETONYEK_DEBUG_MSG(("PAG1TextStorageElement::PAG1TextStorageElement: called in textbox without current tetx\n"));
831     }
832   }
833 }
834 
PAG1TextStorageElement(PAG1ParserState & state,IWORKStylesheetPtr_t & sheetmap,PAGTextStorageKind kind)835 PAG1TextStorageElement::PAG1TextStorageElement(PAG1ParserState &state, IWORKStylesheetPtr_t &sheetmap, PAGTextStorageKind kind)
836   : PAG1XMLContextBase<IWORKTextStorageElement>(state)
837   , m_kind(kind)
838   , m_textOpened(false)
839 {
840   PAG1XMLContextBase<IWORKTextStorageElement>::m_stylesheet=&sheetmap;
841   if (m_kind==PAG_TEXTSTORAGE_KIND_TEXTBOX)
842   {
843     m_textOpened=true;
844     if (!bool(getState().m_currentText))
845     {
846       ETONYEK_DEBUG_MSG(("PAG1TextStorageElement::PAG1TextStorageElement: called in textbox without current tetx\n"));
847     }
848   }
849 }
850 
element(const int name)851 IWORKXMLContextPtr_t PAG1TextStorageElement::element(const int name)
852 {
853   sendStylesheet();
854 
855   switch (name)
856   {
857   case IWORKToken::NS_URI_SF | IWORKToken::attachments :
858     return std::make_shared<AttachmentsElement>(getState());
859   case IWORKToken::NS_URI_SF | IWORKToken::footnotes :
860     return std::make_shared<PAG1FootnotesElement>(getState());
861   case IWORKToken::NS_URI_SF | IWORKToken::text_body :
862     if (!m_textOpened)
863     {
864       assert(!getState().m_currentText);
865       getState().m_currentText = getCollector().createText(getState().m_langManager, m_kind==PAG_TEXTSTORAGE_KIND_TEXTBOX);
866       m_textOpened = true;
867     }
868     return std::make_shared<TextBodyElement>(getState());
869   default:
870     break;
871   }
872 
873   return PAG1XMLContextBase<IWORKTextStorageElement>::element(name);
874 }
875 
endOfElement()876 void PAG1TextStorageElement::endOfElement()
877 {
878   if (isCollector() && m_textOpened && m_kind==PAG_TEXTSTORAGE_KIND_BASIC)
879   {
880     assert(getState().m_currentText);
881     if (bool(getState().m_currentText) && !getState().m_currentText->empty())
882       getCollector().collectText(getState().m_currentText);
883     getCollector().collectTextBody();
884   }
885   if (m_kind!=PAG_TEXTSTORAGE_KIND_TEXTBOX)
886     getState().m_currentText.reset();
887 
888   PAG1XMLContextBase<IWORKTextStorageElement>::endOfElement();
889 }
890 
891 }
892 
893 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
894