diff options
Diffstat (limited to 'src/latexgen.cpp')
-rw-r--r-- | src/latexgen.cpp | 1110 |
1 files changed, 782 insertions, 328 deletions
diff --git a/src/latexgen.cpp b/src/latexgen.cpp index c5f436c..f68c85a 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -14,7 +14,6 @@ */ #include <cstdlib> -#include <sstream> #include "latexgen.h" #include "config.h" @@ -44,16 +43,23 @@ #include "portable.h" #include "fileinfo.h" #include "utf8.h" +#include "datetime.h" +#include "portable.h" +#include "outputlist.h" +#include "moduledef.h" static QCString g_header; static QCString g_footer; +static const SelectionMarkerInfo latexMarkerInfo = { '%', "%%BEGIN ",8 ,"%%END ",6, "",0 }; + +static QCString substituteLatexKeywords(const QCString &str, const QCString &title); -LatexCodeGenerator::LatexCodeGenerator(TextStream &t,const QCString &relPath,const QCString &sourceFileName) +LatexCodeGenerator::LatexCodeGenerator(TextStream *t,const QCString &relPath,const QCString &sourceFileName) : m_t(t), m_relPath(relPath), m_sourceFileName(sourceFileName) { } -LatexCodeGenerator::LatexCodeGenerator(TextStream &t) : m_t(t) +LatexCodeGenerator::LatexCodeGenerator(TextStream *t) : m_t(t) { } @@ -85,21 +91,25 @@ void LatexCodeGenerator::codify(const QCString &str) { case 0x0c: p++; // remove ^L break; - case ' ': m_t <<" "; + case ' ': *m_t << (m_doxyCodeLineOpen ? "\\ " : " "); + m_col++; + p++; + break; + case '^': *m_t <<"\\string^"; m_col++; p++; break; - case '^': m_t <<"\\string^"; + case '`': *m_t <<"\\`{}"; m_col++; p++; break; case '\t': spacesToNextTabStop = tabSize - (m_col%tabSize); - for (i = 0; i < spacesToNextTabStop; i++) m_t <<" "; + for (i = 0; i < spacesToNextTabStop; i++) *m_t << (m_doxyCodeLineOpen ? "\\ " : " "); m_col+=spacesToNextTabStop; p++; break; - case '\n': m_t << '\n'; + case '\n': *m_t << '\n'; m_col=0; p++; break; @@ -131,8 +141,8 @@ void LatexCodeGenerator::codify(const QCString &str) COPYCHAR(); } result[i]=0; // add terminator - filterLatexString(m_t,result, - false, // insideTabbing + filterLatexString(*m_t,result, + m_insideTabbing, // insideTabbing true, // insidePre false, // insideItem m_usedTableLevel>0, // insideTable @@ -152,16 +162,16 @@ void LatexCodeGenerator::writeCodeLink(CodeSymbolType, { bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); bool usePDFLatex = Config_getBool(USE_PDFLATEX); - uint l = name.length(); + uint32_t l = name.length(); if (ref.isEmpty() && usePDFLatex && pdfHyperlinks) { - m_t << "\\mbox{\\hyperlink{"; - if (!f.isEmpty()) m_t << stripPath(f); - if (!f.isEmpty() && !anchor.isEmpty()) m_t << "_"; - if (!anchor.isEmpty()) m_t << anchor; - m_t << "}{"; + *m_t << "\\mbox{\\hyperlink{"; + if (!f.isEmpty()) *m_t << stripPath(f); + if (!f.isEmpty() && !anchor.isEmpty()) *m_t << "_"; + if (!anchor.isEmpty()) *m_t << anchor; + *m_t << "}{"; codify(name); - m_t << "}}"; + *m_t << "}}"; } else { @@ -176,7 +186,7 @@ void LatexCodeGenerator::writeLineNumber(const QCString &ref,const QCString &fil bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); if (!m_doxyCodeLineOpen) { - m_t << "\\DoxyCodeLine{"; + *m_t << "\\DoxyCodeLine{"; m_doxyCodeLineOpen = TRUE; } if (Config_getBool(SOURCE_BROWSER)) @@ -193,7 +203,7 @@ void LatexCodeGenerator::writeLineNumber(const QCString &ref,const QCString &fil bool showTarget = usePDFLatex && pdfHyperlinks && !lineAnchor.isEmpty() && writeLineAnchor; if (showTarget) { - m_t << "\\Hypertarget{" << stripPath(lineAnchor) << "}"; + *m_t << "\\Hypertarget{" << stripPath(lineAnchor) << "}"; } if (!fileName.isEmpty()) { @@ -203,11 +213,14 @@ void LatexCodeGenerator::writeLineNumber(const QCString &ref,const QCString &fil { codify(lineNumber); } - m_t << " "; + *m_t << "\\ "; } else { - m_t << l << " "; + QCString lineNumber; + lineNumber.sprintf("%05d",l); + codify(lineNumber); + *m_t << "\\ "; } m_col=0; } @@ -218,7 +231,7 @@ void LatexCodeGenerator::startCodeLine(bool) m_col=0; if (!m_doxyCodeLineOpen) { - m_t << "\\DoxyCodeLine{"; + *m_t << "\\DoxyCodeLine{"; m_doxyCodeLineOpen = TRUE; } } @@ -227,7 +240,7 @@ void LatexCodeGenerator::endCodeLine() { if (m_doxyCodeLineOpen) { - m_t << "}"; + *m_t << "}"; m_doxyCodeLineOpen = FALSE; } codify("\n"); @@ -235,17 +248,17 @@ void LatexCodeGenerator::endCodeLine() void LatexCodeGenerator::startFontClass(const QCString &name) { - m_t << "\\textcolor{" << name << "}{"; + *m_t << "\\textcolor{" << name << "}{"; } void LatexCodeGenerator::endFontClass() { - m_t << "}"; + *m_t << "}"; } void LatexCodeGenerator::startCodeFragment(const QCString &style) { - m_t << "\n\\begin{" << style << "}{" << m_usedTableLevel << "}\n"; + *m_t << "\n\\begin{" << style << "}{" << m_usedTableLevel << "}\n"; } void LatexCodeGenerator::endCodeFragment(const QCString &style) @@ -253,41 +266,78 @@ void LatexCodeGenerator::endCodeFragment(const QCString &style) //endCodeLine checks is there is still an open code line, if so closes it. endCodeLine(); - m_t << "\\end{" << style << "}\n"; + *m_t << "\\end{" << style << "}\n"; } //------------------------------- -LatexGenerator::LatexGenerator() : OutputGenerator(Config_getString(LATEX_OUTPUT)), m_codeGen(m_t) +LatexGenerator::LatexGenerator() + : OutputGenerator(Config_getString(LATEX_OUTPUT)) + , m_codeList(std::make_unique<OutputCodeList>()) { - //printf("LatexGenerator::LatexGenerator() m_insideTabbing=FALSE\n"); + m_codeGen = m_codeList->add<LatexCodeGenerator>(&m_t); } -LatexGenerator::LatexGenerator(const LatexGenerator &og) : OutputGenerator(og), m_codeGen(m_t) +LatexGenerator::LatexGenerator(const LatexGenerator &og) : OutputGenerator(og.m_dir) { + m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList); + m_codeGen = m_codeList->get<LatexCodeGenerator>(); + m_codeGen->setTextStream(&m_t); + m_firstDescItem = og.m_firstDescItem; + m_disableLinks = og.m_disableLinks; + m_relPath = og.m_relPath; + m_indent = og.m_indent; + m_templateMemberItem = og.m_templateMemberItem; + m_hierarchyLevel = og.m_hierarchyLevel; } LatexGenerator &LatexGenerator::operator=(const LatexGenerator &og) { - OutputGenerator::operator=(og); + if (this!=&og) + { + m_dir = og.m_dir; + m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList); + m_codeGen = m_codeList->get<LatexCodeGenerator>(); + m_codeGen->setTextStream(&m_t); + m_firstDescItem = og.m_firstDescItem; + m_disableLinks = og.m_disableLinks; + m_relPath = og.m_relPath; + m_indent = og.m_indent; + m_templateMemberItem = og.m_templateMemberItem; + m_hierarchyLevel = og.m_hierarchyLevel; + } return *this; } -std::unique_ptr<OutputGenerator> LatexGenerator::clone() const +LatexGenerator::LatexGenerator(LatexGenerator &&og) + : OutputGenerator(std::move(og)) { - return std::make_unique<LatexGenerator>(*this); + m_codeList = std::exchange(og.m_codeList,std::unique_ptr<OutputCodeList>()); + m_codeGen = m_codeList->get<LatexCodeGenerator>(); + m_codeGen->setTextStream(&m_t); + m_firstDescItem = std::exchange(og.m_firstDescItem,true); + m_disableLinks = std::exchange(og.m_disableLinks,false); + m_relPath = std::exchange(og.m_relPath,QCString()); + m_indent = std::exchange(og.m_indent,0); + m_templateMemberItem = std::exchange(og.m_templateMemberItem,false); + m_hierarchyLevel = og.m_hierarchyLevel; } LatexGenerator::~LatexGenerator() { } +void LatexGenerator::addCodeGen(OutputCodeList &list) +{ + list.add(OutputCodeList::OutputCodeVariant(LatexCodeGeneratorDefer(m_codeGen))); +} + static void writeLatexMakefile() { bool generateBib = !CitationManager::instance().isEmpty(); QCString fileName=Config_getString(LATEX_OUTPUT)+"/Makefile"; - std::ofstream f(fileName.str(),std::ofstream::out | std::ofstream::binary); + std::ofstream f = Portable::openOutputStream(fileName); if (!f.is_open()) { term("Could not open file %s for writing\n",qPrint(fileName)); @@ -338,7 +388,7 @@ static void writeLatexMakefile() t << "\techo \"Rerunning latex....\"\n" << "\t$(LATEX_CMD) $(MANUAL_FILE).tex\n" << "\tlatex_count=$(LATEX_COUNT) ; \\\n" - << "\twhile egrep -s 'Rerun (LaTeX|to get cross-references right|to get bibliographical references right)' $(MANUAL_FILE).log && [ $$latex_count -gt 0 ] ;\\\n" + << "\twhile grep -E -s 'Rerun (LaTeX|to get cross-references right|to get bibliographical references right)' $(MANUAL_FILE).log && [ $$latex_count -gt 0 ] ;\\\n" << "\t do \\\n" << "\t echo \"Rerunning latex....\" ;\\\n" << "\t $(LATEX_CMD) $(MANUAL_FILE).tex ; \\\n" @@ -366,7 +416,7 @@ static void writeLatexMakefile() } t << "\t$(LATEX_CMD) $(MANUAL_FILE)\n" << "\tlatex_count=$(LATEX_COUNT) ; \\\n" - << "\twhile egrep -s 'Rerun (LaTeX|to get cross-references right|to get bibliographical references right)' $(MANUAL_FILE).log && [ $$latex_count -gt 0 ] ;\\\n" + << "\twhile grep -E -s 'Rerun (LaTeX|to get cross-references right|to get bibliographical references right)' $(MANUAL_FILE).log && [ $$latex_count -gt 0 ] ;\\\n" << "\t do \\\n" << "\t echo \"Rerunning latex....\" ;\\\n" << "\t $(LATEX_CMD) $(MANUAL_FILE) ;\\\n" @@ -393,13 +443,13 @@ static void writeMakeBat() QCString manual_file = "refman"; const int latex_count = 8; bool generateBib = !CitationManager::instance().isEmpty(); - std::ofstream t(fileName.str(),std::ofstream::out | std::ofstream::binary); + std::ofstream t = Portable::openOutputStream(fileName); if (!t.is_open()) { term("Could not open file %s for writing\n",qPrint(fileName)); } - t << "set Dir_Old=%cd%\r\n"; - t << "cd /D %~dp0\r\n\r\n"; + t << "pushd %~dp0\r\n"; + t << "if not %errorlevel% == 0 goto :end\r\n"; t << "\r\n"; t << "set ORG_LATEX_CMD=%LATEX_CMD%\r\n"; t << "set ORG_MKIDX_CMD=%MKIDX_CMD%\r\n"; @@ -479,8 +529,7 @@ static void writeMakeBat() } t<< "\r\n"; t<< "@REM reset environment\r\n"; - t<< "cd /D %Dir_Old%\r\n"; - t<< "set Dir_Old=\r\n"; + t<< "popd\r\n"; t<< "set LATEX_CMD=%ORG_LATEX_CMD%\r\n"; t<< "set ORG_LATEX_CMD=\r\n"; t<< "set MKIDX_CMD=%ORG_MKIDX_CMD%\r\n"; @@ -491,6 +540,8 @@ static void writeMakeBat() t<< "set ORG_MANUAL_FILE=\r\n"; t<< "set LATEX_COUNT=%ORG_LATEX_COUNT%\r\n"; t<< "set ORG_LATEX_COUNT=\r\n"; + t<< "\r\n"; + t<< ":end\r\n"; #endif } @@ -507,19 +558,27 @@ void LatexGenerator::init() { g_header=fileToString(Config_getString(LATEX_HEADER)); //printf("g_header='%s'\n",qPrint(g_header)); + QCString result = substituteLatexKeywords(g_header,QCString()); + checkBlocks(result,Config_getString(LATEX_HEADER),latexMarkerInfo); } else { g_header = ResourceMgr::instance().getAsString("header.tex"); + QCString result = substituteLatexKeywords(g_header,QCString()); + checkBlocks(result,"<default header.tex>",latexMarkerInfo); } if (!Config_getString(LATEX_FOOTER).isEmpty()) { g_footer=fileToString(Config_getString(LATEX_FOOTER)); //printf("g_footer='%s'\n",qPrint(g_footer)); + QCString result = substituteLatexKeywords(g_footer,QCString()); + checkBlocks(result,Config_getString(LATEX_FOOTER),latexMarkerInfo); } else { g_footer = ResourceMgr::instance().getAsString("footer.tex"); + QCString result = substituteLatexKeywords(g_footer,QCString()); + checkBlocks(result,"<default footer.tex>",latexMarkerInfo); } writeLatexMakefile(); @@ -558,23 +617,24 @@ void LatexGenerator::writeStyleSheetFile(TextStream &t) writeDefaultStyleSheet(t); } -void LatexGenerator::startFile(const QCString &name,const QCString &,const QCString &,int) +void LatexGenerator::startFile(const QCString &name,const QCString &,const QCString &,int,int hierarchyLevel) { #if 0 setEncoding(Config_getString(LATEX_OUTPUT_ENCODING)); #endif QCString fileName=name; + m_hierarchyLevel = hierarchyLevel; m_relPath = relativePathToRoot(fileName); if (!fileName.endsWith(".tex") && !fileName.endsWith(".sty")) fileName+=".tex"; startPlainFile(fileName); - m_codeGen.setRelativePath(m_relPath); - m_codeGen.setSourceFileName(stripPath(fileName)); + m_codeGen->setRelativePath(m_relPath); + m_codeGen->setSourceFileName(stripPath(fileName)); } void LatexGenerator::endFile() { endPlainFile(); - m_codeGen.setSourceFileName(""); + m_codeGen->setSourceFileName(""); } //void LatexGenerator::writeIndex() @@ -633,13 +693,26 @@ static QCString makeIndex() return result; } +static QCString latex_batchmode() +{ + switch (Config_getEnum(LATEX_BATCHMODE)) + { + case LATEX_BATCHMODE_t::NO: return ""; + case LATEX_BATCHMODE_t::YES: return "\\batchmode"; + case LATEX_BATCHMODE_t::BATCH: return "\\batchmode"; + case LATEX_BATCHMODE_t::NON_STOP: return "\\nonstopmode"; + case LATEX_BATCHMODE_t::SCROLL: return "\\scrollmode"; + case LATEX_BATCHMODE_t::ERROR_STOP: return "\\errorstopmode"; + } + return ""; +} + static QCString substituteLatexKeywords(const QCString &str, const QCString &title) { bool compactLatex = Config_getBool(COMPACT_LATEX); bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); bool usePdfLatex = Config_getBool(USE_PDFLATEX); - bool latexBatchmode = Config_getBool(LATEX_BATCHMODE); QCString paperType = Config_getEnumAsString(PAPER_TYPE); QCString style = Config_getString(LATEX_BIB_STYLE); @@ -649,16 +722,22 @@ static QCString substituteLatexKeywords(const QCString &str, } TextStream tg; - bool timeStamp = Config_getBool(LATEX_TIMESTAMP); QCString generatedBy; - if (timeStamp) - { - generatedBy = theTranslator->trGeneratedAt(dateToString(TRUE).data(), - Config_getString(PROJECT_NAME).data()); - } - else + auto timeStamp = Config_getEnum(TIMESTAMP); + switch (timeStamp) { - generatedBy = theTranslator->trGeneratedBy(); + case TIMESTAMP_t::YES: + case TIMESTAMP_t::DATETIME: + generatedBy = theTranslator->trGeneratedAt(dateToString(DateTimeType::DateTime), + Config_getString(PROJECT_NAME)); + break; + case TIMESTAMP_t::DATE: + generatedBy = theTranslator->trGeneratedAt(dateToString(DateTimeType::Date), + Config_getString(PROJECT_NAME)); + break; + case TIMESTAMP_t::NO: + generatedBy = theTranslator->trGeneratedBy(); + break; } filterLatexString(tg, generatedBy, false, // insideTabbing @@ -697,117 +776,140 @@ static QCString substituteLatexKeywords(const QCString &str, // first substitute generic keywords QCString result = substituteKeywords(str,title, - convertToLaTeX(Config_getString(PROJECT_NAME)), - convertToLaTeX(projectNumber), - convertToLaTeX(Config_getString(PROJECT_BRIEF))); + convertToLaTeX(Config_getString(PROJECT_NAME),false), + convertToLaTeX(projectNumber,false), + convertToLaTeX(Config_getString(PROJECT_BRIEF),false)); // additional LaTeX only keywords - result = substitute(result,"$latexdocumentpre",theTranslator->latexDocumentPre()); - result = substitute(result,"$latexdocumentpost",theTranslator->latexDocumentPost()); - result = substitute(result,"$generatedby",generatedBy); - result = substitute(result,"$latexbibstyle",style); - result = substitute(result,"$latexcitereference",theTranslator->trCiteReferences()); - result = substitute(result,"$latexbibfiles",CitationManager::instance().latexBibFiles()); - result = substitute(result,"$papertype",paperType+"paper"); - result = substitute(result,"$extralatexstylesheet",extraLatexStyleSheet()); - result = substitute(result,"$languagesupport",theTranslator->latexLanguageSupportCommand()); - result = substitute(result,"$latexfontenc",latexFontenc); - result = substitute(result,"$latexfont",theTranslator->latexFont()); - result = substitute(result,"$latexemojidirectory",latexEmojiDirectory); - result = substitute(result,"$makeindex",makeIndex()); - result = substitute(result,"$extralatexpackages",extraLatexPackages); - result = substitute(result,"$latexspecialformulachars",latexSpecialFormulaChars); - result = substitute(result,"$formulamacrofile",stripMacroFile); - - // additional LaTeX only conditional blocks - result = selectBlock(result,"CITATIONS_PRESENT", !CitationManager::instance().isEmpty(),OutputGenerator::Latex); - result = selectBlock(result,"COMPACT_LATEX",compactLatex,OutputGenerator::Latex); - result = selectBlock(result,"PDF_HYPERLINKS",pdfHyperlinks,OutputGenerator::Latex); - result = selectBlock(result,"USE_PDFLATEX",usePdfLatex,OutputGenerator::Latex); - result = selectBlock(result,"LATEX_TIMESTAMP",timeStamp,OutputGenerator::Latex); - result = selectBlock(result,"LATEX_BATCHMODE",latexBatchmode,OutputGenerator::Latex); - result = selectBlock(result,"LATEX_FONTENC",!latexFontenc.isEmpty(),OutputGenerator::Latex); - result = selectBlock(result,"FORMULA_MACROFILE",!formulaMacrofile.isEmpty(),OutputGenerator::Latex); - result = selectBlock(result,"PROJECT_NUMBER",!projectNumber.isEmpty(),OutputGenerator::Latex); + result = substituteKeywords(result, + { + // keyword value getter + { "$latexdocumentpre", [&]() { return theTranslator->latexDocumentPre(); } }, + { "$latexdocumentpost", [&]() { return theTranslator->latexDocumentPost(); } }, + { "$generatedby", [&]() { return generatedBy; } }, + { "$latexbibstyle", [&]() { return style; } }, + { "$latexcitereference", [&]() { return theTranslator->trCiteReferences(); } }, + { "$latexbibfiles", [&]() { return CitationManager::instance().latexBibFiles(); } }, + { "$papertype", [&]() { return paperType+"paper"; } }, + { "$extralatexstylesheet", [&]() { return extraLatexStyleSheet(); } }, + { "$languagesupport", [&]() { return theTranslator->latexLanguageSupportCommand(); } }, + { "$latexfontenc", [&]() { return latexFontenc; } }, + { "$latexfont", [&]() { return theTranslator->latexFont(); } }, + { "$latexemojidirectory", [&]() { return latexEmojiDirectory; } }, + { "$makeindex", [&]() { return makeIndex(); } }, + { "$extralatexpackages", [&]() { return extraLatexPackages; } }, + { "$latexspecialformulachars", [&]() { return latexSpecialFormulaChars; } }, + { "$formulamacrofile", [&]() { return stripMacroFile; } }, + { "$latex_batchmode", [&]() { return latex_batchmode(); } } + }); + + // remove conditional blocks + result = selectBlocks(result, + { + // marker is enabled + { "CITATIONS_PRESENT", !CitationManager::instance().isEmpty() }, + { "COMPACT_LATEX", compactLatex }, + { "PDF_HYPERLINKS", pdfHyperlinks }, + { "USE_PDFLATEX", usePdfLatex }, + { "TIMESTAMP", timeStamp!=TIMESTAMP_t::NO }, + { "LATEX_FONTENC", !latexFontenc.isEmpty() }, + { "FORMULA_MACROFILE", !formulaMacrofile.isEmpty() }, + { "PROJECT_NUMBER", !projectNumber.isEmpty() } + },latexMarkerInfo); result = removeEmptyLines(result); return result; } -void LatexGenerator::startIndexSection(IndexSections is) +void LatexGenerator::startIndexSection(IndexSection is) { bool compactLatex = Config_getBool(COMPACT_LATEX); switch (is) { - case isTitlePageStart: - m_t << substituteLatexKeywords(g_header,convertToLaTeX(Config_getString(PROJECT_NAME))); + case IndexSection::isTitlePageStart: + m_t << substituteLatexKeywords(g_header,convertToLaTeX(Config_getString(PROJECT_NAME),m_codeGen->insideTabbing())); break; - case isTitlePageAuthor: + case IndexSection::isTitlePageAuthor: break; - case isMainPage: - if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; - m_t << "{"; //Introduction}\n" + case IndexSection::isMainPage: break; - case isModuleIndex: + case IndexSection::isModuleIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Module Index}\n" break; - case isDirIndex: + case IndexSection::isTopicIndex: + if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; + m_t << "{"; //Topic Index}\n" + break; + case IndexSection::isDirIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Directory Index}\n" break; - case isNamespaceIndex: + case IndexSection::isNamespaceIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Namespace Index}\n" break; - case isConceptIndex: + case IndexSection::isConceptIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Concept Index}\n" break; - case isClassHierarchyIndex: + case IndexSection::isClassHierarchyIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Hierarchical Index}\n" break; - case isCompoundIndex: + case IndexSection::isCompoundIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Annotated Compound Index}\n" break; - case isFileIndex: + case IndexSection::isFileIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Annotated File Index}\n" break; - case isPageIndex: + case IndexSection::isPageIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Annotated Page Index}\n" break; - case isModuleDocumentation: + case IndexSection::isTopicDocumentation: { for (const auto &gd : *Doxygen::groupLinkedMap) { if (!gd->isReference()) { if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; - m_t << "{"; //Module Documentation}\n"; + m_t << "{"; //Topic Documentation}\n"; break; } } } break; - case isDirDocumentation: + case IndexSection::isModuleDocumentation: + { + for (const auto &mod : ModuleManager::instance().modules()) + { + if (!mod->isReference() && mod->isPrimaryInterface()) + { + if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; + m_t << "{"; //Topic Documentation}\n"; + break; + } + } + } + break; + case IndexSection::isDirDocumentation: { for (const auto &dd : *Doxygen::dirLinkedMap) { if (dd->isLinkableInProject()) { if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; - m_t << "{"; //Module Documentation}\n"; + m_t << "{"; //Dir Documentation}\n"; break; } } } break; - case isNamespaceDocumentation: + case IndexSection::isNamespaceDocumentation: { for (const auto &nd : *Doxygen::namespaceLinkedMap) { @@ -820,7 +922,7 @@ void LatexGenerator::startIndexSection(IndexSections is) } } break; - case isConceptDocumentation: + case IndexSection::isConceptDocumentation: { for (const auto &cd : *Doxygen::conceptLinkedMap) { @@ -833,7 +935,7 @@ void LatexGenerator::startIndexSection(IndexSections is) } } break; - case isClassDocumentation: + case IndexSection::isClassDocumentation: { for (const auto &cd : *Doxygen::classLinkedMap) { @@ -850,7 +952,7 @@ void LatexGenerator::startIndexSection(IndexSections is) } } break; - case isFileDocumentation: + case IndexSection::isFileDocumentation: { bool isFirst=TRUE; for (const auto &fn : *Doxygen::inputNameLinkedMap) @@ -871,84 +973,89 @@ void LatexGenerator::startIndexSection(IndexSections is) } } break; - case isExampleDocumentation: + case IndexSection::isExampleDocumentation: { if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Example Documentation}\n"; } break; - case isPageDocumentation: - { - if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; - m_t << "{"; //Page Documentation}\n"; - } + case IndexSection::isPageDocumentation: break; - case isPageDocumentation2: + case IndexSection::isPageDocumentation2: break; - case isEndIndex: + case IndexSection::isEndIndex: break; } } -void LatexGenerator::endIndexSection(IndexSections is) +void LatexGenerator::endIndexSection(IndexSection is) { switch (is) { - case isTitlePageStart: + case IndexSection::isTitlePageStart: break; - case isTitlePageAuthor: + case IndexSection::isTitlePageAuthor: break; - case isMainPage: + case IndexSection::isMainPage: { - //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index"; - QCString indexName="index"; - m_t << "}\n\\label{index}"; - if (Config_getBool(PDF_HYPERLINKS)) m_t << "\\hypertarget{index}{}"; - m_t << "\\input{" << indexName << "}\n"; + if (Doxygen::mainPage) + { + writePageLink(Doxygen::mainPage->getOutputFileBase(), FALSE); + } } break; - case isModuleIndex: + case IndexSection::isModuleIndex: m_t << "}\n\\input{modules}\n"; break; - case isDirIndex: + case IndexSection::isTopicIndex: + m_t << "}\n\\input{topics}\n"; + break; + case IndexSection::isDirIndex: m_t << "}\n\\input{dirs}\n"; break; - case isNamespaceIndex: + case IndexSection::isNamespaceIndex: m_t << "}\n\\input{namespaces}\n"; break; - case isConceptIndex: + case IndexSection::isConceptIndex: m_t << "}\n\\input{concepts}\n"; break; - case isClassHierarchyIndex: + case IndexSection::isClassHierarchyIndex: m_t << "}\n\\input{hierarchy}\n"; break; - case isCompoundIndex: + case IndexSection::isCompoundIndex: m_t << "}\n\\input{annotated}\n"; break; - case isFileIndex: + case IndexSection::isFileIndex: m_t << "}\n\\input{files}\n"; break; - case isPageIndex: + case IndexSection::isPageIndex: m_t << "}\n\\input{pages}\n"; break; - case isModuleDocumentation: + case IndexSection::isTopicDocumentation: { - bool found=FALSE; + m_t << "}\n"; for (const auto &gd : *Doxygen::groupLinkedMap) { - if (!gd->isReference()) + if (!gd->isReference() && !gd->isASubGroup()) { - if (!found) - { - m_t << "}\n"; - found=TRUE; - } - m_t << "\\input{" << gd->getOutputFileBase() << "}\n"; + writePageLink(gd->getOutputFileBase(), FALSE); } } } break; - case isDirDocumentation: + case IndexSection::isModuleDocumentation: + { + m_t << "}\n"; + for (const auto &mod : ModuleManager::instance().modules()) + { + if (!mod->isReference() && mod->isPrimaryInterface()) + { + writePageLink(mod->getOutputFileBase(), FALSE); + } + } + } + break; + case IndexSection::isDirDocumentation: { bool found=FALSE; for (const auto &dd : *Doxygen::dirLinkedMap) @@ -965,7 +1072,7 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isNamespaceDocumentation: + case IndexSection::isNamespaceDocumentation: { bool found=FALSE; for (const auto &nd : *Doxygen::namespaceLinkedMap) @@ -982,7 +1089,7 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isConceptDocumentation: + case IndexSection::isConceptDocumentation: { bool found=FALSE; for (const auto &cd : *Doxygen::conceptLinkedMap) @@ -999,7 +1106,7 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isClassDocumentation: + case IndexSection::isClassDocumentation: { bool found=FALSE; for (const auto &cd : *Doxygen::classLinkedMap) @@ -1020,7 +1127,7 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isFileDocumentation: + case IndexSection::isFileDocumentation: { bool isFirst=TRUE; for (const auto &fn : *Doxygen::inputNameLinkedMap) @@ -1049,7 +1156,7 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isExampleDocumentation: + case IndexSection::isExampleDocumentation: { m_t << "}\n"; for (const auto &pd : *Doxygen::exampleLinkedMap) @@ -1058,31 +1165,22 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; - case isPageDocumentation: + case IndexSection::isPageDocumentation: { - m_t << "}\n"; -#if 0 - bool first=TRUE; - for (const auto *pd : Doxygen::pageLinkedMap) + for (const auto &pd : *Doxygen::pageLinkedMap) { - if (!pd->getGroupDef() && !pd->isReference()) + if (!pd->getGroupDef() && !pd->isReference() && !pd->hasParentPage() + && pd->name() != "citelist" && Doxygen::mainPage.get() != pd.get()) { - if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; - m_t << "{" << pd->title(); - m_t << "}\n"; - - if (compactLatex || first) m_t << "\\input" ; else m_t << "\\include"; - m_t << "{" << pd->getOutputFileBase() << "}\n"; - first=FALSE; + writePageLink(pd->getOutputFileBase(), FALSE); } } -#endif } break; - case isPageDocumentation2: + case IndexSection::isPageDocumentation2: break; - case isEndIndex: - m_t << substituteLatexKeywords(g_footer,convertToLaTeX(Config_getString(PROJECT_NAME))); + case IndexSection::isEndIndex: + m_t << substituteLatexKeywords(g_footer,convertToLaTeX(Config_getString(PROJECT_NAME),m_codeGen->insideTabbing())); break; } } @@ -1096,7 +1194,6 @@ void LatexGenerator::writePageLink(const QCString &name, bool /*first*/) m_t << "{" << name << "}\n"; } - void LatexGenerator::writeStyleInfo(int part) { if (part > 0) @@ -1114,11 +1211,12 @@ void LatexGenerator::writeStyleInfo(int part) startPlainFile("longtable_doxygen.sty"); m_t << ResourceMgr::instance().getAsString("longtable_doxygen.sty"); endPlainFile(); -} - -void LatexGenerator::newParagraph() -{ - m_t << "\n" << "\n"; + /// an extension of the etoc package is required that is only available in the + /// newer version. Providing the updated version to be used with older versions + /// of LaTeX + startPlainFile("etoc_doxygen.sty"); + m_t << ResourceMgr::instance().getAsString("etoc_doxygen.sty"); + endPlainFile(); } void LatexGenerator::startParagraph(const QCString &) @@ -1153,43 +1251,6 @@ void LatexGenerator::endIndexItem(const QCString &ref,const QCString &fn) } } -//void LatexGenerator::writeIndexFileItem(const QCString &,const QCString &text) -//{ -// m_t << "\\item\\contentsline{section}{"; -// docify(text); -// m_t << "}{\\pageref{" << stripPath(text) << "}}\n"; -//} - - -void LatexGenerator::startHtmlLink(const QCString &url) -{ - if (Config_getBool(PDF_HYPERLINKS)) - { - m_t << "\\href{"; - m_t << latexFilterURL(url); - m_t << "}"; - } - m_t << "{\\texttt{ "; -} - -void LatexGenerator::endHtmlLink() -{ - m_t << "}}"; -} - -//void LatexGenerator::writeMailLink(const QCString &url) -//{ -// if (Config_getBool(PDF_HYPERLINKS)) -// { -// m_t << "\\href{mailto:"; -// m_t << url; -// m_t << "}"; -// } -// m_t << "\\texttt{ "; -// docify(url); -// m_t << "}"; -//} - void LatexGenerator::writeStartAnnoItem(const QCString &,const QCString &, const QCString &path,const QCString &name) { @@ -1199,11 +1260,6 @@ void LatexGenerator::writeStartAnnoItem(const QCString &,const QCString &, m_t << "} "; } -void LatexGenerator::writeEndAnnoItem(const QCString &name) -{ - m_t << "}{\\pageref{" << stripPath(name) << "}}{}\n"; -} - void LatexGenerator::startIndexKey() { m_t << "\\item\\contentsline{section}{"; @@ -1259,28 +1315,50 @@ void LatexGenerator::endTextLink() m_t << "}"; } -void LatexGenerator::writeObjectLink(const QCString &ref, const QCString &f, - const QCString &anchor, const QCString &text) +static QCString objectLinkToString(const QCString &ref, const QCString &f, + const QCString &anchor, const QCString &text, + bool insideTabbing,bool disableLinks) { bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); - if (!m_disableLinks && ref.isEmpty() && pdfHyperlinks) + QCString result; + if (!disableLinks && ref.isEmpty() && pdfHyperlinks) { - m_t << "\\mbox{\\hyperlink{"; - if (!f.isEmpty()) m_t << stripPath(f); - if (!f.isEmpty() && !anchor.isEmpty()) m_t << "_"; - if (!anchor.isEmpty()) m_t << anchor; - m_t << "}{"; - docify(text); - m_t << "}}"; + result += "\\mbox{\\hyperlink{"; + if (!f.isEmpty()) result += stripPath(f); + if (!f.isEmpty() && !anchor.isEmpty()) result += "_"; + if (!anchor.isEmpty()) result += anchor; + result += "}{"; + result += convertToLaTeX(text,insideTabbing); + result += "}}"; } else { - m_t << "\\textbf{ "; - docify(text); - m_t << "}"; + result += "\\textbf{ "; + result += convertToLaTeX(text,insideTabbing); + result += "}"; + } + return result; +} + +static void processEntity(TextStream &t, bool pdfHyperlinks, const char *strForm, const char *strRepl) +{ + if (pdfHyperlinks) + { + t << "\\texorpdfstring{"; + } + t << strForm; + if (pdfHyperlinks) + { + t << "}{" << strRepl << "}"; } } +void LatexGenerator::writeObjectLink(const QCString &ref, const QCString &f, + const QCString &anchor, const QCString &text) +{ + m_t << objectLinkToString(ref,f,anchor,text,m_codeGen->insideTabbing(),m_disableLinks); +} + void LatexGenerator::startPageRef() { m_t << " \\doxyref{}{"; @@ -1297,28 +1375,37 @@ void LatexGenerator::endPageRef(const QCString &clname, const QCString &anchor) void LatexGenerator::startTitleHead(const QCString &fileName) { - bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); - bool usePDFLatex = Config_getBool(USE_PDFLATEX); - if (usePDFLatex && pdfHyperlinks && !fileName.isEmpty()) - { - m_t << "\\hypertarget{" << stripPath(fileName) << "}{}"; - } + int hierarchyLevel = m_hierarchyLevel; if (Config_getBool(COMPACT_LATEX)) { - m_t << "\\doxysubsection{"; + ++hierarchyLevel; } + + if (hierarchyLevel < 0) + m_t << "\\chapter{"; else - { - m_t << "\\doxysection{"; - } + m_t << "\\doxy" << QCString("sub").repeat(hierarchyLevel) << "section{"; } void LatexGenerator::endTitleHead(const QCString &fileName,const QCString &name) { m_t << "}\n"; + + bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); + bool usePDFLatex = Config_getBool(USE_PDFLATEX); + if (usePDFLatex && pdfHyperlinks && !fileName.isEmpty()) + { + m_t << "\\hypertarget{" << stripPath(fileName) << "}{}"; + } + + QCString fn = stripPath(fileName); + if (!fn.isEmpty()) + { + m_t << "\\label{" << fn << "}"; + } if (!name.isEmpty()) { - m_t << "\\label{" << stripPath(fileName) << "}\\index{"; + m_t << "\\index{"; m_t << latexEscapeLabelName(name); m_t << "@{"; m_t << latexEscapeIndexChars(name); @@ -1345,7 +1432,7 @@ void LatexGenerator::startGroupHeader(int extraIndentLevel) extraIndentLevel++; } - if (extraIndentLevel==3) + if (extraIndentLevel>=3) { m_t << "\\doxysubparagraph*{"; } @@ -1353,13 +1440,10 @@ void LatexGenerator::startGroupHeader(int extraIndentLevel) { m_t << "\\doxyparagraph{"; } - else if (extraIndentLevel==1) - { - m_t << "\\doxysubsubsection{"; - } - else // extraIndentLevel==0 + else { - m_t << "\\doxysubsection{"; + extraIndentLevel += m_hierarchyLevel + 1; + m_t << "\\doxy" << QCString("sub").repeat(extraIndentLevel) << "section{"; } m_disableLinks=TRUE; } @@ -1372,14 +1456,13 @@ void LatexGenerator::endGroupHeader(int) void LatexGenerator::startMemberHeader(const QCString &,int) { + int l = m_hierarchyLevel + 1; if (Config_getBool(COMPACT_LATEX)) { - m_t << "\\doxysubsubsection*{"; - } - else - { - m_t << "\\doxysubsection*{"; + ++l; } + + m_t << "\\doxysub" << QCString("sub").repeat(l) << "section*{"; m_disableLinks=TRUE; } @@ -1427,13 +1510,20 @@ void LatexGenerator::startMemberDoc(const QCString &clname, } m_t << "}\n"; } - static const char *levelLab[] = { "doxysubsubsection","doxyparagraph","doxysubparagraph", "doxysubparagraph" }; bool compactLatex = Config_getBool(COMPACT_LATEX); bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); - int level=0; - if (showInline) level+=2; - if (compactLatex) level++; - m_t << "\\" << levelLab[level]; + if (showInline) + { + m_t << "\\doxysubparagraph"; + } + else if (compactLatex) + { + m_t << "\\doxyparagraph"; + } + else + { + m_t << "\\doxy" << QCString("sub").repeat(m_hierarchyLevel + 2) << "section"; + } m_t << "{"; if (pdfHyperlinks) @@ -1467,7 +1557,7 @@ void LatexGenerator::startDoxyAnchor(const QCString &fName,const QCString &, { bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); bool usePDFLatex = Config_getBool(USE_PDFLATEX); - m_t << "\\mbox{"; + if (m_insideTableEnv) m_t << "\\mbox{"; // see issue #6093 if (usePDFLatex && pdfHyperlinks) { m_t << "\\Hypertarget{"; @@ -1478,10 +1568,11 @@ void LatexGenerator::startDoxyAnchor(const QCString &fName,const QCString &, m_t << "\\label{"; if (!fName.isEmpty()) m_t << stripPath(fName); if (!anchor.isEmpty()) m_t << "_" << anchor; - m_t << "}} \n"; + if (m_insideTableEnv) m_t << "}"; + m_t << "} \n"; } -void LatexGenerator::endDoxyAnchor(const QCString &fName,const QCString &anchor) +void LatexGenerator::endDoxyAnchor(const QCString &/* fName */,const QCString &/* anchor */) { } @@ -1578,10 +1669,10 @@ void LatexGenerator::endSection(const QCString &lab,SectionType) void LatexGenerator::docify(const QCString &str) { filterLatexString(m_t,str, - m_insideTabbing, // insideTabbing + m_codeGen->insideTabbing(), // insideTabbing false, // insidePre false, // insideItem - m_codeGen.usedTableLevel()>0, // insideTable + m_codeGen->usedTableLevel()>0, // insideTable false // keepSpaces ); } @@ -1613,7 +1704,7 @@ void LatexGenerator::startAnonTypeScope(int indent) { m_t << "\\begin{tabbing}\n"; m_t << "xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=\\kill\n"; - m_insideTabbing=TRUE; + m_codeGen->setInsideTabbing(true); } m_indent=indent; } @@ -1623,14 +1714,14 @@ void LatexGenerator::endAnonTypeScope(int indent) if (indent==0) { m_t << "\n" << "\\end{tabbing}"; - m_insideTabbing=FALSE; + m_codeGen->setInsideTabbing(false); } m_indent=indent; } void LatexGenerator::startMemberTemplateParams() { - if (templateMemberItem) + if (m_templateMemberItem) { m_t << "{\\footnotesize "; } @@ -1638,35 +1729,35 @@ void LatexGenerator::startMemberTemplateParams() void LatexGenerator::endMemberTemplateParams(const QCString &,const QCString &) { - if (templateMemberItem) + if (m_templateMemberItem) { m_t << "}\\\\"; } } -void LatexGenerator::startMemberItem(const QCString &,int annoType,const QCString &) +void LatexGenerator::startMemberItem(const QCString &,MemberItemType type,const QCString &) { //printf("LatexGenerator::startMemberItem(%d)\n",annType); - if (!m_insideTabbing) + if (!m_codeGen->insideTabbing()) { m_t << "\\item \n"; - templateMemberItem = (annoType == 3); + m_templateMemberItem = (type == MemberItemType::Templated); } } -void LatexGenerator::endMemberItem() +void LatexGenerator::endMemberItem(MemberItemType) { - if (m_insideTabbing) + if (m_codeGen->insideTabbing()) { m_t << "\\\\"; } - templateMemberItem = FALSE; + m_templateMemberItem = FALSE; m_t << "\n"; } void LatexGenerator::startMemberDescription(const QCString &,const QCString &,bool) { - if (!m_insideTabbing) + if (!m_codeGen->insideTabbing()) { m_t << "\\begin{DoxyCompactList}\\small\\item\\em "; } @@ -1679,7 +1770,7 @@ void LatexGenerator::startMemberDescription(const QCString &,const QCString &,bo void LatexGenerator::endMemberDescription() { - if (!m_insideTabbing) + if (!m_codeGen->insideTabbing()) { //m_t << "\\item\\end{DoxyCompactList}"; m_t << "\\end{DoxyCompactList}"; @@ -1694,7 +1785,7 @@ void LatexGenerator::endMemberDescription() void LatexGenerator::writeNonBreakableSpace(int) { //printf("writeNonBreakableSpace()\n"); - if (m_insideTabbing) + if (m_codeGen->insideTabbing()) { m_t << "\\>"; } @@ -1720,13 +1811,13 @@ void LatexGenerator::writeNonBreakableSpace(int) void LatexGenerator::startDescTable(const QCString &title) { - m_codeGen.incUsedTableLevel(); + m_codeGen->incUsedTableLevel(); m_t << "\\begin{DoxyEnumFields}{" << title << "}\n"; } void LatexGenerator::endDescTable() { - m_codeGen.decUsedTableLevel(); + m_codeGen->decUsedTableLevel(); m_t << "\\end{DoxyEnumFields}\n"; } @@ -1767,7 +1858,7 @@ void LatexGenerator::lastIndexPage() void LatexGenerator::startMemberList() { - if (!m_insideTabbing) + if (!m_codeGen->insideTabbing()) { m_t << "\\begin{DoxyCompactItemize}\n"; } @@ -1775,8 +1866,8 @@ void LatexGenerator::startMemberList() void LatexGenerator::endMemberList() { - //printf("LatexGenerator::endMemberList(%d)\n",m_insideTabbing); - if (!m_insideTabbing) + //printf("LatexGenerator::endMemberList(%d)\n",m_codeGen->InsideTabbing()); + if (!m_codeGen->insideTabbing()) { m_t << "\\end{DoxyCompactItemize}\n"; } @@ -1827,7 +1918,7 @@ void LatexGenerator::endMemberGroup(bool hasHeader) void LatexGenerator::startDotGraph() { - newParagraph(); + m_t << "\n" << "\n"; } void LatexGenerator::endDotGraph(DotClassGraph &g) @@ -1871,36 +1962,6 @@ void LatexGenerator::endDirDepGraph(DotDirDeps &g) g.writeGraph(m_t,GOF_EPS,EOF_LaTeX,dir(),fileName(),m_relPath); } -void LatexGenerator::startDescription() -{ - m_t << "\\begin{description}\n"; -} - -void LatexGenerator::endDescription() -{ - m_t << "\\end{description}\n"; - m_firstDescItem=TRUE; -} - -void LatexGenerator::startDescItem() -{ - m_firstDescItem=TRUE; - m_t << "\\item["; -} - -void LatexGenerator::endDescItem() -{ - if (m_firstDescItem) - { - m_t << "]\n"; - m_firstDescItem=FALSE; - } - else - { - lineBreak(); - } -} - void LatexGenerator::startExamples() { m_t << "\\begin{Desc}\n\\item["; @@ -1913,18 +1974,6 @@ void LatexGenerator::endExamples() m_t << "\\end{Desc}\n"; } -void LatexGenerator::startParamList(ParamListTypes,const QCString &title) -{ - m_t << "\\begin{Desc}\n\\item["; - docify(title); - m_t << "]"; -} - -void LatexGenerator::endParamList() -{ - m_t << "\\end{Desc}\n"; -} - void LatexGenerator::startParameterList(bool openBracket) { /* start of ParameterType ParameterName list */ @@ -1980,9 +2029,9 @@ void LatexGenerator::writeDoc(const IDocNodeAST *ast,const Definition *ctx,const const DocNodeAST *astImpl = dynamic_cast<const DocNodeAST*>(ast); if (astImpl) { - LatexDocVisitor visitor(m_t,m_codeGen, + LatexDocVisitor visitor(m_t,*m_codeList,*m_codeGen, ctx?ctx->getDefFileExtension():QCString(""), - m_insideTabbing); + m_hierarchyLevel); std::visit(visitor,astImpl->root); } } @@ -2036,7 +2085,7 @@ void LatexGenerator::startInlineHeader() } else { - m_t << "\\doxysubsubsection*{"; + m_t << "\\doxy" << QCString("sub").repeat(m_hierarchyLevel + 1) << "section*{"; } } @@ -2047,7 +2096,7 @@ void LatexGenerator::endInlineHeader() void LatexGenerator::lineBreak(const QCString &) { - if (m_insideTabbing) + if (m_codeGen->insideTabbing()) { m_t << "\\\\\n"; } @@ -2059,7 +2108,7 @@ void LatexGenerator::lineBreak(const QCString &) void LatexGenerator::startMemberDocSimple(bool isEnum) { - m_codeGen.incUsedTableLevel(); + m_codeGen->incUsedTableLevel(); if (isEnum) { m_t << "\\begin{DoxyEnumFields}{"; @@ -2071,11 +2120,13 @@ void LatexGenerator::startMemberDocSimple(bool isEnum) docify(theTranslator->trCompoundMembers()); } m_t << "}\n"; + m_insideTableEnv=true; } void LatexGenerator::endMemberDocSimple(bool isEnum) { - m_codeGen.decUsedTableLevel(); + m_insideTableEnv=false; + m_codeGen->decUsedTableLevel(); if (isEnum) { m_t << "\\end{DoxyEnumFields}\n"; @@ -2088,24 +2139,24 @@ void LatexGenerator::endMemberDocSimple(bool isEnum) void LatexGenerator::startInlineMemberType() { - m_insideTabbing = TRUE; // to prevent \+ from causing unwanted breaks + m_codeGen->setInsideTabbing(true); // to prevent \+ from causing unwanted breaks } void LatexGenerator::endInlineMemberType() { m_t << "&\n"; - m_insideTabbing = FALSE; + m_codeGen->setInsideTabbing(false); } void LatexGenerator::startInlineMemberName() { - m_insideTabbing = TRUE; // to prevent \+ from causing unwanted breaks + m_codeGen->setInsideTabbing(true); // to prevent \+ from causing unwanted breaks } void LatexGenerator::endInlineMemberName() { m_t << "&\n"; - m_insideTabbing = FALSE; + m_codeGen->setInsideTabbing(false); } void LatexGenerator::startInlineMemberDoc() @@ -2131,3 +2182,406 @@ void LatexGenerator::writeLabel(const QCString &l,bool isLast) void LatexGenerator::endLabels() { } + +void LatexGenerator::writeInheritedSectionTitle( + const QCString &/*id*/,const QCString &ref, + const QCString &file, const QCString &anchor, + const QCString &title, const QCString &name) +{ + if (Config_getBool(COMPACT_LATEX)) + { + m_t << "\\doxyparagraph*{"; + } + else + { + m_t << "\\doxy" << QCString("sub").repeat(m_hierarchyLevel + 1) << "section*{"; + } + m_t << theTranslator->trInheritedFrom(convertToLaTeX(title,m_codeGen->insideTabbing()), + objectLinkToString(ref, file, anchor, name, m_codeGen->insideTabbing(), m_disableLinks)); + m_t << "}\n"; +} + +void LatexGenerator::writeLocalToc(const SectionRefs &,const LocalToc &localToc) +{ + if (localToc.isLatexEnabled()) + { + int maxLevel = localToc.latexLevel() + m_hierarchyLevel; + m_t << "\\etocsetnexttocdepth{" << maxLevel << "}\n"; + m_t << "\\localtableofcontents\n"; + } +} + +//-------------------------------------------------------------------------------------------------- + +void writeExtraLatexPackages(TextStream &t) +{ + // User-specified packages + const StringVector &extraPackages = Config_getList(EXTRA_PACKAGES); + if (!extraPackages.empty()) + { + t << "% Packages requested by user\n"; + for (const auto &pkgName : extraPackages) + { + if ((pkgName[0] == '[') || (pkgName[0] == '{')) + t << "\\usepackage" << pkgName.c_str() << "\n"; + else + t << "\\usepackage{" << pkgName.c_str() << "}\n"; + } + t << "\n"; + } +} + +void writeLatexSpecialFormulaChars(TextStream &t) +{ + unsigned char minus[4]; // Superscript minus + unsigned char sup2[3]; // Superscript two + unsigned char sup3[3]; + minus[0]= 0xE2; + minus[1]= 0x81; + minus[2]= 0xBB; + minus[3]= 0; + sup2[0]= 0xC2; + sup2[1]= 0xB2; + sup2[2]= 0; + sup3[0]= 0xC2; + sup3[1]= 0xB3; + sup3[2]= 0; + + t << "\\usepackage{newunicodechar}\n"; + // taken from the newunicodechar package and removed the warning message + // actually forcing to redefine the unicode character + t << " \\makeatletter\n" + " \\def\\doxynewunicodechar#1#2{%\n" + " \\@tempswafalse\n" + " \\edef\\nuc@tempa{\\detokenize{#1}}%\n" + " \\if\\relax\\nuc@tempa\\relax\n" + " \\nuc@emptyargerr\n" + " \\else\n" + " \\edef\\@tempb{\\expandafter\\@car\\nuc@tempa\\@nil}%\n" + " \\nuc@check\n" + " \\if@tempswa\n" + " \\@namedef{u8:\\nuc@tempa}{#2}%\n" + " \\fi\n" + " \\fi\n" + " }\n" + " \\makeatother\n"; + + t << " \\doxynewunicodechar{" << minus << "}{${}^{-}$}% Superscript minus\n" + " \\doxynewunicodechar{" << sup2 << "}{${}^{2}$}% Superscript two\n" + " \\doxynewunicodechar{" << sup3 << "}{${}^{3}$}% Superscript three\n" + "\n"; +} + +void filterLatexString(TextStream &t,const QCString &str, + bool insideTabbing,bool insidePre,bool insideItem,bool insideTable,bool keepSpaces, const bool retainNewline) +{ + if (str.isEmpty()) return; + bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); + //printf("filterLatexString(%s) insideTabbing=%d\n",qPrint(str),insideTabbing); + const char *p=str.data(); + const char *q; + int cnt; + unsigned char c; + unsigned char pc='\0'; + + while (*p) + { + c=static_cast<unsigned char>(*p++); + + if (insidePre) + { + switch(c) + { + case 0xef: // handle U+FFFD i.e. "Replacement character" caused by octal: 357 277 275 / hexadecimal 0xef 0xbf 0xbd + // the LaTeX command \ucr has been defined in doxygen.sty + if (static_cast<unsigned char>(*(p)) == 0xbf && static_cast<unsigned char>(*(p+1)) == 0xbd) + { + t << "{\\ucr}"; + p += 2; + } + else + t << static_cast<char>(c); + break; + case '\\': t << "\\(\\backslash\\)"; break; + case '{': t << "\\{"; break; + case '}': t << "\\}"; break; + case '_': t << "\\_"; break; + case '&': t << "\\&"; break; + case '%': t << "\\%"; break; + case '#': t << "\\#"; break; + case '$': t << "\\$"; break; + case '"': t << "\"{}"; break; + case '-': t << "-\\/"; break; + case '^': insideTable ? t << "\\string^" : t << static_cast<char>(c); break; + case '~': t << "\\string~"; break; + case '\n': if (retainNewline) t << "\\newline"; else t << ' '; + break; + case ' ': if (keepSpaces) t << "~"; else t << ' '; + break; + default: + if (c<32) t << ' '; // non printable control character + else t << static_cast<char>(c); + break; + } + } + else + { + switch(c) + { + case 0xef: // handle U+FFFD i.e. "Replacement character" caused by octal: 357 277 275 / hexadecimal 0xef 0xbf 0xbd + // the LaTeX command \ucr has been defined in doxygen.sty + if (static_cast<unsigned char>(*(p)) == 0xbf && static_cast<unsigned char>(*(p+1)) == 0xbd) + { + t << "{\\ucr}"; + p += 2; + } + else + t << static_cast<char>(c); + break; + case '#': t << "\\#"; break; + case '$': t << "\\$"; break; + case '%': t << "\\%"; break; + case '^': processEntity(t,pdfHyperlinks,"$^\\wedge$","\\string^"); break; + case '&': // possibility to have a special symbol + q = p; + cnt = 2; // we have to count & and ; as well + while ((*q >= 'a' && *q <= 'z') || (*q >= 'A' && *q <= 'Z') || (*q >= '0' && *q <= '9')) + { + cnt++; + q++; + } + if (*q == ';') + { + --p; // we need & as well + HtmlEntityMapper::SymType res = HtmlEntityMapper::instance().name2sym(QCString(p).left(cnt)); + if (res == HtmlEntityMapper::Sym_Unknown) + { + p++; + t << "\\&"; + } + else + { + t << HtmlEntityMapper::instance().latex(res); + q++; + p = q; + } + } + else + { + t << "\\&"; + } + break; + case '*': processEntity(t,pdfHyperlinks,"$\\ast$","*"); break; + case '_': if (!insideTabbing) t << "\\+"; + t << "\\_"; + if (!insideTabbing) t << "\\+"; + break; + case '{': t << "\\{"; break; + case '}': t << "\\}"; break; + case '<': t << "$<$"; break; + case '>': t << "$>$"; break; + case '|': processEntity(t,pdfHyperlinks,"$\\vert$","|"); break; + case '~': processEntity(t,pdfHyperlinks,"$\\sim$","\\string~"); break; + case '[': if (Config_getBool(PDF_HYPERLINKS) || insideItem) + t << "\\mbox{[}"; + else + t << "["; + break; + case ']': if (pc=='[') t << "$\\,$"; + if (Config_getBool(PDF_HYPERLINKS) || insideItem) + t << "\\mbox{]}"; + else + t << "]"; + break; + case '-': t << "-\\/"; + break; + case '\\': t << "\\textbackslash{}"; + break; + case '"': t << "\"{}"; + break; + case '`': t << "\\`{}"; + break; + case '\'': t << "\\textquotesingle{}"; + break; + case '\n': if (retainNewline) t << "\\newline"; else t << ' '; + break; + case ' ': if (keepSpaces) { if (insideTabbing) t << "\\>"; else t << '~'; } else t << ' '; + break; + + default: + //if (!insideTabbing && forceBreaks && c!=' ' && *p!=' ') + if (!insideTabbing && + ((c>='A' && c<='Z' && pc!=' ' && !(pc>='A' && pc <= 'Z') && pc!='\0' && *p) || (c==':' && pc!=':') || (pc=='.' && isId(c))) + ) + { + t << "\\+"; + } + if (c<32) + { + t << ' '; // non-printable control character + } + else + { + t << static_cast<char>(c); + } + } + } + pc = c; + } +} + +QCString convertToLaTeX(const QCString &s,bool insideTabbing,bool keepSpaces) +{ + TextStream t; + filterLatexString(t,s,insideTabbing,false,false,false,keepSpaces); + return t.str(); +} + +QCString latexEscapeLabelName(const QCString &s) +{ + //printf("latexEscapeLabelName(%s)\n",qPrint(s)); + if (s.isEmpty()) return s; + QCString tmp(s.length()+1); + TextStream t; + const char *p=s.data(); + char c; + int i; + while ((c=*p++)) + { + switch (c) + { + case '|': t << "\\texttt{\"|}"; break; + case '!': t << "\"!"; break; + case '@': t << "\"@"; break; + case '%': t << "\\%"; break; + case '{': t << "\\lcurly{}"; break; + case '}': t << "\\rcurly{}"; break; + case '~': t << "````~"; break; // to get it a bit better in index together with other special characters + // NOTE: adding a case here, means adding it to while below as well! + default: + i=0; + // collect as long string as possible, before handing it to docify + tmp[i++]=c; + while ((c=*p) && c!='@' && c!='[' && c!=']' && c!='!' && c!='{' && c!='}' && c!='|') + { + tmp[i++]=c; + p++; + } + tmp[i]=0; + filterLatexString(t,tmp, + true, // insideTabbing + false, // insidePre + false, // insideItem + false, // insideTable + false // keepSpaces + ); + break; + } + } + return t.str(); +} + +QCString latexEscapeIndexChars(const QCString &s) +{ + //printf("latexEscapeIndexChars(%s)\n",qPrint(s)); + if (s.isEmpty()) return s; + QCString tmp(s.length()+1); + TextStream t; + const char *p=s.data(); + char c; + int i; + while ((c=*p++)) + { + switch (c) + { + case '!': t << "\"!"; break; + case '"': t << "\"\""; break; + case '@': t << "\"@"; break; + case '|': t << "\\texttt{\"|}"; break; + case '[': t << "["; break; + case ']': t << "]"; break; + case '{': t << "\\lcurly{}"; break; + case '}': t << "\\rcurly{}"; break; + // NOTE: adding a case here, means adding it to while below as well! + default: + i=0; + // collect as long string as possible, before handing it to docify + tmp[i++]=c; + while ((c=*p) && c!='"' && c!='@' && c!='[' && c!=']' && c!='!' && c!='{' && c!='}' && c!='|') + { + tmp[i++]=c; + p++; + } + tmp[i]=0; + filterLatexString(t,tmp, + true, // insideTabbing + false, // insidePre + false, // insideItem + false, // insideTable + false // keepSpaces + ); + break; + } + } + return t.str(); +} + +QCString latexEscapePDFString(const QCString &s) +{ + if (s.isEmpty()) return s; + TextStream t; + const char *p=s.data(); + char c; + while ((c=*p++)) + { + switch (c) + { + case '\\': t << "\\textbackslash{}"; break; + case '{': t << "\\{"; break; + case '}': t << "\\}"; break; + case '_': t << "\\_"; break; + case '%': t << "\\%"; break; + case '&': t << "\\&"; break; + case '#': t << "\\#"; break; + case '$': t << "\\$"; break; + case '^': t << "\\string^"; break; + case '~': t << "\\string~"; break; + default: + t << c; + break; + } + } + return t.str(); +} + +QCString latexFilterURL(const QCString &s) +{ + constexpr auto hex = "0123456789ABCDEF"; + if (s.isEmpty()) return s; + TextStream t; + const char *p=s.data(); + char c; + while ((c=*p++)) + { + switch (c) + { + case '#': t << "\\#"; break; + case '%': t << "\\%"; break; + case '\\': t << "\\\\"; break; + default: + if (c<0) + { + unsigned char id = static_cast<unsigned char>(c); + t << "\\%" << hex[id>>4] << hex[id&0xF]; + } + else + { + t << c; + } + break; + } + } + return t.str(); +} + + |