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