1 /******************************************************************************
2  *
3  *
4  *
5  *
6  * Copyright (C) 1997-2015 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby
10  * granted. No representations are made about the suitability of this software
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18 
19 #include <algorithm>
20 
21 #include "rtfdocvisitor.h"
22 #include "docparser.h"
23 #include "language.h"
24 #include "doxygen.h"
25 #include "outputgen.h"
26 #include "dot.h"
27 #include "msc.h"
28 #include "util.h"
29 #include "rtfstyle.h"
30 #include "message.h"
31 #include "parserintf.h"
32 #include "msc.h"
33 #include "dia.h"
34 #include "filedef.h"
35 #include "config.h"
36 #include "htmlentity.h"
37 #include "emoji.h"
38 #include "plantuml.h"
39 #include "fileinfo.h"
40 
41 //#define DBG_RTF(x) m_t << x
42 #define DBG_RTF(x) do {} while(0)
43 
align(DocHtmlCell * cell)44 static QCString align(DocHtmlCell *cell)
45 {
46   for (const auto &attr : cell->attribs())
47   {
48     if (attr.name.lower()=="align")
49     {
50       if (attr.value.lower()=="center")     return "\\qc ";
51       else if (attr.value.lower()=="right") return "\\qr ";
52       else return "";
53     }
54   }
55   return "";
56 }
57 
RTFDocVisitor(TextStream & t,CodeOutputInterface & ci,const QCString & langExt)58 RTFDocVisitor::RTFDocVisitor(TextStream &t,CodeOutputInterface &ci,
59                              const QCString &langExt)
60   : DocVisitor(DocVisitor_RTF), m_t(t), m_ci(ci), m_langExt(langExt)
61 {
62 }
63 
getStyle(const QCString & name)64 QCString RTFDocVisitor::getStyle(const QCString &name)
65 {
66   QCString n = name + QCString().setNum(indentLevel());
67   StyleData &sd = rtf_Style[n.str()];
68   return sd.reference();
69 }
70 
indentLevel() const71 int RTFDocVisitor::indentLevel() const
72 {
73   return std::min(m_indentLevel,maxIndentLevels-1);
74 }
75 
incIndentLevel()76 void RTFDocVisitor::incIndentLevel()
77 {
78   m_indentLevel++;
79   if (m_indentLevel>=maxIndentLevels)
80   {
81     err("Maximum indent level (%d) exceeded while generating RTF output!\n",maxIndentLevels-1);
82   }
83 }
84 
decIndentLevel()85 void RTFDocVisitor::decIndentLevel()
86 {
87   if (m_indentLevel>0) m_indentLevel--;
88 }
89 
90   //------------------------------------
91   // visitor functions for leaf nodes
92   //--------------------------------------
93 
visit(DocWord * w)94 void RTFDocVisitor::visit(DocWord *w)
95 {
96   if (m_hide) return;
97   DBG_RTF("{\\comment RTFDocVisitor::visit(DocWord)}\n");
98   filter(w->word());
99   m_lastIsPara=FALSE;
100 }
101 
visit(DocLinkedWord * w)102 void RTFDocVisitor::visit(DocLinkedWord *w)
103 {
104   if (m_hide) return;
105   DBG_RTF("{\\comment RTFDocVisitor::visit(DocLinkedWord)}\n");
106   startLink(w->ref(),w->file(),w->anchor());
107   filter(w->word());
108   endLink(w->ref());
109   m_lastIsPara=FALSE;
110 }
111 
visit(DocWhiteSpace * w)112 void RTFDocVisitor::visit(DocWhiteSpace *w)
113 {
114   if (m_hide) return;
115   DBG_RTF("{\\comment RTFDocVisitor::visit(DocWhiteSpace)}\n");
116   if (m_insidePre)
117   {
118     m_t << w->chars();
119   }
120   else
121   {
122     m_t << " ";
123   }
124   m_lastIsPara=FALSE;
125 }
126 
visit(DocSymbol * s)127 void RTFDocVisitor::visit(DocSymbol *s)
128 {
129   if (m_hide) return;
130   DBG_RTF("{\\comment RTFDocVisitor::visit(DocSymbol)}\n");
131   const char *res = HtmlEntityMapper::instance()->rtf(s->symbol());
132   if (res)
133   {
134     m_t << res;
135   }
136   else
137   {
138     err("RTF: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
139   }
140   m_lastIsPara=FALSE;
141 }
142 
visit(DocEmoji * s)143 void RTFDocVisitor::visit(DocEmoji *s)
144 {
145   if (m_hide) return;
146   DBG_RTF("{\\comment RTFDocVisitor::visit(DocEmoji)}\n");
147   const char *res = EmojiEntityMapper::instance()->unicode(s->index());
148   if (res)
149   {
150     const char *p = res;
151     int val = 0;
152     int val1 = 0;
153     while (*p)
154     {
155       switch(*p)
156       {
157         case '&': case '#': case 'x':
158           break;
159         case ';':
160 	  val1 = val;
161 	  val = 0xd800 + ( ( val1 - 0x10000 ) & 0xffc00 ) / 0x400 - 0x10000;
162           m_t << "\\u" << val << "?";
163           val = 0xdC00 + ( ( val1 - 0x10000 ) & 0x3ff ) - 0x10000 ;
164           m_t << "\\u" << val << "?";
165           val = 0;
166           break;
167         case '0': case '1': case '2': case '3': case '4':
168         case '5': case '6': case '7': case '8': case '9':
169           val = val * 16 + *p - '0';
170           break;
171         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
172           val = val * 16 + *p - 'a' + 10;
173           break;
174       }
175       p++;
176     }
177   }
178   else
179   {
180     m_t << s->name();
181   }
182   m_lastIsPara=FALSE;
183 }
184 
visit(DocURL * u)185 void RTFDocVisitor::visit(DocURL *u)
186 {
187   if (m_hide) return;
188   DBG_RTF("{\\comment RTFDocVisitor::visit(DocURL)}\n");
189   if (Config_getBool(RTF_HYPERLINKS))
190   {
191     m_t << "{\\field "
192              "{\\*\\fldinst "
193                "{ HYPERLINK \"";
194     if (u->isEmail()) m_t << "mailto:";
195     m_t << u->url();
196     m_t <<  "\" }"
197                "{}";
198     m_t <<   "}"
199              "{\\fldrslt "
200                "{\\cs37\\ul\\cf2 ";
201     filter(u->url());
202     m_t <<     "}"
203              "}"
204            "}\n";
205   }
206   else
207   {
208     m_t << "{\\f2 ";
209     filter(u->url());
210     m_t << "}";
211   }
212   m_lastIsPara=FALSE;
213 }
214 
visit(DocLineBreak *)215 void RTFDocVisitor::visit(DocLineBreak *)
216 {
217   if (m_hide) return;
218   DBG_RTF("{\\comment RTFDocVisitor::visit(DocLineBreak)}\n");
219   m_t << "\\par\n";
220   m_lastIsPara=TRUE;
221 }
222 
visit(DocHorRuler *)223 void RTFDocVisitor::visit(DocHorRuler *)
224 {
225   if (m_hide) return;
226   DBG_RTF("{\\comment RTFDocVisitor::visit(DocHorRuler)}\n");
227   m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw5\\brsp20 \\adjustright \\par}\n";
228   m_lastIsPara=TRUE;
229 }
230 
visit(DocStyleChange * s)231 void RTFDocVisitor::visit(DocStyleChange *s)
232 {
233   if (m_hide) return;
234   m_lastIsPara=FALSE;
235   DBG_RTF("{\\comment RTFDocVisitor::visit(DocStyleChange)}\n");
236   switch (s->style())
237   {
238     case DocStyleChange::Bold:
239       if (s->enable()) m_t << "{\\b ";      else m_t << "} ";
240       break;
241     case DocStyleChange::S:
242     case DocStyleChange::Strike:
243     case DocStyleChange::Del:
244       if (s->enable()) m_t << "{\\strike ";      else m_t << "} ";
245       break;
246     case DocStyleChange::Underline:
247     case DocStyleChange::Ins:
248       if (s->enable()) m_t << "{\\ul ";      else m_t << "} ";
249       break;
250     case DocStyleChange::Italic:
251       if (s->enable()) m_t << "{\\i ";     else m_t << "} ";
252       break;
253     case DocStyleChange::Code:
254       if (s->enable()) m_t << "{\\f2 ";   else m_t << "} ";
255       break;
256     case DocStyleChange::Subscript:
257       if (s->enable()) m_t << "{\\sub ";    else m_t << "} ";
258       break;
259     case DocStyleChange::Superscript:
260       if (s->enable()) m_t << "{\\super ";    else m_t << "} ";
261       break;
262     case DocStyleChange::Center:
263       if (s->enable()) m_t << "{\\qc "; else m_t << "} ";
264       break;
265     case DocStyleChange::Small:
266       if (s->enable()) m_t << "{\\sub ";  else m_t << "} ";
267       break;
268     case DocStyleChange::Cite:
269       if (s->enable()) m_t << "{\\i ";     else m_t << "} ";
270       break;
271     case DocStyleChange::Preformatted:
272       if (s->enable())
273       {
274         m_t << "{\n";
275         m_t << "\\par\n";
276         m_t << rtf_Style_Reset << getStyle("CodeExample");
277         m_insidePre=TRUE;
278       }
279       else
280       {
281         m_insidePre=FALSE;
282         m_t << "\\par";
283         m_t << "}\n";
284       }
285       m_lastIsPara=TRUE;
286       break;
287     case DocStyleChange::Div:  /* HTML only */ break;
288     case DocStyleChange::Span: /* HTML only */ break;
289     case DocStyleChange::Details: /* emulation of the <details> tag */
290       if (s->enable())
291       {
292         m_t << "{\n";
293         m_t << "\\par\n";
294       }
295       else
296       {
297         m_t << "\\par";
298         m_t << "}\n";
299       }
300       m_lastIsPara=TRUE;
301       break;
302     case DocStyleChange::Summary: /* emulation of the <summary> tag inside a <details> tag */
303       if (s->enable()) m_t << "{\\b ";      else m_t << "} ";
304       break;
305   }
306 }
307 
visitCaption(RTFDocVisitor * parent,const DocNodeList & children)308 static void visitCaption(RTFDocVisitor *parent, const DocNodeList &children)
309 {
310   for (const auto &n : children) n->accept(parent);
311 }
312 
visit(DocVerbatim * s)313 void RTFDocVisitor::visit(DocVerbatim *s)
314 {
315   if (m_hide) return;
316   DBG_RTF("{\\comment RTFDocVisitor::visit(DocVerbatim)}\n");
317   QCString lang = m_langExt;
318   if (!s->language().isEmpty()) // explicit language setting
319   {
320     lang = s->language();
321   }
322   SrcLangExt langExt = getLanguageFromCodeLang(lang);
323   switch(s->type())
324   {
325     case DocVerbatim::Code:
326       m_t << "{\n";
327       m_t << "\\par\n";
328       m_t << rtf_Style_Reset << getStyle("CodeExample");
329       getCodeParser(lang).parseCode(m_ci,s->context(),s->text(),langExt,
330                                     s->isExample(),s->exampleFile());
331       //m_t << "\\par\n";
332       m_t << "}\n";
333       break;
334     case DocVerbatim::JavaDocLiteral:
335       filter(s->text(),TRUE);
336       break;
337     case DocVerbatim::JavaDocCode:
338       m_t << "{\n";
339       m_t << "{\\f2 ";
340       filter(s->text(),TRUE);
341       m_t << "}";
342       m_t << "}\n";
343       break;
344     case DocVerbatim::Verbatim:
345       m_t << "{\n";
346       m_t << "\\par\n";
347       m_t << rtf_Style_Reset << getStyle("CodeExample");
348       filter(s->text(),TRUE);
349       //m_t << "\\par\n";
350       m_t << "}\n";
351       break;
352     case DocVerbatim::RtfOnly:
353       m_t << s->text();
354       break;
355     case DocVerbatim::HtmlOnly:
356     case DocVerbatim::LatexOnly:
357     case DocVerbatim::XmlOnly:
358     case DocVerbatim::ManOnly:
359     case DocVerbatim::DocbookOnly:
360       /* nothing */
361       break;
362     case DocVerbatim::Dot:
363       {
364         static int dotindex = 1;
365         QCString fileName(4096);
366 
367         fileName.sprintf("%s%d%s",
368             qPrint(Config_getString(RTF_OUTPUT)+"/inline_dotgraph_"),
369             dotindex++,
370             ".dot"
371            );
372         std::ofstream file(fileName.str(),std::ofstream::out | std::ofstream::binary);
373         if (!file.is_open())
374         {
375           err("Could not open file %s for writing\n",qPrint(fileName));
376         }
377         else
378         {
379           QCString stext = s->text();
380           file.write( stext.data(), stext.length() );
381           file.close();
382         }
383 
384         writeDotFile(fileName, s->hasCaption(), s->srcFile(), s->srcLine());
385         visitCaption(this, s->children());
386         includePicturePostRTF(true, s->hasCaption());
387 
388         if (Config_getBool(DOT_CLEANUP)) Dir().remove(fileName.str());
389       }
390       break;
391     case DocVerbatim::Msc:
392       {
393         static int mscindex = 1;
394         QCString baseName(4096);
395 
396         baseName.sprintf("%s%d%s",
397             qPrint(Config_getString(RTF_OUTPUT)+"/inline_mscgraph_"),
398             mscindex++,
399             ".msc"
400            );
401         std::ofstream file(baseName.str(),std::ofstream::out | std::ofstream::binary);
402         if (!file.is_open())
403         {
404           err("Could not open file %s for writing\n",qPrint(baseName));
405         }
406         QCString text = "msc {";
407         text+=s->text();
408         text+="}";
409         file.write( text.data(), text.length() );
410         file.close();
411 
412         writeMscFile(baseName, s->hasCaption(), s->srcFile(), s->srcLine());
413         visitCaption(this, s->children());
414         includePicturePostRTF(true, s->hasCaption());
415 
416         if (Config_getBool(DOT_CLEANUP)) Dir().remove(baseName.str());
417       }
418       break;
419     case DocVerbatim::PlantUML:
420       {
421         static QCString rtfOutput = Config_getString(RTF_OUTPUT);
422         QCString baseName = PlantumlManager::instance().writePlantUMLSource(
423                        rtfOutput,s->exampleFile(),s->text(),PlantumlManager::PUML_BITMAP,
424                        s->engine(),s->srcFile(),s->srcLine());
425 
426         writePlantUMLFile(baseName, s->hasCaption());
427         visitCaption(this, s->children());
428         includePicturePostRTF(true, s->hasCaption());
429       }
430       break;
431   }
432   m_lastIsPara=FALSE;
433 }
434 
visit(DocAnchor * anc)435 void RTFDocVisitor::visit(DocAnchor *anc)
436 {
437   if (m_hide) return;
438   DBG_RTF("{\\comment RTFDocVisitor::visit(DocAnchor)}\n");
439   QCString anchor;
440   if (!anc->file().isEmpty())
441   {
442     anchor+=stripPath(anc->file());
443   }
444   if (!anc->file().isEmpty() && !anc->anchor().isEmpty())
445   {
446     anchor+="_";
447   }
448   if (!anc->anchor().isEmpty())
449   {
450     anchor+=anc->anchor();
451   }
452   m_t << "{\\bkmkstart " << rtfFormatBmkStr(anchor) << "}\n";
453   m_t << "{\\bkmkend " << rtfFormatBmkStr(anchor) << "}\n";
454   m_lastIsPara=FALSE;
455 }
456 
visit(DocInclude * inc)457 void RTFDocVisitor::visit(DocInclude *inc)
458 {
459   if (m_hide) return;
460   SrcLangExt langExt = getLanguageFromFileName(inc->extension());
461   DBG_RTF("{\\comment RTFDocVisitor::visit(DocInclude)}\n");
462   switch(inc->type())
463   {
464      case DocInclude::IncWithLines:
465       {
466          m_t << "{\n";
467          m_t << "\\par\n";
468          m_t << rtf_Style_Reset << getStyle("CodeExample");
469          FileInfo cfi( inc->file().str() );
470          FileDef *fd = createFileDef( cfi.dirPath(), cfi.fileName() );
471          getCodeParser(inc->extension()).parseCode(m_ci,inc->context(),
472                                            inc->text(),
473                                            langExt,
474                                            inc->isExample(),
475                                            inc->exampleFile(),
476                                            fd,   // fileDef,
477                                            -1,    // start line
478                                            -1,    // end line
479                                            FALSE, // inline fragment
480                                            0,     // memberDef
481                                            TRUE   // show line numbers
482 					   );
483          delete fd;
484          m_t << "\\par";
485          m_t << "}\n";
486       }
487       break;
488     case DocInclude::Include:
489       m_t << "{\n";
490       m_t << "\\par\n";
491       m_t << rtf_Style_Reset << getStyle("CodeExample");
492       getCodeParser(inc->extension()).parseCode(m_ci,inc->context(),
493                                         inc->text(),langExt,inc->isExample(),
494                                         inc->exampleFile(),
495                                         0,     // fileDef
496                                         -1,    // startLine
497                                         -1,    // endLine
498                                         TRUE,  // inlineFragment
499                                         0,     // memberDef
500                                         FALSE  // show line numbers
501 				       );
502       m_t << "\\par";
503       m_t << "}\n";
504       break;
505     case DocInclude::DontInclude:
506     case DocInclude::DontIncWithLines:
507     case DocInclude::HtmlInclude:
508     case DocInclude::LatexInclude:
509     case DocInclude::ManInclude:
510     case DocInclude::XmlInclude:
511     case DocInclude::DocbookInclude:
512       break;
513     case DocInclude::RtfInclude:
514       m_t << inc->text();
515       break;
516     case DocInclude::VerbInclude:
517       m_t << "{\n";
518       m_t << "\\par\n";
519       m_t << rtf_Style_Reset << getStyle("CodeExample");
520       filter(inc->text());
521       m_t << "\\par";
522       m_t << "}\n";
523       break;
524     case DocInclude::Snippet:
525       m_t << "{\n";
526       if (!m_lastIsPara) m_t << "\\par\n";
527       m_t << rtf_Style_Reset << getStyle("CodeExample");
528       getCodeParser(inc->extension()).parseCode(m_ci,
529                                         inc->context(),
530                                         extractBlock(inc->text(),inc->blockId()),
531                                         langExt,
532                                         inc->isExample(),
533                                         inc->exampleFile()
534                                        );
535       m_t << "}";
536       break;
537     case DocInclude::SnipWithLines:
538       {
539          FileInfo cfi( inc->file().str() );
540          FileDef *fd = createFileDef( cfi.dirPath(), cfi.fileName() );
541          m_t << "{\n";
542          if (!m_lastIsPara) m_t << "\\par\n";
543          m_t << rtf_Style_Reset << getStyle("CodeExample");
544          getCodeParser(inc->extension()).parseCode(m_ci,
545                                            inc->context(),
546                                            extractBlock(inc->text(),inc->blockId()),
547                                            langExt,
548                                            inc->isExample(),
549                                            inc->exampleFile(),
550                                            fd,
551                                            lineBlock(inc->text(),inc->blockId()),
552                                            -1,    // endLine
553                                            FALSE, // inlineFragment
554                                            0,     // memberDef
555                                            TRUE   // show line number
556                                           );
557          delete fd;
558          m_t << "}";
559       }
560       break;
561     case DocInclude::SnippetDoc:
562     case DocInclude::IncludeDoc:
563       err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
564           "Please create a bug report\n",__FILE__);
565       break;
566   }
567   m_lastIsPara=TRUE;
568 }
569 
visit(DocIncOperator * op)570 void RTFDocVisitor::visit(DocIncOperator *op)
571 {
572   //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
573   //    op->type(),op->isFirst(),op->isLast(),qPrint(op->text()));
574   DBG_RTF("{\\comment RTFDocVisitor::visit(DocIncOperator)}\n");
575   QCString locLangExt = getFileNameExtension(op->includeFileName());
576   if (locLangExt.isEmpty()) locLangExt = m_langExt;
577   SrcLangExt langExt = getLanguageFromFileName(locLangExt);
578   if (op->isFirst())
579   {
580     if (!m_hide)
581     {
582       m_t << "{\n";
583       m_t << "\\par\n";
584       m_t << rtf_Style_Reset << getStyle("CodeExample");
585     }
586     pushHidden(m_hide);
587     m_hide = TRUE;
588   }
589   if (op->type()!=DocIncOperator::Skip)
590   {
591     m_hide = popHidden();
592     if (!m_hide)
593     {
594       FileDef *fd = 0;
595       if (!op->includeFileName().isEmpty())
596       {
597         FileInfo cfi( op->includeFileName().str() );
598         fd = createFileDef( cfi.dirPath(), cfi.fileName() );
599       }
600 
601       getCodeParser(locLangExt).parseCode(m_ci,op->context(),op->text(),langExt,
602                                         op->isExample(),op->exampleFile(),
603                                         fd,     // fileDef
604                                         op->line(),    // startLine
605                                         -1,    // endLine
606                                         FALSE, // inline fragment
607                                         0,     // memberDef
608                                         op->showLineNo()  // show line numbers
609                                        );
610       if (fd) delete fd;
611     }
612     pushHidden(m_hide);
613     m_hide=TRUE;
614   }
615   if (op->isLast())
616   {
617     m_hide = popHidden();
618     if (!m_hide)
619     {
620       m_t << "\\par";
621       m_t << "}\n";
622     }
623     m_lastIsPara=TRUE;
624   }
625   else
626   {
627     if (!m_hide) m_t << "\n";
628     m_lastIsPara=FALSE;
629   }
630 }
631 
visit(DocFormula * f)632 void RTFDocVisitor::visit(DocFormula *f)
633 {
634   if (m_hide) return;
635   DBG_RTF("{\\comment RTFDocVisitor::visit(DocFormula)}\n");
636   bool bDisplay = !f->isInline();
637   if (bDisplay)
638   {
639     m_t << "\\par";
640     m_t << "{";
641     m_t << "\\pard\\plain";
642     m_t << "\\pard";
643     m_t << "\\qc";
644   }
645   m_t << "{ \\field\\flddirty {\\*\\fldinst  INCLUDEPICTURE \"" << f->relPath() << f->name() << ".png\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt Image}}";
646   if (bDisplay)
647   {
648     m_t << "\\par}";
649   }
650   m_lastIsPara=FALSE;
651 }
652 
visit(DocIndexEntry * i)653 void RTFDocVisitor::visit(DocIndexEntry *i)
654 {
655   if (m_hide) return;
656   DBG_RTF("{\\comment RTFDocVisitor::visit(DocIndexEntry)}\n");
657   m_t << "{\\xe \\v " << i->entry() << "}\n";
658   m_lastIsPara=FALSE;
659 }
660 
visit(DocSimpleSectSep *)661 void RTFDocVisitor::visit(DocSimpleSectSep *)
662 {
663 }
664 
visit(DocCite * cite)665 void RTFDocVisitor::visit(DocCite *cite)
666 {
667   if (m_hide) return;
668   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocCite)}\n");
669   if (!cite->file().isEmpty())
670   {
671     startLink(cite->ref(),cite->file(),cite->anchor());
672   }
673   else
674   {
675     m_t << "{\\b ";
676   }
677   filter(cite->text());
678   if (!cite->file().isEmpty())
679   {
680     endLink(cite->ref());
681   }
682   else
683   {
684     m_t << "}";
685   }
686 }
687 
688 
689 //--------------------------------------
690 // visitor functions for compound nodes
691 //--------------------------------------
692 
visitPre(DocAutoList * l)693 void RTFDocVisitor::visitPre(DocAutoList *l)
694 {
695   if (m_hide) return;
696   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocAutoList)}\n");
697   m_t << "{\n";
698   int level = indentLevel();
699   m_listItemInfo[level].isEnum = l->isEnumList();
700   m_listItemInfo[level].type   = '1';
701   m_listItemInfo[level].number = 1;
702   m_lastIsPara=FALSE;
703 }
704 
visitPost(DocAutoList *)705 void RTFDocVisitor::visitPost(DocAutoList *)
706 {
707   if (m_hide) return;
708   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocAutoList)}\n");
709   if (!m_lastIsPara) m_t << "\\par";
710   m_t << "}\n";
711   m_lastIsPara=TRUE;
712   if (indentLevel()==0) m_t << "\\par\n";
713 }
714 
visitPre(DocAutoListItem *)715 void RTFDocVisitor::visitPre(DocAutoListItem *)
716 {
717   if (m_hide) return;
718   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocAutoListItem)}\n");
719   if (!m_lastIsPara) m_t << "\\par\n";
720   m_t << rtf_Style_Reset;
721   int level = indentLevel();
722   if (m_listItemInfo[level].isEnum)
723   {
724     m_t << getStyle("ListEnum") << "\n";
725     m_t << m_listItemInfo[level].number << ".\\tab ";
726     m_listItemInfo[level].number++;
727   }
728   else
729   {
730     m_t << getStyle("ListBullet") << "\n";
731   }
732   incIndentLevel();
733   m_lastIsPara=FALSE;
734 }
735 
visitPost(DocAutoListItem *)736 void RTFDocVisitor::visitPost(DocAutoListItem *)
737 {
738   decIndentLevel();
739   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocAutoListItem)}\n");
740 }
741 
visitPre(DocPara *)742 void RTFDocVisitor::visitPre(DocPara *)
743 {
744   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocPara)}\n");
745 }
746 
visitPost(DocPara * p)747 void RTFDocVisitor::visitPost(DocPara *p)
748 {
749   if (m_hide) return;
750   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocPara)}\n");
751   if (!m_lastIsPara &&
752       !p->isLast() &&            // omit <p> for last paragraph
753       !(p->parent() &&           // and for parameters & sections
754         p->parent()->kind()==DocNode::Kind_ParamSect
755        )
756      )
757   {
758     m_t << "\\par\n";
759     m_lastIsPara=TRUE;
760   }
761 }
762 
visitPre(DocRoot * r)763 void RTFDocVisitor::visitPre(DocRoot *r)
764 {
765   if (m_hide) return;
766   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocRoot)}\n");
767   if (r->indent()) incIndentLevel();
768   m_t << "{" << rtf_Style["BodyText"].reference() << "\n";
769 }
770 
visitPost(DocRoot * r)771 void RTFDocVisitor::visitPost(DocRoot *r)
772 {
773   if (m_hide) return;
774   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocRoot)}\n");
775   if (!m_lastIsPara && !r->singleLine()) m_t << "\\par\n";
776   m_t << "}";
777   m_lastIsPara=TRUE;
778   if (r->indent()) decIndentLevel();
779 }
780 
visitPre(DocSimpleSect * s)781 void RTFDocVisitor::visitPre(DocSimpleSect *s)
782 {
783   if (m_hide) return;
784   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleSect)}\n");
785   if (!m_lastIsPara) m_t << "\\par\n";
786   m_t << "{"; // start desc
787   //m_t << "{\\b "; // start bold
788   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
789   switch(s->type())
790   {
791     case DocSimpleSect::See:
792       m_t << theTranslator->trSeeAlso(); break;
793     case DocSimpleSect::Return:
794       m_t << theTranslator->trReturns(); break;
795     case DocSimpleSect::Author:
796       m_t << theTranslator->trAuthor(TRUE,TRUE); break;
797     case DocSimpleSect::Authors:
798       m_t << theTranslator->trAuthor(TRUE,FALSE); break;
799     case DocSimpleSect::Version:
800       m_t << theTranslator->trVersion(); break;
801     case DocSimpleSect::Since:
802       m_t << theTranslator->trSince(); break;
803     case DocSimpleSect::Date:
804       m_t << theTranslator->trDate(); break;
805     case DocSimpleSect::Note:
806       m_t << theTranslator->trNote(); break;
807     case DocSimpleSect::Warning:
808       m_t << theTranslator->trWarning(); break;
809     case DocSimpleSect::Pre:
810       m_t << theTranslator->trPrecondition(); break;
811     case DocSimpleSect::Post:
812       m_t << theTranslator->trPostcondition(); break;
813     case DocSimpleSect::Copyright:
814       m_t << theTranslator->trCopyright(); break;
815     case DocSimpleSect::Invar:
816       m_t << theTranslator->trInvariant(); break;
817     case DocSimpleSect::Remark:
818       m_t << theTranslator->trRemarks(); break;
819     case DocSimpleSect::Attention:
820       m_t << theTranslator->trAttention(); break;
821     case DocSimpleSect::User: break;
822     case DocSimpleSect::Rcs: break;
823     case DocSimpleSect::Unknown:  break;
824   }
825 
826   // special case 1: user defined title
827   if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
828   {
829     m_t << "\\par";
830     m_t << "}"; // end bold
831     incIndentLevel();
832     m_t << rtf_Style_Reset << getStyle("DescContinue");
833     m_t << "{\\s17 \\sa60 \\sb30\n";
834   }
835   m_lastIsPara=FALSE;
836 }
837 
visitPost(DocSimpleSect * s)838 void RTFDocVisitor::visitPost(DocSimpleSect *s)
839 {
840   if (m_hide) return;
841   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleSect)}\n");
842   if (!m_lastIsPara) m_t << "\\par\n";
843   decIndentLevel();
844   if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) m_t << "}";
845   m_t << "}"; // end desc
846   m_lastIsPara=TRUE;
847 }
848 
visitPre(DocTitle *)849 void RTFDocVisitor::visitPre(DocTitle *)
850 {
851   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocTitle)}\n");
852 }
853 
visitPost(DocTitle *)854 void RTFDocVisitor::visitPost(DocTitle *)
855 {
856   if (m_hide) return;
857   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocTitle)}\n");
858   m_t << "\\par\n";
859   m_t << "}"; // end bold
860   incIndentLevel();
861   m_t << rtf_Style_Reset << getStyle("DescContinue");
862   m_lastIsPara=FALSE;
863 }
864 
visitPre(DocSimpleList *)865 void RTFDocVisitor::visitPre(DocSimpleList *)
866 {
867   if (m_hide) return;
868   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleSect)}\n");
869   m_t << "{\n";
870   m_listItemInfo[indentLevel()].isEnum = FALSE;
871   m_lastIsPara=FALSE;
872 }
873 
visitPost(DocSimpleList *)874 void RTFDocVisitor::visitPost(DocSimpleList *)
875 {
876   if (m_hide) return;
877   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleSect)}\n");
878   if (!m_lastIsPara) m_t << "\\par\n";
879   m_t << "}\n";
880   m_lastIsPara=TRUE;
881 }
882 
visitPre(DocSimpleListItem *)883 void RTFDocVisitor::visitPre(DocSimpleListItem *)
884 {
885   if (m_hide) return;
886   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleListItem)}\n");
887   m_t << "\\par" << rtf_Style_Reset << getStyle("ListBullet") << "\n";
888   m_lastIsPara=FALSE;
889   incIndentLevel();
890 }
891 
visitPost(DocSimpleListItem *)892 void RTFDocVisitor::visitPost(DocSimpleListItem *)
893 {
894   decIndentLevel();
895   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleListItem)}\n");
896 }
897 
visitPre(DocSection * s)898 void RTFDocVisitor::visitPre(DocSection *s)
899 {
900   if (m_hide) return;
901   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSection)}\n");
902   if (!m_lastIsPara) m_t << "\\par\n";
903   m_t << "{\\bkmkstart " << rtfFormatBmkStr(stripPath(s->file())+"_"+s->anchor()) << "}\n";
904   m_t << "{\\bkmkend " << rtfFormatBmkStr(stripPath(s->file())+"_"+s->anchor()) << "}\n";
905   m_t << "{{" // start section
906       << rtf_Style_Reset;
907   QCString heading;
908   int level = std::min(s->level()+1,4);
909   heading.sprintf("Heading%d",level);
910   // set style
911   m_t << rtf_Style[heading.str()].reference() << "\n";
912   // make table of contents entry
913   filter(s->title());
914   m_t << "\n\\par" << "}\n";
915   m_t << "{\\tc\\tcl" << level << " \\v ";
916   filter(s->title());
917   m_t << "}\n";
918   m_lastIsPara=TRUE;
919 }
920 
visitPost(DocSection *)921 void RTFDocVisitor::visitPost(DocSection *)
922 {
923   if (m_hide) return;
924   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSection)}\n");
925   m_t << "\\par}\n"; // end section
926   m_lastIsPara=TRUE;
927 }
928 
visitPre(DocHtmlList * l)929 void RTFDocVisitor::visitPre(DocHtmlList *l)
930 {
931   if (m_hide) return;
932   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlList)}\n");
933   m_t << "{\n";
934   int level = indentLevel();
935   m_listItemInfo[level].isEnum = l->type()==DocHtmlList::Ordered;
936   m_listItemInfo[level].number = 1;
937   m_listItemInfo[level].type   = '1';
938   for (const auto &opt : l->attribs())
939   {
940     if (opt.name=="type")
941     {
942       m_listItemInfo[level].type = opt.value[0];
943     }
944     if (opt.name=="start")
945     {
946       bool ok;
947       int val = opt.value.toInt(&ok);
948       if (ok) m_listItemInfo[level].number = val;
949     }
950   }
951   m_lastIsPara=FALSE;
952 }
953 
visitPost(DocHtmlList *)954 void RTFDocVisitor::visitPost(DocHtmlList *)
955 {
956   if (m_hide) return;
957   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlList)}\n");
958   m_t << "\\par" << "}\n";
959   m_lastIsPara=TRUE;
960 }
961 
visitPre(DocHtmlListItem * l)962 void RTFDocVisitor::visitPre(DocHtmlListItem *l)
963 {
964   if (m_hide) return;
965   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlListItem)}\n");
966   m_t << "\\par\n";
967   m_t << rtf_Style_Reset;
968   int level = indentLevel();
969   if (m_listItemInfo[level].isEnum)
970   {
971     for (const auto &opt : l->attribs())
972     {
973       if (opt.name=="value")
974       {
975         bool ok;
976         int val = opt.value.toInt(&ok);
977         if (ok) m_listItemInfo[level].number = val;
978       }
979     }
980     m_t << getStyle("ListEnum") << "\n";
981     switch (m_listItemInfo[level].type)
982     {
983       case '1':
984         m_t << m_listItemInfo[level].number;
985         break;
986       case 'a':
987         m_t << integerToAlpha(m_listItemInfo[level].number,false);
988         break;
989       case 'A':
990         m_t << integerToAlpha(m_listItemInfo[level].number);
991         break;
992       case 'i':
993         m_t << integerToRoman(m_listItemInfo[level].number,false);
994         break;
995       case 'I':
996         m_t << integerToRoman(m_listItemInfo[level].number);
997         break;
998       default:
999         m_t << m_listItemInfo[level].number;
1000         break;
1001     }
1002     m_t << ".\\tab ";
1003     m_listItemInfo[level].number++;
1004   }
1005   else
1006   {
1007     m_t << getStyle("ListBullet") << "\n";
1008   }
1009   incIndentLevel();
1010   m_lastIsPara=FALSE;
1011 }
1012 
visitPost(DocHtmlListItem *)1013 void RTFDocVisitor::visitPost(DocHtmlListItem *)
1014 {
1015   decIndentLevel();
1016   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlListItem)}\n");
1017 }
1018 
visitPre(DocHtmlDescList *)1019 void RTFDocVisitor::visitPre(DocHtmlDescList *)
1020 {
1021   if (m_hide) return;
1022   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescList)}\n");
1023   //m_t << "{\n";
1024   //m_t << rtf_Style_Reset << getStyle("ListContinue");
1025   //m_lastIsPara=FALSE;
1026 }
1027 
visitPost(DocHtmlDescList *)1028 void RTFDocVisitor::visitPost(DocHtmlDescList *)
1029 {
1030   if (m_hide) return;
1031   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescList)}\n");
1032   //m_t << "}\n";
1033   //m_t << "\\par\n";
1034   //m_lastIsPara=TRUE;
1035 }
1036 
visitPre(DocHtmlDescTitle *)1037 void RTFDocVisitor::visitPre(DocHtmlDescTitle *)
1038 {
1039   if (m_hide) return;
1040   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescTitle)}\n");
1041   //m_t << "\\par\n";
1042   //m_t << "{\\b ";
1043   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
1044   m_lastIsPara=FALSE;
1045 }
1046 
visitPost(DocHtmlDescTitle *)1047 void RTFDocVisitor::visitPost(DocHtmlDescTitle *)
1048 {
1049   if (m_hide) return;
1050   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescTitle)}\n");
1051   m_t << "\\par\n";
1052   m_t << "}\n";
1053   m_lastIsPara=TRUE;
1054 }
1055 
visitPre(DocHtmlDescData *)1056 void RTFDocVisitor::visitPre(DocHtmlDescData *)
1057 {
1058   if (m_hide) return;
1059   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescData)}\n");
1060   incIndentLevel();
1061   m_t << "{" << rtf_Style_Reset << getStyle("DescContinue");
1062 }
1063 
visitPost(DocHtmlDescData *)1064 void RTFDocVisitor::visitPost(DocHtmlDescData *)
1065 {
1066   if (m_hide) return;
1067   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescData)}\n");
1068   m_t << "\\par";
1069   m_t << "}\n";
1070   decIndentLevel();
1071   m_lastIsPara=TRUE;
1072 }
1073 
visitPre(DocHtmlTable * t)1074 void RTFDocVisitor::visitPre(DocHtmlTable *t)
1075 {
1076   if (m_hide) return;
1077   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlTable)}\n");
1078   if (!m_lastIsPara) m_t << "\\par\n";
1079   m_lastIsPara=TRUE;
1080   if (t->hasCaption())
1081   {
1082     DocHtmlCaption *c = t->caption();
1083     m_t << "\\pard \\qc \\b";
1084     if (!c->file().isEmpty())
1085     {
1086       m_t << "{\\bkmkstart " << rtfFormatBmkStr(stripPath(c->file())+"_"+c->anchor()) << "}\n";
1087       m_t << "{\\bkmkend " << rtfFormatBmkStr(stripPath(c->file())+"_"+c->anchor()) << "}\n";
1088     }
1089     m_t << "{Table \\field\\flddirty{\\*\\fldinst { SEQ Table \\\\*Arabic }}{\\fldrslt {\\noproof 1}} ";
1090   }
1091 }
1092 
visitPost(DocHtmlTable *)1093 void RTFDocVisitor::visitPost(DocHtmlTable *)
1094 {
1095   if (m_hide) return;
1096   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlTable)}\n");
1097   m_t << "\\pard\\plain\n";
1098   m_t << "\\par\n";
1099   m_lastIsPara=TRUE;
1100 }
1101 
visitPre(DocHtmlCaption *)1102 void RTFDocVisitor::visitPre(DocHtmlCaption *)
1103 {
1104   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlCaption)}\n");
1105   // start of caption is handled in the RTFDocVisitor::visitPre(DocHtmlTable *t)
1106 }
1107 
visitPost(DocHtmlCaption *)1108 void RTFDocVisitor::visitPost(DocHtmlCaption *)
1109 {
1110   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlCaption)}\n");
1111   m_t << "}\n\\par\n";
1112 }
1113 
visitPre(DocHtmlRow * r)1114 void RTFDocVisitor::visitPre(DocHtmlRow *r)
1115 {
1116   if (m_hide) return;
1117   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlRow)}\n");
1118   uint i,columnWidth=(uint)r->numCells()>0 ? rtf_pageWidth/(uint)r->numCells() : 10;
1119   m_t << "\\trowd \\trgaph108\\trleft-108"
1120          "\\trbrdrt\\brdrs\\brdrw10 "
1121          "\\trbrdrl\\brdrs\\brdrw10 "
1122          "\\trbrdrb\\brdrs\\brdrw10 "
1123          "\\trbrdrr\\brdrs\\brdrw10 "
1124          "\\trbrdrh\\brdrs\\brdrw10 "
1125          "\\trbrdrv\\brdrs\\brdrw10 \n";
1126   for (i=0;i<r->numCells();i++)
1127   {
1128     if (r->isHeading())
1129     {
1130       m_t << "\\clcbpat16"; // set cell shading to light grey (color 16 in the clut)
1131     }
1132     m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10 "
1133            "\\clbrdrl\\brdrs\\brdrw10 "
1134            "\\clbrdrb\\brdrs\\brdrw10 "
1135            "\\clbrdrr \\brdrs\\brdrw10 "
1136            "\\cltxlrtb "
1137            "\\cellx" << ((i+1)*columnWidth) << "\n";
1138   }
1139   m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
1140   m_lastIsPara=FALSE;
1141 }
1142 
visitPost(DocHtmlRow *)1143 void RTFDocVisitor::visitPost(DocHtmlRow *)
1144 {
1145   if (m_hide) return;
1146   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlRow)}\n");
1147   m_t << "\n";
1148   m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
1149   m_t << "{\\row }\n";
1150   m_lastIsPara=FALSE;
1151 }
1152 
visitPre(DocHtmlCell * c)1153 void RTFDocVisitor::visitPre(DocHtmlCell *c)
1154 {
1155   if (m_hide) return;
1156   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlCell)}\n");
1157   m_t << "{" << align(c);
1158   m_lastIsPara=FALSE;
1159 }
1160 
visitPost(DocHtmlCell *)1161 void RTFDocVisitor::visitPost(DocHtmlCell *)
1162 {
1163   if (m_hide) return;
1164   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlCell)}\n");
1165   m_t << "\\cell }";
1166   m_lastIsPara=FALSE;
1167 }
1168 
visitPre(DocInternal *)1169 void RTFDocVisitor::visitPre(DocInternal *)
1170 {
1171   if (m_hide) return;
1172   //DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocInternal)}\n");
1173   //m_t << "{"; // start desc
1174   //m_t << "{\\b "; // start bold
1175   //m_t << theTranslator->trForInternalUseOnly();
1176   //m_t << "}"; // end bold
1177   //m_t << "\\par\n";
1178   //incIndentLevel();
1179   //m_t << rtf_Style_Reset << getStyle("DescContinue");
1180   //m_lastIsPara=FALSE;
1181 }
1182 
visitPost(DocInternal *)1183 void RTFDocVisitor::visitPost(DocInternal *)
1184 {
1185   if (m_hide) return;
1186   //DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocInternal)}\n");
1187   //m_t << "\\par";
1188   //decIndentLevel();
1189   //m_t << "}"; // end desc
1190   //m_lastIsPara=TRUE;
1191 }
1192 
visitPre(DocHRef * href)1193 void RTFDocVisitor::visitPre(DocHRef *href)
1194 {
1195   if (m_hide) return;
1196   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHRef)}\n");
1197   if (Config_getBool(RTF_HYPERLINKS))
1198   {
1199     if (href->url().startsWith("#"))
1200     {
1201       // when starting with # so a local link
1202       QCString cite;
1203       cite = href->file() + "_" + href->url().right(href->url().length()-1);
1204       m_t << "{\\field "
1205                "{\\*\\fldinst "
1206                  "{ HYPERLINK \\\\l \"" << rtfFormatBmkStr(cite) << "\" "
1207                  "}{}"
1208                "}"
1209                "{\\fldrslt "
1210                  "{\\cs37\\ul\\cf2 ";
1211     }
1212     else
1213     {
1214       m_t << "{\\field "
1215                  "{\\*\\fldinst "
1216                  "{ HYPERLINK \"" << href->url() << "\" "
1217                  "}{}"
1218                "}"
1219                "{\\fldrslt "
1220                  "{\\cs37\\ul\\cf2 ";
1221     }
1222   }
1223   else
1224   {
1225     m_t << "{\\f2 ";
1226   }
1227   m_lastIsPara=FALSE;
1228 }
1229 
visitPost(DocHRef *)1230 void RTFDocVisitor::visitPost(DocHRef *)
1231 {
1232   if (m_hide) return;
1233   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHRef)}\n");
1234   if (Config_getBool(RTF_HYPERLINKS))
1235   {
1236     m_t <<     "}"
1237              "}"
1238            "}";
1239   }
1240   else
1241   {
1242     m_t << "}";
1243   }
1244   m_lastIsPara=FALSE;
1245 }
1246 
visitPre(DocHtmlHeader * header)1247 void RTFDocVisitor::visitPre(DocHtmlHeader *header)
1248 {
1249   if (m_hide) return;
1250   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlHeader)}\n");
1251   m_t << "{" // start section
1252       << rtf_Style_Reset;
1253   QCString heading;
1254   int level = std::min(header->level(),5);
1255   heading.sprintf("Heading%d",level);
1256   // set style
1257   m_t << rtf_Style[heading.str()].reference();
1258   // make open table of contents entry that will be closed in visitPost method
1259   m_t << "{\\tc\\tcl" << level << " ";
1260   m_lastIsPara=FALSE;
1261 }
1262 
visitPost(DocHtmlHeader *)1263 void RTFDocVisitor::visitPost(DocHtmlHeader *)
1264 {
1265   if (m_hide) return;
1266   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlHeader)}\n");
1267   // close open table of contents entry
1268   m_t << "} \\par";
1269   m_t << "}\n"; // end section
1270   m_lastIsPara=TRUE;
1271 }
1272 
visitPre(DocImage * img)1273 void RTFDocVisitor::visitPre(DocImage *img)
1274 {
1275   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocImage)}\n");
1276   includePicturePreRTF(img->name(), img->type()==DocImage::Rtf, img->hasCaption(), img->isInlineImage());
1277 }
includePicturePreRTF(const QCString & name,bool isTypeRTF,bool hasCaption,bool inlineImage)1278 void RTFDocVisitor::includePicturePreRTF(const QCString &name, bool isTypeRTF, bool hasCaption, bool inlineImage)
1279 {
1280   if (isTypeRTF)
1281   {
1282     if (!inlineImage)
1283     {
1284       m_t << "\\par\n";
1285       m_t << "{\n";
1286       m_t << rtf_Style_Reset << "\n";
1287       if (hasCaption || m_lastIsPara) m_t << "\\par\n";
1288       m_t << "\\pard \\qc ";
1289     }
1290     m_t << "{ \\field\\flddirty {\\*\\fldinst  INCLUDEPICTURE \"";
1291     m_t << name;
1292     m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt Image}}\n";
1293     if (!inlineImage)
1294     {
1295       m_t << "\\par\n";
1296       if (hasCaption)
1297       {
1298          m_t << "\\pard \\qc \\b";
1299          m_t << "{Image \\field\\flddirty{\\*\\fldinst { SEQ Image \\\\*Arabic }}{\\fldrslt {\\noproof 1}} ";
1300       }
1301       m_lastIsPara=TRUE;
1302     }
1303     else
1304     {
1305       if (hasCaption) m_t << "{\\comment "; // to prevent caption to be shown
1306     }
1307   }
1308   else // other format -> skip
1309   {
1310     pushHidden(m_hide);
1311     m_hide=TRUE;
1312   }
1313 }
1314 
visitPost(DocImage * img)1315 void RTFDocVisitor::visitPost(DocImage *img)
1316 {
1317   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocImage)}\n");
1318   includePicturePostRTF(img->type()==DocImage::Rtf, img->hasCaption(), img->isInlineImage());
1319 }
1320 
includePicturePostRTF(bool isTypeRTF,bool hasCaption,bool inlineImage)1321 void RTFDocVisitor::includePicturePostRTF(bool isTypeRTF, bool hasCaption, bool inlineImage)
1322 {
1323   if (isTypeRTF)
1324   {
1325     if (m_hide) return;
1326     if (inlineImage)
1327     {
1328       if (hasCaption) m_t << " }";
1329     }
1330     else
1331     {
1332       if (hasCaption)
1333       {
1334         m_t << "}\n";
1335         m_t << "\\par}\n";
1336       }
1337       else
1338       {
1339         m_t << "}\n";
1340       }
1341     }
1342   }
1343   else
1344   {
1345     m_hide = popHidden();
1346   }
1347 }
1348 
visitPre(DocDotFile * df)1349 void RTFDocVisitor::visitPre(DocDotFile *df)
1350 {
1351   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocDotFile)}\n");
1352   if (!Config_getBool(DOT_CLEANUP)) copyFile(df->file(),Config_getString(RTF_OUTPUT)+"/"+stripPath(df->file()));
1353   writeDotFile(df);
1354 }
1355 
visitPost(DocDotFile * df)1356 void RTFDocVisitor::visitPost(DocDotFile *df)
1357 {
1358   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocDotFile)}\n");
1359   includePicturePostRTF(true, df->hasCaption());
1360 }
visitPre(DocMscFile * df)1361 void RTFDocVisitor::visitPre(DocMscFile *df)
1362 {
1363   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocMscFile)}\n");
1364   if (!Config_getBool(DOT_CLEANUP)) copyFile(df->file(),Config_getString(RTF_OUTPUT)+"/"+stripPath(df->file()));
1365   writeMscFile(df);
1366 }
1367 
visitPost(DocMscFile * df)1368 void RTFDocVisitor::visitPost(DocMscFile *df)
1369 {
1370   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocMscFile)}\n");
1371   includePicturePostRTF(true, df->hasCaption());
1372 }
1373 
visitPre(DocDiaFile * df)1374 void RTFDocVisitor::visitPre(DocDiaFile *df)
1375 {
1376   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocDiaFile)}\n");
1377   if (!Config_getBool(DOT_CLEANUP)) copyFile(df->file(),Config_getString(RTF_OUTPUT)+"/"+stripPath(df->file()));
1378   writeDiaFile(df);
1379 }
1380 
visitPost(DocDiaFile * df)1381 void RTFDocVisitor::visitPost(DocDiaFile *df)
1382 {
1383   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocDiaFile)}\n");
1384   includePicturePostRTF(true, df->hasCaption());
1385 }
1386 
visitPre(DocLink * lnk)1387 void RTFDocVisitor::visitPre(DocLink *lnk)
1388 {
1389   if (m_hide) return;
1390   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocLink)}\n");
1391   startLink(lnk->ref(),lnk->file(),lnk->anchor());
1392 }
1393 
visitPost(DocLink * lnk)1394 void RTFDocVisitor::visitPost(DocLink *lnk)
1395 {
1396   if (m_hide) return;
1397   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocLink)}\n");
1398   endLink(lnk->ref());
1399 }
1400 
visitPre(DocRef * ref)1401 void RTFDocVisitor::visitPre(DocRef *ref)
1402 {
1403   if (m_hide) return;
1404   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocRef)}\n");
1405   // when ref->isSubPage()==TRUE we use ref->file() for HTML and
1406   // ref->anchor() for LaTeX/RTF
1407   if (ref->isSubPage())
1408   {
1409     startLink(ref->ref(),QCString(),ref->anchor());
1410   }
1411   else
1412   {
1413     if (!ref->file().isEmpty()) startLink(ref->ref(),ref->file(),ref->anchor());
1414   }
1415   if (!ref->hasLinkText()) filter(ref->targetTitle());
1416 }
1417 
visitPost(DocRef * ref)1418 void RTFDocVisitor::visitPost(DocRef *ref)
1419 {
1420   if (m_hide) return;
1421   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocRef)}\n");
1422   if (!ref->file().isEmpty()) endLink(ref->ref());
1423   //m_t << " ";
1424 }
1425 
1426 
visitPre(DocSecRefItem *)1427 void RTFDocVisitor::visitPre(DocSecRefItem *)
1428 {
1429   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSecRefItem)}\n");
1430 }
1431 
visitPost(DocSecRefItem *)1432 void RTFDocVisitor::visitPost(DocSecRefItem *)
1433 {
1434   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSecRefItem)}\n");
1435 }
1436 
visitPre(DocSecRefList *)1437 void RTFDocVisitor::visitPre(DocSecRefList *)
1438 {
1439   if (m_hide) return;
1440   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSecRefList)}\n");
1441   m_t << "{\n";
1442   incIndentLevel();
1443   m_t << rtf_Style_Reset << getStyle("LatexTOC") << "\n";
1444   m_t << "\\par\n";
1445   m_lastIsPara=TRUE;
1446 }
1447 
visitPost(DocSecRefList *)1448 void RTFDocVisitor::visitPost(DocSecRefList *)
1449 {
1450   if (m_hide) return;
1451   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSecRefList)}\n");
1452   decIndentLevel();
1453   m_t << "\\par";
1454   m_t << "}\n";
1455   m_lastIsPara=TRUE;
1456 }
1457 
visitPre(DocParamSect * s)1458 void RTFDocVisitor::visitPre(DocParamSect *s)
1459 {
1460   if (m_hide) return;
1461   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocParamSect)}\n");
1462   m_t << "{"; // start param list
1463   if (!m_lastIsPara) m_t << "\\par\n";
1464   //m_t << "{\\b "; // start bold
1465   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
1466   switch(s->type())
1467   {
1468     case DocParamSect::Param:
1469       m_t << theTranslator->trParameters(); break;
1470     case DocParamSect::RetVal:
1471       m_t << theTranslator->trReturnValues(); break;
1472     case DocParamSect::Exception:
1473       m_t << theTranslator->trExceptions(); break;
1474     case DocParamSect::TemplateParam:
1475       m_t << theTranslator->trTemplateParameters(); break;
1476     default:
1477       ASSERT(0);
1478   }
1479   m_t << "\\par";
1480   m_t << "}\n";
1481   bool useTable = s->type()==DocParamSect::Param ||
1482                   s->type()==DocParamSect::RetVal ||
1483                   s->type()==DocParamSect::Exception ||
1484                   s->type()==DocParamSect::TemplateParam;
1485   if (!useTable)
1486   {
1487     incIndentLevel();
1488   }
1489   m_t << rtf_Style_Reset << getStyle("DescContinue");
1490   m_lastIsPara=TRUE;
1491 }
1492 
visitPost(DocParamSect * s)1493 void RTFDocVisitor::visitPost(DocParamSect *s)
1494 {
1495   if (m_hide) return;
1496   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocParamSect)}\n");
1497   //m_t << "\\par\n";
1498   bool useTable = s->type()==DocParamSect::Param ||
1499                   s->type()==DocParamSect::RetVal ||
1500                   s->type()==DocParamSect::Exception ||
1501                   s->type()==DocParamSect::TemplateParam;
1502   if (!useTable)
1503   {
1504     decIndentLevel();
1505   }
1506   m_t << "}\n";
1507 }
1508 
visitPre(DocParamList * pl)1509 void RTFDocVisitor::visitPre(DocParamList *pl)
1510 {
1511   static int columnPos[4][5] =
1512   { { 2, 25, 100, 100, 100 }, // no inout, no type
1513     { 3, 14,  35, 100, 100 }, // inout, no type
1514     { 3, 25,  50, 100, 100 }, // no inout, type
1515     { 4, 14,  35, 55,  100 }, // inout, type
1516   };
1517   int config=0;
1518   if (m_hide) return;
1519   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocParamList)}\n");
1520 
1521   DocParamSect::Type parentType = DocParamSect::Unknown;
1522   DocParamSect *sect = 0;
1523   if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect)
1524   {
1525     parentType = ((DocParamSect*)pl->parent())->type();
1526     sect=(DocParamSect*)pl->parent();
1527   }
1528   bool useTable = parentType==DocParamSect::Param ||
1529                   parentType==DocParamSect::RetVal ||
1530                   parentType==DocParamSect::Exception ||
1531                   parentType==DocParamSect::TemplateParam;
1532   if (sect && sect->hasInOutSpecifier()) config+=1;
1533   if (sect && sect->hasTypeSpecifier())  config+=2;
1534   if (useTable)
1535   {
1536     int i;
1537     m_t << "\\trowd \\trgaph108\\trleft426\\tblind426"
1538          "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 "
1539          "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 "
1540          "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 "
1541          "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 "
1542          "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 "
1543          "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 "<< "\n";
1544     for (i=0;i<columnPos[config][0];i++)
1545     {
1546       m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10\\brdrcf15 "
1547            "\\clbrdrl\\brdrs\\brdrw10\\brdrcf15 "
1548            "\\clbrdrb\\brdrs\\brdrw10\\brdrcf15 "
1549            "\\clbrdrr \\brdrs\\brdrw10\\brdrcf15 "
1550            "\\cltxlrtb "
1551            "\\cellx" << (rtf_pageWidth*columnPos[config][i+1]/100) << "\n";
1552     }
1553     m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
1554   }
1555 
1556   if (sect && sect->hasInOutSpecifier())
1557   {
1558     if (useTable)
1559     {
1560       m_t << "{";
1561     }
1562 
1563     // Put in the direction: in/out/in,out if specified.
1564     if (pl->direction()!=DocParamSect::Unspecified)
1565     {
1566       if (pl->direction()==DocParamSect::In)
1567       {
1568         m_t << "in";
1569       }
1570       else if (pl->direction()==DocParamSect::Out)
1571       {
1572         m_t << "out";
1573       }
1574       else if (pl->direction()==DocParamSect::InOut)
1575       {
1576         m_t << "in,out";
1577       }
1578     }
1579 
1580     if (useTable)
1581     {
1582       m_t << "\\cell }";
1583     }
1584   }
1585 
1586   if (sect && sect->hasTypeSpecifier())
1587   {
1588     if (useTable)
1589     {
1590       m_t << "{";
1591     }
1592     for (const auto &type : pl->paramTypes())
1593     {
1594       if (type->kind()==DocNode::Kind_Word)
1595       {
1596         visit((DocWord*)type.get());
1597       }
1598       else if (type->kind()==DocNode::Kind_LinkedWord)
1599       {
1600         visit((DocLinkedWord*)type.get());
1601       }
1602       else if (type->kind()==DocNode::Kind_Sep)
1603       {
1604         m_t << " " << ((DocSeparator *)type.get())->chars() << " ";
1605       }
1606     }
1607     if (useTable)
1608     {
1609       m_t << "\\cell }";
1610     }
1611   }
1612 
1613 
1614   if (useTable)
1615   {
1616     m_t << "{";
1617   }
1618 
1619   m_t << "{\\i ";
1620   bool first=TRUE;
1621   for (const auto &param : pl->parameters())
1622   {
1623     if (!first) m_t << ","; else first=FALSE;
1624     if (param->kind()==DocNode::Kind_Word)
1625     {
1626       visit((DocWord*)param.get());
1627     }
1628     else if (param->kind()==DocNode::Kind_LinkedWord)
1629     {
1630       visit((DocLinkedWord*)param.get());
1631     }
1632   }
1633   m_t << "} ";
1634 
1635   if (useTable)
1636   {
1637     m_t << "\\cell }{";
1638   }
1639   m_lastIsPara=TRUE;
1640 }
1641 
visitPost(DocParamList * pl)1642 void RTFDocVisitor::visitPost(DocParamList *pl)
1643 {
1644   if (m_hide) return;
1645   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocParamList)}\n");
1646 
1647   DocParamSect::Type parentType = DocParamSect::Unknown;
1648   //DocParamSect *sect = 0;
1649   if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect)
1650   {
1651     parentType = ((DocParamSect*)pl->parent())->type();
1652     //sect=(DocParamSect*)pl->parent();
1653   }
1654   bool useTable = parentType==DocParamSect::Param ||
1655                   parentType==DocParamSect::RetVal ||
1656                   parentType==DocParamSect::Exception ||
1657                   parentType==DocParamSect::TemplateParam;
1658   if (useTable)
1659   {
1660     m_t << "\\cell }\n";
1661     //m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
1662     m_t << "{\\row }\n";
1663   }
1664   else
1665   {
1666     m_t << "\\par\n";
1667   }
1668 
1669   m_lastIsPara=TRUE;
1670 }
1671 
visitPre(DocXRefItem * x)1672 void RTFDocVisitor::visitPre(DocXRefItem *x)
1673 {
1674   if (m_hide) return;
1675   if (x->title().isEmpty()) return;
1676   bool anonymousEnum = x->file()=="@";
1677   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocXRefItem)}\n");
1678   if (!m_lastIsPara)
1679   {
1680     m_t << "\\par\n";
1681     m_lastIsPara=TRUE;
1682   }
1683   m_t << "{"; // start param list
1684   //m_t << "{\\b "; // start bold
1685   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
1686   if (Config_getBool(RTF_HYPERLINKS) && !anonymousEnum)
1687   {
1688     QCString refName;
1689     if (!x->file().isEmpty())
1690     {
1691       refName+=stripPath(x->file());
1692     }
1693     if (!x->file().isEmpty() && !x->anchor().isEmpty())
1694     {
1695       refName+="_";
1696     }
1697     if (!x->anchor().isEmpty())
1698     {
1699       refName+=x->anchor();
1700     }
1701 
1702     m_t << "{\\field "
1703              "{\\*\\fldinst "
1704                "{ HYPERLINK  \\\\l \"" << rtfFormatBmkStr(refName) << "\" "
1705                "}{}"
1706              "}"
1707              "{\\fldrslt "
1708                "{\\cs37\\ul\\cf2 ";
1709     filter(x->title());
1710     m_t <<     "}"
1711              "}"
1712            "}";
1713   }
1714   else
1715   {
1716     filter(x->title());
1717   }
1718   m_t << ":";
1719   m_t << "\\par";
1720   m_t << "}"; // end bold
1721   incIndentLevel();
1722   m_t << rtf_Style_Reset << getStyle("DescContinue");
1723   m_lastIsPara=FALSE;
1724 }
1725 
visitPost(DocXRefItem * x)1726 void RTFDocVisitor::visitPost(DocXRefItem *x)
1727 {
1728   if (m_hide) return;
1729   if (x->title().isEmpty()) return;
1730   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocXRefItem)}\n");
1731   m_t << "\\par\n";
1732   decIndentLevel();
1733   m_t << "}\n"; // end xref item
1734   m_lastIsPara=TRUE;
1735 }
1736 
visitPre(DocInternalRef * ref)1737 void RTFDocVisitor::visitPre(DocInternalRef *ref)
1738 {
1739   if (m_hide) return;
1740   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocInternalRef)}\n");
1741   startLink("",ref->file(),ref->anchor());
1742 }
1743 
visitPost(DocInternalRef *)1744 void RTFDocVisitor::visitPost(DocInternalRef *)
1745 {
1746   if (m_hide) return;
1747   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocInternalRef)}\n");
1748   endLink("");
1749   m_t << " ";
1750 }
1751 
visitPre(DocText *)1752 void RTFDocVisitor::visitPre(DocText *)
1753 {
1754   if (m_hide) return;
1755   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocText)}\n");
1756 }
1757 
visitPost(DocText *)1758 void RTFDocVisitor::visitPost(DocText *)
1759 {
1760   if (m_hide) return;
1761   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocText)}\n");
1762 }
1763 
visitPre(DocHtmlBlockQuote *)1764 void RTFDocVisitor::visitPre(DocHtmlBlockQuote *)
1765 {
1766   if (m_hide) return;
1767   DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlBlockQuote)}\n");
1768   if (!m_lastIsPara) m_t << "\\par\n";
1769   m_t << "{"; // start desc
1770   incIndentLevel();
1771   m_t << rtf_Style_Reset << getStyle("DescContinue");
1772 }
1773 
visitPost(DocHtmlBlockQuote *)1774 void RTFDocVisitor::visitPost(DocHtmlBlockQuote *)
1775 {
1776   if (m_hide) return;
1777   DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlBlockQuote)}\n");
1778   if (!m_lastIsPara) m_t << "\\par\n";
1779   decIndentLevel();
1780   m_t << "}"; // end desc
1781   m_lastIsPara=TRUE;
1782 }
1783 
visitPre(DocVhdlFlow *)1784 void RTFDocVisitor::visitPre(DocVhdlFlow *)
1785 {
1786   if (m_hide) return;
1787 }
1788 
visitPost(DocVhdlFlow *)1789 void RTFDocVisitor::visitPost(DocVhdlFlow *)
1790 {
1791   if (m_hide) return;
1792 }
1793 
visitPre(DocParBlock *)1794 void RTFDocVisitor::visitPre(DocParBlock *)
1795 {
1796   if (m_hide) return;
1797 }
1798 
visitPost(DocParBlock *)1799 void RTFDocVisitor::visitPost(DocParBlock *)
1800 {
1801   if (m_hide) return;
1802 }
1803 
1804 
1805 //static char* getMultiByte(int c)
1806 //{
1807 //    static char s[10];
1808 //    sprintf(s,"\\'%X",c);
1809 //    return s;
1810 //}
1811 
filter(const QCString & str,bool verbatim)1812 void RTFDocVisitor::filter(const QCString &str,bool verbatim)
1813 {
1814   if (!str.isEmpty())
1815   {
1816     const unsigned char *p=(const unsigned char *)str.data();
1817     unsigned char c;
1818     //unsigned char pc='\0';
1819     while (*p)
1820     {
1821       //static bool MultiByte = FALSE;
1822       c=*p++;
1823 
1824       //if ( MultiByte )
1825       //{
1826       //  m_t << getMultiByte( c );
1827       //  MultiByte = FALSE;
1828       //  continue;
1829       //}
1830       //if ( c >= 0x80 )
1831       //{
1832       //  MultiByte = TRUE;
1833       //  m_t << getMultiByte( c );
1834       //  continue;
1835       //}
1836 
1837       switch (c)
1838       {
1839         case '{':  m_t << "\\{";            break;
1840         case '}':  m_t << "\\}";            break;
1841         case '\\': m_t << "\\\\";           break;
1842         case '\n': if (verbatim)
1843                    {
1844                      m_t << "\\par\n";
1845                    }
1846                    else
1847                    {
1848                      m_t << '\n';
1849                    }
1850                    break;
1851         default:   m_t << (char)c;
1852       }
1853       //pc = c;
1854     }
1855   }
1856 }
1857 
startLink(const QCString & ref,const QCString & file,const QCString & anchor)1858 void RTFDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor)
1859 {
1860   if (ref.isEmpty() && Config_getBool(RTF_HYPERLINKS))
1861   {
1862     QCString refName;
1863     if (!file.isEmpty())
1864     {
1865       refName+=stripPath(file);
1866     }
1867     if (!file.isEmpty() && !anchor.isEmpty())
1868     {
1869       refName+='_';
1870     }
1871     if (!anchor.isEmpty())
1872     {
1873       refName+=anchor;
1874     }
1875 
1876     m_t << "{\\field {\\*\\fldinst { HYPERLINK  \\\\l \"";
1877     m_t << rtfFormatBmkStr(refName);
1878     m_t << "\" }{}";
1879     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1880   }
1881   else
1882   {
1883     m_t << "{\\b ";
1884   }
1885   m_lastIsPara=FALSE;
1886 }
1887 
endLink(const QCString & ref)1888 void RTFDocVisitor::endLink(const QCString &ref)
1889 {
1890   if (ref.isEmpty() && Config_getBool(RTF_HYPERLINKS))
1891   {
1892     m_t << "}}}";
1893   }
1894   else
1895   {
1896     m_t << "}";
1897   }
1898   m_lastIsPara=FALSE;
1899 }
1900 
writeDotFile(DocDotFile * df)1901 void RTFDocVisitor::writeDotFile(DocDotFile *df)
1902 {
1903   writeDotFile(df->file(), df->hasCaption(), df->srcFile(), df->srcLine());
1904 }
writeDotFile(const QCString & filename,bool hasCaption,const QCString & srcFile,int srcLine)1905 void RTFDocVisitor::writeDotFile(const QCString &filename, bool hasCaption,
1906                                  const QCString &srcFile, int srcLine)
1907 {
1908   QCString baseName=filename;
1909   int i;
1910   if ((i=baseName.findRev('/'))!=-1)
1911   {
1912     baseName=baseName.right(baseName.length()-i-1);
1913   }
1914   QCString outDir = Config_getString(RTF_OUTPUT);
1915   writeDotGraphFromFile(filename,outDir,baseName,GOF_BITMAP,srcFile,srcLine);
1916   QCString imgExt = getDotImageExtension();
1917   includePicturePreRTF(baseName + "." + imgExt, true, hasCaption);
1918 }
1919 
writeMscFile(DocMscFile * df)1920 void RTFDocVisitor::writeMscFile(DocMscFile *df)
1921 {
1922   writeMscFile(df->file(), df->hasCaption(), df->srcFile(), df->srcLine());
1923 }
writeMscFile(const QCString & fileName,bool hasCaption,const QCString & srcFile,int srcLine)1924 void RTFDocVisitor::writeMscFile(const QCString &fileName, bool hasCaption,
1925                                  const QCString &srcFile, int srcLine)
1926 {
1927   QCString baseName=fileName;
1928   int i;
1929   if ((i=baseName.findRev('/'))!=-1)
1930   {
1931     baseName=baseName.right(baseName.length()-i-1);
1932   }
1933   QCString outDir = Config_getString(RTF_OUTPUT);
1934   writeMscGraphFromFile(fileName,outDir,baseName,MSC_BITMAP,srcFile,srcLine);
1935   includePicturePreRTF(baseName + ".png", true, hasCaption);
1936 }
1937 
writeDiaFile(DocDiaFile * df)1938 void RTFDocVisitor::writeDiaFile(DocDiaFile *df)
1939 {
1940   QCString baseName=df->file();
1941   int i;
1942   if ((i=baseName.findRev('/'))!=-1)
1943   {
1944     baseName=baseName.right(baseName.length()-i-1);
1945   }
1946   QCString outDir = Config_getString(RTF_OUTPUT);
1947   writeDiaGraphFromFile(df->file(),outDir,baseName,DIA_BITMAP,df->srcFile(),df->srcLine());
1948   includePicturePreRTF(baseName + ".png", true, df->hasCaption());
1949 }
1950 
writePlantUMLFile(const QCString & fileName,bool hasCaption)1951 void RTFDocVisitor::writePlantUMLFile(const QCString &fileName, bool hasCaption)
1952 {
1953   QCString baseName=fileName;
1954   int i;
1955   if ((i=baseName.findRev('/'))!=-1)
1956   {
1957     baseName=baseName.right(baseName.length()-i-1);
1958   }
1959   QCString outDir = Config_getString(RTF_OUTPUT);
1960   PlantumlManager::instance().generatePlantUMLOutput(fileName,outDir,PlantumlManager::PUML_BITMAP);
1961   includePicturePreRTF(baseName + ".png", true, hasCaption);
1962 }
1963