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