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