1 /******************************************************************************
6 * Copyright (C) 1997-2015 by Dimitri van Heesch.
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.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
18 #include "htmlattrib.h"
19 #include <qfileinfo.h>
20 #include "latexdocvisitor.h"
22 #include "docparser.h"
25 #include "outputgen.h"
29 #include "parserintf.h"
35 #include "htmlentity.h"
39 const int maxLevels=5;
40 static const char *secLabels[maxLevels] =
41 { "section","subsection","subsubsection","paragraph","subparagraph" };
43 static const char *getSectionName(int level)
45 static bool compactLatex = Config_getBool(COMPACT_LATEX);
47 if (compactLatex) l++;
48 if (Doxygen::insideMainPage) l--;
49 return secLabels[QMIN(maxLevels-1,l)];
52 static void visitPreStart(FTextStream &t, bool hasCaption, QCString name, QCString width, QCString height, bool inlineImage = FALSE)
56 t << "\n\\begin{DoxyInlineImage}\n";
62 t << "\n\\begin{DoxyImage}\n";
66 t << "\n\\begin{DoxyImageNoCaption}\n"
71 t << "\\includegraphics";
72 if (!width.isEmpty() || !height.isEmpty())
78 t << "width=" << width;
80 if (!width.isEmpty() && !height.isEmpty())
84 if (!height.isEmpty())
86 t << "height=" << height;
88 if (width.isEmpty() && height.isEmpty())
93 t << "[height=\\baselineskip,keepaspectratio=true]";
97 t << "[width=\\textwidth,height=\\textheight/2,keepaspectratio=true]";
105 t << "{" << name << "}";
111 t << "\n\\doxyfigcaption{";
115 t << "%"; // to catch the caption
122 static void visitPostEnd(FTextStream &t, bool hasCaption, bool inlineImage = FALSE)
126 t << "\n\\end{DoxyInlineImage}\n";
130 t << "}\n"; // end mbox or caption
133 t << "\\end{DoxyImage}\n";
137 t << "\\end{DoxyImageNoCaption}\n";
143 static void visitCaption(LatexDocVisitor *parent, QList<DocNode> children)
145 QListIterator<DocNode> cli(children);
147 for (cli.toFirst();(n=cli.current());++cli) n->accept(parent);
150 QCString LatexDocVisitor::escapeMakeIndexChars(const char *s)
154 char str[2]; str[1]=0;
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;
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),
184 m_tableStateStack.setAutoDelete(TRUE);
187 //--------------------------------------
188 // visitor functions for leaf nodes
189 //--------------------------------------
191 void LatexDocVisitor::visit(DocWord *w)
197 void LatexDocVisitor::visit(DocLinkedWord *w)
200 startLink(w->ref(),w->file(),w->anchor());
202 endLink(w->ref(),w->file(),w->anchor());
205 void LatexDocVisitor::visit(DocWhiteSpace *w)
218 void LatexDocVisitor::visit(DocSymbol *s)
221 const char *res = HtmlEntityMapper::instance()->latex(s->symbol());
224 if (((s->symbol() == DocSymbol::Sym_lt) || (s->symbol() == DocSymbol::Sym_Less))&& (!m_insidePre))
228 else if (((s->symbol() == DocSymbol::Sym_gt) || (s->symbol() == DocSymbol::Sym_Greater)) && (!m_insidePre))
239 err("LaTeX: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
243 void LatexDocVisitor::visit(DocEmoji *s)
246 QCString emojiName = EmojiEntityMapper::instance()->name(s->index());
247 if (!emojiName.isEmpty())
249 QCString imageName=emojiName.mid(1,emojiName.length()-2); // strip : at start and end
250 m_t << "\\doxygenemoji{";
252 m_t << "}{" << imageName << "}";
260 void LatexDocVisitor::visit(DocURL *u)
263 if (Config_getBool(PDF_HYPERLINKS))
266 if (u->isEmail()) m_t << "mailto:";
267 m_t << latexFilterURL(u->url()) << "}";
269 m_t << "{\\texttt{ ";
274 void LatexDocVisitor::visit(DocLineBreak *)
277 m_t << "~\\newline\n";
280 void LatexDocVisitor::visit(DocHorRuler *)
286 void LatexDocVisitor::visit(DocStyleChange *s)
291 case DocStyleChange::Bold:
292 if (s->enable()) m_t << "{\\bfseries{"; else m_t << "}}";
294 case DocStyleChange::Strike:
295 if (s->enable()) m_t << "\\sout{"; else m_t << "}";
297 case DocStyleChange::Underline:
298 if (s->enable()) m_t << "\\uline{"; else m_t << "}";
300 case DocStyleChange::Italic:
301 if (s->enable()) m_t << "{\\itshape "; else m_t << "}";
303 case DocStyleChange::Code:
304 if (s->enable()) m_t << "{\\ttfamily "; else m_t << "}";
306 case DocStyleChange::Subscript:
307 if (s->enable()) m_t << "\\textsubscript{"; else m_t << "}";
309 case DocStyleChange::Superscript:
310 if (s->enable()) m_t << "\\textsuperscript{"; else m_t << "}";
312 case DocStyleChange::Center:
313 if (s->enable()) m_t << "\\begin{center}"; else m_t << "\\end{center} ";
315 case DocStyleChange::Small:
316 if (s->enable()) m_t << "\n\\footnotesize "; else m_t << "\n\\normalsize ";
318 case DocStyleChange::Preformatted:
321 m_t << "\n\\begin{DoxyPre}";
327 m_t << "\\end{DoxyPre}\n";
330 case DocStyleChange::Div: /* HTML only */ break;
331 case DocStyleChange::Span: /* HTML only */ break;
335 void LatexDocVisitor::visit(DocVerbatim *s)
338 QCString lang = m_langExt;
339 if (!s->language().isEmpty()) // explicit language setting
341 lang = s->language();
343 SrcLangExt langExt = getLanguageFromFileName(lang);
346 case DocVerbatim::Code:
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";
357 case DocVerbatim::Verbatim:
358 m_t << "\\begin{DoxyVerb}";
360 m_t << "\\end{DoxyVerb}\n";
362 case DocVerbatim::HtmlOnly:
363 case DocVerbatim::XmlOnly:
364 case DocVerbatim::ManOnly:
365 case DocVerbatim::RtfOnly:
366 case DocVerbatim::DocbookOnly:
369 case DocVerbatim::LatexOnly:
372 case DocVerbatim::Dot:
374 static int dotindex = 1;
375 QCString fileName(4096);
377 fileName.sprintf("%s%d%s",
378 (Config_getString(LATEX_OUTPUT)+"/inline_dotgraph_").data(),
382 QFile file(fileName);
383 if (!file.open(IO_WriteOnly))
385 err("Could not open file %s for writing\n",fileName.data());
389 file.writeBlock( s->text(), s->text().length() );
392 startDotFile(fileName,s->width(),s->height(),s->hasCaption());
393 visitCaption(this, s->children());
394 endDotFile(s->hasCaption());
396 if (Config_getBool(DOT_CLEANUP)) file.remove();
400 case DocVerbatim::Msc:
402 static int mscindex = 1;
403 QCString baseName(4096);
405 baseName.sprintf("%s%d",
406 (Config_getString(LATEX_OUTPUT)+"/inline_mscgraph_").data(),
409 QFile file(baseName+".msc");
410 if (!file.open(IO_WriteOnly))
412 err("Could not open file %s.msc for writing\n",baseName.data());
416 QCString text = "msc {";
419 file.writeBlock( text, text.length() );
422 writeMscFile(baseName, s);
424 if (Config_getBool(DOT_CLEANUP)) file.remove();
428 case DocVerbatim::PlantUML:
430 QCString latexOutput = Config_getString(LATEX_OUTPUT);
431 QCString baseName = writePlantUMLSource(latexOutput,s->exampleFile(),s->text());
433 writePlantUMLFile(baseName, s);
439 void LatexDocVisitor::visit(DocAnchor *anc)
442 m_t << "\\label{" << stripPath(anc->file()) << "_" << anc->anchor() << "}%" << endl;
443 if (!anc->file().isEmpty() && Config_getBool(PDF_HYPERLINKS))
445 m_t << "\\Hypertarget{" << stripPath(anc->file()) << "_" << anc->anchor()
450 void LatexDocVisitor::visit(DocInclude *inc)
453 SrcLangExt langExt = getLanguageFromFileName(inc->extension());
456 case DocInclude::IncWithLines:
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(),
471 FALSE, // inline fragment
473 TRUE // show line numbers
475 LatexCodeGenerator::setDoxyCodeOpen(FALSE);
476 m_t << "\\end{DoxyCodeInclude}" << endl;
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(),
489 TRUE, // inlineFragment
493 LatexCodeGenerator::setDoxyCodeOpen(FALSE);
494 m_t << "\\end{DoxyCodeInclude}\n";
496 case DocInclude::DontInclude:
498 case DocInclude::HtmlInclude:
500 case DocInclude::LatexInclude:
503 case DocInclude::VerbInclude:
504 m_t << "\n\\begin{DoxyVerbInclude}\n";
506 m_t << "\\end{DoxyVerbInclude}\n";
508 case DocInclude::Snippet:
510 m_t << "\n\\begin{DoxyCodeInclude}{" << usedTableLevels() << "}\n";
511 LatexCodeGenerator::setDoxyCodeOpen(TRUE);
512 Doxygen::parserManager->getParser(inc->extension())
515 extractBlock(inc->text(),inc->blockId()),
520 LatexCodeGenerator::setDoxyCodeOpen(FALSE);
521 m_t << "\\end{DoxyCodeInclude}" << endl;
524 case DocInclude::SnipWithLines:
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())
533 extractBlock(inc->text(),inc->blockId()),
538 lineBlock(inc->text(),inc->blockId()),
540 FALSE, // inlineFragment
542 TRUE // show line number
544 LatexCodeGenerator::setDoxyCodeOpen(FALSE);
545 m_t << "\\end{DoxyCodeInclude}" << endl;
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__);
556 void LatexDocVisitor::visit(DocIncOperator *op)
558 //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
559 // op->type(),op->isFirst(),op->isLast(),op->text().data());
562 if (!m_hide) m_t << "\n\\begin{DoxyCodeInclude}{" << usedTableLevels() << "}\n";
563 LatexCodeGenerator::setDoxyCodeOpen(TRUE);
567 SrcLangExt langExt = getLanguageFromFileName(m_langExt);
568 if (op->type()!=DocIncOperator::Skip)
573 Doxygen::parserManager->getParser(m_langExt)
574 ->parseCode(m_ci,op->context(),op->text(),langExt,
575 op->isExample(),op->exampleFile());
583 LatexCodeGenerator::setDoxyCodeOpen(FALSE);
584 if (!m_hide) m_t << "\n\\end{DoxyCodeInclude}\n";
588 if (!m_hide) m_t << endl;
592 void LatexDocVisitor::visit(DocFormula *f)
595 const char *p=f->text();
603 case '\'': m_t << "\\text{'}"; break;
604 default: m_t << c; break;
610 void LatexDocVisitor::visit(DocIndexEntry *i)
614 m_t << latexEscapeLabelName(i->entry());
616 m_t << latexEscapeIndexChars(i->entry());
620 void LatexDocVisitor::visit(DocSimpleSectSep *)
624 void LatexDocVisitor::visit(DocCite *cite)
627 if (!cite->file().isEmpty())
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 << "}";
636 m_t << "{\\bfseries [";
637 filter(cite->text());
642 //--------------------------------------
643 // visitor functions for compound nodes
644 //--------------------------------------
646 void LatexDocVisitor::visitPre(DocAutoList *l)
651 m_t << "\n\\begin{DoxyEnumerate}";
655 m_t << "\n\\begin{DoxyItemize}";
659 void LatexDocVisitor::visitPost(DocAutoList *l)
664 m_t << "\n\\end{DoxyEnumerate}";
668 m_t << "\n\\end{DoxyItemize}";
672 void LatexDocVisitor::visitPre(DocAutoListItem *)
678 void LatexDocVisitor::visitPost(DocAutoListItem *)
682 void LatexDocVisitor::visitPre(DocPara *)
686 void LatexDocVisitor::visitPost(DocPara *p)
689 if (!p->isLast() && // omit <p> for last paragraph
690 !(p->parent() && // and for parameter sections
691 p->parent()->kind()==DocNode::Kind_ParamSect
693 ) m_t << endl << endl;
696 void LatexDocVisitor::visitPre(DocRoot *)
700 void LatexDocVisitor::visitPost(DocRoot *)
704 void LatexDocVisitor::visitPre(DocSimpleSect *s)
709 case DocSimpleSect::See:
710 m_t << "\\begin{DoxySeeAlso}{";
711 filter(theTranslator->trSeeAlso());
713 case DocSimpleSect::Return:
714 m_t << "\\begin{DoxyReturn}{";
715 filter(theTranslator->trReturns());
717 case DocSimpleSect::Author:
718 m_t << "\\begin{DoxyAuthor}{";
719 filter(theTranslator->trAuthor(TRUE,TRUE));
721 case DocSimpleSect::Authors:
722 m_t << "\\begin{DoxyAuthor}{";
723 filter(theTranslator->trAuthor(TRUE,FALSE));
725 case DocSimpleSect::Version:
726 m_t << "\\begin{DoxyVersion}{";
727 filter(theTranslator->trVersion());
729 case DocSimpleSect::Since:
730 m_t << "\\begin{DoxySince}{";
731 filter(theTranslator->trSince());
733 case DocSimpleSect::Date:
734 m_t << "\\begin{DoxyDate}{";
735 filter(theTranslator->trDate());
737 case DocSimpleSect::Note:
738 m_t << "\\begin{DoxyNote}{";
739 filter(theTranslator->trNote());
741 case DocSimpleSect::Warning:
742 m_t << "\\begin{DoxyWarning}{";
743 filter(theTranslator->trWarning());
745 case DocSimpleSect::Pre:
746 m_t << "\\begin{DoxyPrecond}{";
747 filter(theTranslator->trPrecondition());
749 case DocSimpleSect::Post:
750 m_t << "\\begin{DoxyPostcond}{";
751 filter(theTranslator->trPostcondition());
753 case DocSimpleSect::Copyright:
754 m_t << "\\begin{DoxyCopyright}{";
755 filter(theTranslator->trCopyright());
757 case DocSimpleSect::Invar:
758 m_t << "\\begin{DoxyInvariant}{";
759 filter(theTranslator->trInvariant());
761 case DocSimpleSect::Remark:
762 m_t << "\\begin{DoxyRemark}{";
763 filter(theTranslator->trRemarks());
765 case DocSimpleSect::Attention:
766 m_t << "\\begin{DoxyAttention}{";
767 filter(theTranslator->trAttention());
769 case DocSimpleSect::User:
770 m_t << "\\begin{DoxyParagraph}{";
772 case DocSimpleSect::Rcs:
773 m_t << "\\begin{DoxyParagraph}{";
775 case DocSimpleSect::Unknown: break;
778 // special case 1: user defined title
779 if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
789 void LatexDocVisitor::visitPost(DocSimpleSect *s)
794 case DocSimpleSect::See:
795 m_t << "\n\\end{DoxySeeAlso}\n";
797 case DocSimpleSect::Return:
798 m_t << "\n\\end{DoxyReturn}\n";
800 case DocSimpleSect::Author:
801 m_t << "\n\\end{DoxyAuthor}\n";
803 case DocSimpleSect::Authors:
804 m_t << "\n\\end{DoxyAuthor}\n";
806 case DocSimpleSect::Version:
807 m_t << "\n\\end{DoxyVersion}\n";
809 case DocSimpleSect::Since:
810 m_t << "\n\\end{DoxySince}\n";
812 case DocSimpleSect::Date:
813 m_t << "\n\\end{DoxyDate}\n";
815 case DocSimpleSect::Note:
816 m_t << "\n\\end{DoxyNote}\n";
818 case DocSimpleSect::Warning:
819 m_t << "\n\\end{DoxyWarning}\n";
821 case DocSimpleSect::Pre:
822 m_t << "\n\\end{DoxyPrecond}\n";
824 case DocSimpleSect::Post:
825 m_t << "\n\\end{DoxyPostcond}\n";
827 case DocSimpleSect::Copyright:
828 m_t << "\n\\end{DoxyCopyright}\n";
830 case DocSimpleSect::Invar:
831 m_t << "\n\\end{DoxyInvariant}\n";
833 case DocSimpleSect::Remark:
834 m_t << "\n\\end{DoxyRemark}\n";
836 case DocSimpleSect::Attention:
837 m_t << "\n\\end{DoxyAttention}\n";
839 case DocSimpleSect::User:
840 m_t << "\n\\end{DoxyParagraph}\n";
842 case DocSimpleSect::Rcs:
843 m_t << "\n\\end{DoxyParagraph}\n";
850 void LatexDocVisitor::visitPre(DocTitle *)
854 void LatexDocVisitor::visitPost(DocTitle *)
861 void LatexDocVisitor::visitPre(DocSimpleList *)
864 m_t << "\\begin{DoxyItemize}" << endl;
867 void LatexDocVisitor::visitPost(DocSimpleList *)
870 m_t << "\\end{DoxyItemize}" << endl;
873 void LatexDocVisitor::visitPre(DocSimpleListItem *)
879 void LatexDocVisitor::visitPost(DocSimpleListItem *)
883 void LatexDocVisitor::visitPre(DocSection *s)
886 if (Config_getBool(PDF_HYPERLINKS))
888 m_t << "\\hypertarget{" << stripPath(s->file()) << "_" << s->anchor() << "}{}";
890 m_t << "\\" << getSectionName(s->level()) << "{";
891 filter(convertCharEntitiesToUTF8(s->title().data()));
892 m_t << "}\\label{" << stripPath(s->file()) << "_" << s->anchor() << "}" << endl;
895 void LatexDocVisitor::visitPost(DocSection *)
899 void LatexDocVisitor::visitPre(DocHtmlList *s)
902 if (s->type()==DocHtmlList::Ordered)
903 m_t << "\n\\begin{DoxyEnumerate}";
905 m_t << "\n\\begin{DoxyItemize}";
908 void LatexDocVisitor::visitPost(DocHtmlList *s)
911 if (s->type()==DocHtmlList::Ordered)
912 m_t << "\n\\end{DoxyEnumerate}";
914 m_t << "\n\\end{DoxyItemize}";
917 void LatexDocVisitor::visitPre(DocHtmlListItem *)
923 void LatexDocVisitor::visitPost(DocHtmlListItem *)
927 //void LatexDocVisitor::visitPre(DocHtmlPre *)
929 // m_t << "\\small\\begin{alltt}";
933 //void LatexDocVisitor::visitPost(DocHtmlPre *)
935 // m_insidePre=FALSE;
936 // m_t << "\\end{alltt}\\normalsize " << endl;
939 void LatexDocVisitor::visitPre(DocHtmlDescList *dl)
942 QCString val = dl->attribs().find("class");
945 m_t << "\n\\begin{DoxyRefList}";
949 m_t << "\n\\begin{DoxyDescription}";
953 void LatexDocVisitor::visitPost(DocHtmlDescList *dl)
956 QCString val = dl->attribs().find("class");
959 m_t << "\n\\end{DoxyRefList}";
963 m_t << "\n\\end{DoxyDescription}";
967 void LatexDocVisitor::visitPre(DocHtmlDescTitle *)
974 void LatexDocVisitor::visitPost(DocHtmlDescTitle *)
981 void LatexDocVisitor::visitPre(DocHtmlDescData *)
985 void LatexDocVisitor::visitPost(DocHtmlDescData *)
989 static bool tableIsNested(const DocNode *n)
992 while (n && !isNested)
994 isNested = n->kind()==DocNode::Kind_HtmlTable || n->kind()==DocNode::Kind_ParamSect;
1000 static void writeStartTableCommand(FTextStream &t,const DocNode *n,int cols)
1002 if (tableIsNested(n))
1004 t << "{\\begin{tabularx}{\\linewidth}{|*{" << cols << "}{>{\\raggedright\\arraybackslash}X|}}";
1008 t << "\\tabulinesep=1mm\n\\begin{longtabu}spread 0pt [c]{*{" << cols << "}{|X[-1]}|}\n";
1010 //return isNested ? "TabularNC" : "TabularC";
1013 static void writeEndTableCommand(FTextStream &t,const DocNode *n)
1015 if (tableIsNested(n))
1017 t << "\\end{tabularx}}\n";
1021 t << "\\end{longtabu}\n";
1023 //return isNested ? "TabularNC" : "TabularC";
1026 void LatexDocVisitor::visitPre(DocHtmlTable *t)
1030 if (t->hasCaption())
1032 DocHtmlCaption *c = t->caption();
1033 static bool pdfHyperLinks = Config_getBool(PDF_HYPERLINKS);
1034 if (!c->file().isEmpty() && pdfHyperLinks)
1036 m_t << "\\hypertarget{" << stripPath(c->file()) << "_" << c->anchor()
1042 writeStartTableCommand(m_t,t->parent(),t->numColumns());
1044 if (t->hasCaption())
1046 DocHtmlCaption *c = t->caption();
1047 m_t << "\\caption{";
1048 visitCaption(this, c->children());
1050 m_t << "\\label{" << stripPath(c->file()) << "_" << c->anchor() << "}";
1054 setNumCols(t->numColumns());
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())
1064 DocNode *n = t->parent();
1065 if (!tableIsNested(n)) firstRow->accept(this);
1070 void LatexDocVisitor::visitPost(DocHtmlTable *t)
1073 writeEndTableCommand(m_t,t->parent());
1077 void LatexDocVisitor::visitPre(DocHtmlCaption *c)
1079 m_hideCaption = m_hide;
1083 void LatexDocVisitor::visitPost(DocHtmlCaption *c)
1085 m_hide = m_hideCaption;
1088 void LatexDocVisitor::visitPre(DocHtmlRow *r)
1090 setCurrentColumn(0);
1093 void LatexDocVisitor::visitPost(DocHtmlRow *row)
1097 DocNode *n = row->parent() ->parent();
1099 int c=currentColumn();
1100 while (c<=numCols()) // end of row while inside a row span?
1103 for (i=0;i<rowSpans().count();i++)
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
1113 if (span->colSpan>1) // row span is also part of a column span
1115 m_t << "\\multicolumn{" << span->colSpan << "}{";
1118 else // solitary row span
1120 m_t << "\\multicolumn{1}{c|}{}";
1131 for (i=0;i<rowSpans().count();i++)
1133 ActiveRowSpan *span = rowSpans().at(i);
1134 if (span->rowSpan>0) span->rowSpan--;
1135 if (span->rowSpan<=0)
1139 else if (span->column>col)
1141 m_t << "\\cline{" << col << "-" << (span->column-1) << "}";
1142 col = span->column+span->colSpan;
1146 col = span->column+span->colSpan;
1150 if (col <= numCols())
1152 m_t << "\\cline{" << col << "-" << numCols() << "}";
1158 if (row->isHeading() && row->rowIndex()==1 && !tableIsNested(n))
1162 m_t << "\\endfirsthead" << endl;
1163 m_t << "\\hline" << endl;
1164 m_t << "\\endfoot" << endl;
1165 m_t << "\\hline" << endl;
1169 m_t << "\\endhead" << endl;
1174 void LatexDocVisitor::visitPre(DocHtmlCell *c)
1178 DocHtmlRow *row = 0;
1179 if (c->parent() && c->parent()->kind()==DocNode::Kind_HtmlRow)
1181 row = (DocHtmlRow*)c->parent();
1184 setCurrentColumn(currentColumn()+1);
1186 //Skip columns that span from above.
1188 for (i=0;i<rowSpans().count();i++)
1190 ActiveRowSpan *span = rowSpans().at(i);
1191 if (span->rowSpan>0 && span->column==currentColumn())
1193 if (row && span->colSpan>1)
1195 m_t << "\\multicolumn{" << span->colSpan << "}{";
1196 if (currentColumn() /*c->columnIndex()*/==1) // add extra | for first column
1200 m_t << "l|}{" << (c->isHeading()? "\\columncolor{\\tableheadbgcolor}" : "") << "}"; // alignment not relevant, empty column
1201 setCurrentColumn(currentColumn()+span->colSpan);
1205 setCurrentColumn(currentColumn()+1);
1211 int cs = c->colSpan();
1212 int a = c->alignment();
1216 m_t << "\\multicolumn{" << cs << "}{";
1217 if (c->columnIndex()==1) // add extra | for first column
1223 case DocHtmlCell::Right:
1226 case DocHtmlCell::Center:
1234 int rs = c->rowSpan();
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 << "}{*}{";
1244 if (a==DocHtmlCell::Center)
1246 m_t << "\\PBS\\centering ";
1248 else if (a==DocHtmlCell::Right)
1250 m_t << "\\PBS\\raggedleft ";
1254 m_t << "\\cellcolor{\\tableheadbgcolor}\\textbf{ ";
1258 setCurrentColumn(currentColumn()+cs-1);
1262 void LatexDocVisitor::visitPost(DocHtmlCell *c)
1271 setInRowSpan(FALSE);
1276 setInColSpan(FALSE);
1279 if (!c->isLast()) m_t << "&";
1282 void LatexDocVisitor::visitPre(DocInternal *)
1285 //m_t << "\\begin{DoxyInternal}{";
1286 //filter(theTranslator->trForInternalUseOnly());
1290 void LatexDocVisitor::visitPost(DocInternal *)
1293 //m_t << "\\end{DoxyInternal}" << endl;
1296 void LatexDocVisitor::visitPre(DocHRef *href)
1299 if (Config_getBool(PDF_HYPERLINKS))
1302 m_t << latexFilterURL(href->url());
1305 m_t << "{\\texttt{ ";
1308 void LatexDocVisitor::visitPost(DocHRef *)
1314 void LatexDocVisitor::visitPre(DocHtmlHeader *header)
1317 m_t << "\\" << getSectionName(header->level()) << "*{";
1320 void LatexDocVisitor::visitPost(DocHtmlHeader *)
1325 void LatexDocVisitor::visitPre(DocImage *img)
1327 if (img->type()==DocImage::Latex)
1330 QCString gfxName = img->name();
1331 if (gfxName.right(4)==".eps" || gfxName.right(4)==".pdf")
1333 gfxName=gfxName.left(gfxName.length()-4);
1336 visitPreStart(m_t,img->hasCaption(), gfxName, img->width(), img->height(), img->isInlineImage());
1338 else // other format -> skip
1345 void LatexDocVisitor::visitPost(DocImage *img)
1347 if (img->type()==DocImage::Latex)
1350 visitPostEnd(m_t,img->hasCaption(), img->isInlineImage());
1352 else // other format
1358 void LatexDocVisitor::visitPre(DocDotFile *df)
1361 startDotFile(df->file(),df->width(),df->height(),df->hasCaption());
1364 void LatexDocVisitor::visitPost(DocDotFile *df)
1367 endDotFile(df->hasCaption());
1369 void LatexDocVisitor::visitPre(DocMscFile *df)
1372 startMscFile(df->file(),df->width(),df->height(),df->hasCaption());
1375 void LatexDocVisitor::visitPost(DocMscFile *df)
1378 endMscFile(df->hasCaption());
1381 void LatexDocVisitor::visitPre(DocDiaFile *df)
1384 startDiaFile(df->file(),df->width(),df->height(),df->hasCaption());
1387 void LatexDocVisitor::visitPost(DocDiaFile *df)
1390 endDiaFile(df->hasCaption());
1392 void LatexDocVisitor::visitPre(DocLink *lnk)
1395 startLink(lnk->ref(),lnk->file(),lnk->anchor());
1398 void LatexDocVisitor::visitPost(DocLink *lnk)
1401 endLink(lnk->ref(),lnk->file(),lnk->anchor());
1404 void LatexDocVisitor::visitPre(DocRef *ref)
1407 // when ref->isSubPage()==TRUE we use ref->file() for HTML and
1408 // ref->anchor() for LaTeX/RTF
1409 if (ref->isSubPage())
1411 startLink(ref->ref(),0,ref->anchor());
1415 if (!ref->file().isEmpty()) startLink(ref->ref(),ref->file(),ref->anchor(),ref->refToTable());
1417 if (!ref->hasLinkText()) filter(ref->targetTitle());
1420 void LatexDocVisitor::visitPost(DocRef *ref)
1423 if (ref->isSubPage())
1425 endLink(ref->ref(),0,ref->anchor());
1429 if (!ref->file().isEmpty()) endLink(ref->ref(),ref->file(),ref->anchor(),ref->refToTable());
1433 void LatexDocVisitor::visitPre(DocSecRefItem *ref)
1436 m_t << "\\item \\contentsline{section}{";
1437 static bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS);
1440 m_t << "\\mbox{\\hyperlink{" << ref->file() << "_" << ref->anchor() << "}{" ;
1444 void LatexDocVisitor::visitPost(DocSecRefItem *ref)
1447 static bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS);
1452 m_t << "}{\\ref{" << ref->file() << "_" << ref->anchor() << "}}{}" << endl;
1455 void LatexDocVisitor::visitPre(DocSecRefList *)
1458 m_t << "\\footnotesize" << endl;
1459 m_t << "\\begin{multicols}{2}" << endl;
1460 m_t << "\\begin{DoxyCompactList}" << endl;
1463 void LatexDocVisitor::visitPost(DocSecRefList *)
1466 m_t << "\\end{DoxyCompactList}" << endl;
1467 m_t << "\\end{multicols}" << endl;
1468 m_t << "\\normalsize" << endl;
1471 void LatexDocVisitor::visitPre(DocParamSect *s)
1474 bool hasInOutSpecs = s->hasInOutSpecifier();
1475 bool hasTypeSpecs = s->hasTypeSpecifier();
1476 incUsedTableLevels();
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
1484 filter(theTranslator->trParameters());
1486 case DocParamSect::RetVal:
1487 m_t << "\n\\begin{DoxyRetVals}{";
1488 filter(theTranslator->trReturnValues());
1490 case DocParamSect::Exception:
1491 m_t << "\n\\begin{DoxyExceptions}{";
1492 filter(theTranslator->trExceptions());
1494 case DocParamSect::TemplateParam:
1495 m_t << "\n\\begin{DoxyTemplParams}{";
1496 filter(theTranslator->trTemplateParameters());
1504 void LatexDocVisitor::visitPost(DocParamSect *s)
1507 decUsedTableLevels();
1510 case DocParamSect::Param:
1511 m_t << "\\end{DoxyParams}\n";
1513 case DocParamSect::RetVal:
1514 m_t << "\\end{DoxyRetVals}\n";
1516 case DocParamSect::Exception:
1517 m_t << "\\end{DoxyExceptions}\n";
1519 case DocParamSect::TemplateParam:
1520 m_t << "\\end{DoxyTemplParams}\n";
1527 void LatexDocVisitor::visitPre(DocParamList *pl)
1530 DocParamSect::Type parentType = DocParamSect::Unknown;
1531 DocParamSect *sect = 0;
1532 if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect)
1534 parentType = ((DocParamSect*)pl->parent())->type();
1535 sect=(DocParamSect*)pl->parent();
1537 bool useTable = parentType==DocParamSect::Param ||
1538 parentType==DocParamSect::RetVal ||
1539 parentType==DocParamSect::Exception ||
1540 parentType==DocParamSect::TemplateParam;
1545 if (sect && sect->hasInOutSpecifier())
1547 if (pl->direction()!=DocParamSect::Unspecified)
1549 m_t << "\\mbox{\\texttt{ ";
1550 if (pl->direction()==DocParamSect::In)
1554 else if (pl->direction()==DocParamSect::Out)
1558 else if (pl->direction()==DocParamSect::InOut)
1564 if (useTable) m_t << " & ";
1566 if (sect && sect->hasTypeSpecifier())
1568 QListIterator<DocNode> li(pl->paramTypes());
1571 for (li.toFirst();(type=li.current());++li)
1573 if (!first) m_t << " | "; else first=FALSE;
1574 if (type->kind()==DocNode::Kind_Word)
1576 visit((DocWord*)type);
1578 else if (type->kind()==DocNode::Kind_LinkedWord)
1580 visit((DocLinkedWord*)type);
1583 if (useTable) m_t << " & ";
1586 //QStrListIterator li(pl->parameters());
1588 QListIterator<DocNode> li(pl->parameters());
1591 for (li.toFirst();(param=li.current());++li)
1593 if (!first) m_t << ","; else first=FALSE;
1595 if (param->kind()==DocNode::Kind_Word)
1597 visit((DocWord*)param);
1599 else if (param->kind()==DocNode::Kind_LinkedWord)
1601 visit((DocLinkedWord*)param);
1616 void LatexDocVisitor::visitPost(DocParamList *pl)
1619 DocParamSect::Type parentType = DocParamSect::Unknown;
1620 if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect)
1622 parentType = ((DocParamSect*)pl->parent())->type();
1624 bool useTable = parentType==DocParamSect::Param ||
1625 parentType==DocParamSect::RetVal ||
1626 parentType==DocParamSect::Exception ||
1627 parentType==DocParamSect::TemplateParam;
1630 m_t << "\\\\" << endl
1631 << "\\hline" << endl;
1635 void LatexDocVisitor::visitPre(DocXRefItem *x)
1637 static bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS);
1639 if (x->title().isEmpty()) return;
1640 m_t << "\\begin{DoxyRefDesc}{";
1643 bool anonymousEnum = x->file()=="@";
1645 if (pdfHyperlinks && !anonymousEnum)
1647 m_t << "\\mbox{\\hyperlink{" << stripPath(x->file()) << "_" << x->anchor() << "}{";
1651 m_t << "\\textbf{ ";
1656 if (pdfHyperlinks && !anonymousEnum)
1663 void LatexDocVisitor::visitPost(DocXRefItem *x)
1666 if (x->title().isEmpty()) return;
1667 m_t << "\\end{DoxyRefDesc}" << endl;
1670 void LatexDocVisitor::visitPre(DocInternalRef *ref)
1673 startLink(0,ref->file(),ref->anchor());
1676 void LatexDocVisitor::visitPost(DocInternalRef *ref)
1679 endLink(0,ref->file(),ref->anchor());
1682 void LatexDocVisitor::visitPre(DocCopy *)
1686 void LatexDocVisitor::visitPost(DocCopy *)
1690 void LatexDocVisitor::visitPre(DocText *)
1694 void LatexDocVisitor::visitPost(DocText *)
1698 void LatexDocVisitor::visitPre(DocHtmlBlockQuote *)
1701 m_t << "\\begin{quote}" << endl;
1704 void LatexDocVisitor::visitPost(DocHtmlBlockQuote *)
1707 m_t << "\\end{quote}" << endl;
1710 void LatexDocVisitor::visitPre(DocVhdlFlow *)
1715 void LatexDocVisitor::visitPost(DocVhdlFlow *)
1720 void LatexDocVisitor::visitPre(DocParBlock *)
1725 void LatexDocVisitor::visitPost(DocParBlock *)
1730 void LatexDocVisitor::filter(const char *str)
1732 filterLatexString(m_t,str,m_insideTabbing,m_insidePre,m_insideItem);
1735 void LatexDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor,bool refToTable)
1737 static bool pdfHyperLinks = Config_getBool(PDF_HYPERLINKS);
1738 if (ref.isEmpty() && pdfHyperLinks) // internal PDF link
1742 m_t << "\\doxytablelink{";
1746 m_t << "\\mbox{\\hyperlink{";
1748 if (!file.isEmpty()) m_t << stripPath(file);
1749 if (!file.isEmpty() && !anchor.isEmpty()) m_t << "_";
1750 if (!anchor.isEmpty()) m_t << anchor;
1753 else if (ref.isEmpty() && refToTable)
1755 m_t << "\\doxytableref{";
1757 else if (ref.isEmpty()) // internal non-PDF link
1759 m_t << "\\doxyref{";
1761 else // external link
1763 m_t << "\\textbf{ ";
1767 void LatexDocVisitor::endLink(const QCString &ref,const QCString &file,const QCString &anchor,bool refToTable)
1770 static bool pdfHyperLinks = Config_getBool(PDF_HYPERLINKS);
1771 if (ref.isEmpty() && !pdfHyperLinks)
1774 filter(theTranslator->trPageAbbreviation());
1775 m_t << "}{" << file;
1776 if (!file.isEmpty() && !anchor.isEmpty()) m_t << "_";
1777 m_t << anchor << "}";
1779 if (ref.isEmpty() && pdfHyperLinks) // internal PDF link
1788 void LatexDocVisitor::pushEnabled()
1790 m_enabled.push(new bool(m_hide));
1793 void LatexDocVisitor::popEnabled()
1795 bool *v=m_enabled.pop();
1801 void LatexDocVisitor::startDotFile(const QCString &fileName,
1802 const QCString &width,
1803 const QCString &height,
1807 QCString baseName=fileName;
1809 if ((i=baseName.findRev('/'))!=-1)
1811 baseName=baseName.right(baseName.length()-i-1);
1813 if ((i=baseName.find('.'))!=-1)
1815 baseName=baseName.left(i);
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);
1824 void LatexDocVisitor::endDotFile(bool hasCaption)
1827 visitPostEnd(m_t,hasCaption);
1830 void LatexDocVisitor::startMscFile(const QCString &fileName,
1831 const QCString &width,
1832 const QCString &height,
1836 QCString baseName=fileName;
1838 if ((i=baseName.findRev('/'))!=-1)
1840 baseName=baseName.right(baseName.length()-i-1);
1842 if ((i=baseName.find('.'))!=-1)
1844 baseName=baseName.left(i);
1846 baseName.prepend("msc_");
1848 QCString outDir = Config_getString(LATEX_OUTPUT);
1849 writeMscGraphFromFile(fileName,outDir,baseName,MSC_EPS);
1850 visitPreStart(m_t,hasCaption, baseName, width, height);
1853 void LatexDocVisitor::endMscFile(bool hasCaption)
1856 visitPostEnd(m_t,hasCaption);
1860 void LatexDocVisitor::writeMscFile(const QCString &baseName, DocVerbatim *s)
1862 QCString shortName = baseName;
1864 if ((i=shortName.findRev('/'))!=-1)
1866 shortName=shortName.right(shortName.length()-i-1);
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());
1876 void LatexDocVisitor::startDiaFile(const QCString &fileName,
1877 const QCString &width,
1878 const QCString &height,
1882 QCString baseName=fileName;
1884 if ((i=baseName.findRev('/'))!=-1)
1886 baseName=baseName.right(baseName.length()-i-1);
1888 if ((i=baseName.find('.'))!=-1)
1890 baseName=baseName.left(i);
1892 baseName.prepend("dia_");
1894 QCString outDir = Config_getString(LATEX_OUTPUT);
1895 writeDiaGraphFromFile(fileName,outDir,baseName,DIA_EPS);
1896 visitPreStart(m_t,hasCaption, baseName, width, height);
1899 void LatexDocVisitor::endDiaFile(bool hasCaption)
1902 visitPostEnd(m_t,hasCaption);
1906 void LatexDocVisitor::writeDiaFile(const QCString &baseName, DocVerbatim *s)
1908 QCString shortName = baseName;
1910 if ((i=shortName.findRev('/'))!=-1)
1912 shortName=shortName.right(shortName.length()-i-1);
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());
1921 void LatexDocVisitor::writePlantUMLFile(const QCString &baseName, DocVerbatim *s)
1923 QCString shortName = baseName;
1925 if ((i=shortName.findRev('/'))!=-1)
1927 shortName=shortName.right(shortName.length()-i-1);
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());