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