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