/****************************************************************************** * * Copyright (C) 1997-2021 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ #include #include #include #include #include "message.h" #include "htmlgen.h" #include "config.h" #include "util.h" #include "doxygen.h" #include "diagram.h" #include "version.h" #include "dot.h" #include "dotcallgraph.h" #include "dotclassgraph.h" #include "dotdirdeps.h" #include "dotgfxhierarchytable.h" #include "dotgroupcollaboration.h" #include "dotincldepgraph.h" #include "language.h" #include "htmlhelp.h" #include "docparser.h" #include "htmldocvisitor.h" #include "searchindex.h" #include "pagedef.h" #include "debug.h" #include "dirdef.h" #include "vhdldocgen.h" #include "layout.h" #include "image.h" #include "ftvhelp.h" #include "bufstr.h" #include "resourcemgr.h" #include "tooltip.h" #include "growbuf.h" #include "fileinfo.h" #include "dir.h" #include "utf8.h" #include "textstream.h" //#define DBG_HTML(x) x; #define DBG_HTML(x) static QCString g_header; static QCString g_footer; static QCString g_mathjax_code; static QCString g_latex_macro; static const char *hex="0123456789ABCDEF"; // note: this is only active if DISABLE_INDEX=YES, if DISABLE_INDEX is disabled, this // part will be rendered inside menu.js static void writeClientSearchBox(TextStream &t,const QCString &relPath) { t << "
\n"; t << " \n"; t << " \"\"/\n"; t << " trSearch() << "\" accesskey=\"S\"\n"; t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n"; t << " onblur=\"searchBox.OnSearchFieldFocus(false)\" \n"; t << " onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n"; t << " \n"; t << " " << "\"\"/\n"; t << " \n"; t << "
\n"; } // note: this is only active if DISABLE_INDEX=YES. if DISABLE_INDEX is disabled, this // part will be rendered inside menu.js static void writeServerSearchBox(TextStream &t,const QCString &relPath,bool highlightSearch) { bool externalSearch = Config_getBool(EXTERNAL_SEARCH); t << "
\n"; t << "
\n"; t << "
\n"; t << " \"\"/\n"; if (!highlightSearch) { t << " trSearch() << "\" size=\"20\" accesskey=\"S\" \n"; t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n"; t << " onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n"; t << "
\n"; t << "
\n"; t << "
\n"; } } //------------------------------------------------------------------------ /// Convert a set of LaTeX commands `\(re)newcommand` to a form readable by MathJax /// LaTeX syntax: /// ``` /// \newcommand{\cmd}{replacement} /// or /// \renewcommand{\cmd}{replacement} /// ``` /// MathJax syntax: /// ``` /// cmd: "{replacement}" /// ``` /// /// LaTeX syntax: /// ``` /// \newcommand{\cmd}[nr]{replacement} /// or /// \renewcommand{\cmd}[nr]{replacement} /// ``` /// MathJax syntax: /// ``` /// cmd: ["{replacement}",nr] /// ``` static QCString getConvertLatexMacro() { QCString macrofile = Config_getString(FORMULA_MACROFILE); if (macrofile.isEmpty()) return ""; QCString s = fileToString(macrofile); macrofile = FileInfo(macrofile.str()).absFilePath(); int size = s.length(); GrowBuf out(size); const char *data = s.data(); int line = 1; int cnt = 0; int i = 0; QCString nr; while (i < size) { nr = ""; // skip initial white space, but count lines while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n')) { if (data[i] == '\n') line++; i++; } if (i >= size) break; // check for \newcommand or \renewcommand if (data[i] != '\\') { warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]); return ""; } i++; if (!qstrncmp(data + i, "newcommand", (uint)strlen("newcommand"))) { i += (int)strlen("newcommand"); } else if (!qstrncmp(data + i, "renewcommand", (uint)strlen("renewcommand"))) { i += (int)strlen("renewcommand"); } else { warn(macrofile,line, "file contains non valid code, expected 'newcommand' or 'renewcommand'"); return ""; } // handle {cmd} if (data[i] != '{') { warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]); return ""; } i++; if (data[i] != '\\') { warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]); return ""; } i++; // run till }, i.e. cmd out.addStr(" "); while (i < size && (data[i] != '}')) out.addChar(data[i++]); if (i >= size) { warn(macrofile,line, "file contains non valid code, no closing '}' for command"); return ""; } out.addChar(':'); out.addChar(' '); i++; if (data[i] == '[') { // handle [nr] // run till ] out.addChar('['); i++; while (i < size && (data[i] != ']')) nr += data[i++]; if (i >= size) { warn(macrofile,line, "file contains non valid code, no closing ']'"); return ""; } i++; } else if (data[i] != '{') { warn(macrofile,line, "file contains non valid code, expected '[' or '{' got '%c'\n",data[i]); return ""; } // handle {replacement} // retest as the '[' part might have advanced so we can have a new '{' if (data[i] != '{') { warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]); return ""; } out.addChar('"'); out.addChar('{'); i++; // run till } cnt = 1; while (i < size && cnt) { switch(data[i]) { case '\\': out.addChar('\\'); // need to escape it for MathJax js code out.addChar('\\'); i++; if (data[i] == '\\') // we have an escaped backslash { out.addChar('\\'); out.addChar('\\'); i++; } else if (data[i] != '"') out.addChar(data[i++]); // double quote handled separately break; case '{': cnt++; out.addChar(data[i++]); break; case '}': cnt--; if (cnt) out.addChar(data[i]); i++; break; case '"': out.addChar('\\'); // need to escape it for MathJax js code out.addChar(data[i++]); break; case '\n': line++; out.addChar(data[i++]); break; default: out.addChar(data[i++]); break; } } if (i > size) { warn(macrofile,line, "file contains non valid code, no closing '}' for replacement"); return ""; } out.addChar('}'); out.addChar('"'); if (!nr.isEmpty()) { out.addChar(','); out.addStr(nr); } if (!nr.isEmpty()) { out.addChar(']'); } out.addChar(','); out.addChar('\n'); } out.addChar(0); return out.get(); } static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch) { TextStream t; if (serverSide) { writeServerSearchBox(t, relPath, highlightSearch); } else { writeClientSearchBox(t, relPath); } return t.str(); } static QCString substituteHtmlKeywords(const QCString &str, const QCString &title, const QCString &relPath, const QCString &navPath=QCString()) { // Build CSS/JavaScript tags depending on treeview, search engine settings QCString cssFile; QCString generatedBy; QCString treeViewCssJs; QCString searchCssJs; QCString searchBox; QCString mathJaxJs; QCString extraCssText; QCString projectName = Config_getString(PROJECT_NAME); bool timeStamp = Config_getBool(HTML_TIMESTAMP); bool treeView = Config_getBool(GENERATE_TREEVIEW); bool searchEngine = Config_getBool(SEARCHENGINE); bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); bool mathJax = Config_getBool(USE_MATHJAX); QCString mathJaxFormat = Config_getEnum(MATHJAX_FORMAT); bool disableIndex = Config_getBool(DISABLE_INDEX); bool hasProjectName = !projectName.isEmpty(); bool hasProjectNumber = !Config_getString(PROJECT_NUMBER).isEmpty(); bool hasProjectBrief = !Config_getString(PROJECT_BRIEF).isEmpty(); bool hasProjectLogo = !Config_getString(PROJECT_LOGO).isEmpty(); bool hasFullSideBar = Config_getBool(FULL_SIDEBAR) && disableIndex && treeView; static bool titleArea = (hasProjectName || hasProjectBrief || hasProjectLogo || (disableIndex && searchEngine)); cssFile = Config_getString(HTML_STYLESHEET); if (cssFile.isEmpty()) { cssFile = "doxygen.css"; } else { FileInfo cssfi(cssFile.str()); if (cssfi.exists()) { cssFile = cssfi.fileName(); } else { cssFile = "doxygen.css"; } } extraCssText = ""; const StringVector &extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); for (const auto &fileName : extraCssFile) { if (!fileName.empty()) { FileInfo fi(fileName); if (fi.exists()) { extraCssText += "\n"; } } } if (timeStamp) { generatedBy = theTranslator->trGeneratedAt(dateToString(TRUE), convertToHtml(Config_getString(PROJECT_NAME))); } else { generatedBy = theTranslator->trGeneratedBy(); } if (treeView) { treeViewCssJs = "\n" // "\n" "\n" "\n" "\n"; } if (searchEngine) { searchCssJs = "\n"; if (!serverBasedSearch) { searchCssJs += "\n"; } searchCssJs += "\n"; if (!serverBasedSearch) { if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS)) { searchCssJs += ""; } } else { if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS)) { searchCssJs += "\n"; } // OPENSEARCH_PROVIDER { searchCssJs += ""; // OPENSEARCH_PROVIDER } } searchBox = getSearchBox(serverBasedSearch, relPath, FALSE); } if (mathJax) { QCString mathJaxVersion = Config_getEnum(MATHJAX_VERSION); QCString path = Config_getString(MATHJAX_RELPATH); if (path.isEmpty() || path.left(2)=="..") // relative path { path.prepend(relPath); } if (mathJaxVersion == "MathJax_3") { mathJaxJs += "\n" "\n"; mathJaxJs += "\n"; } else // MathJax v2 { mathJaxJs = "\n"; mathJaxJs += "\n"; } } // first substitute generic keywords QCString result = substituteKeywords(str,title, convertToHtml(Config_getString(PROJECT_NAME)), convertToHtml(Config_getString(PROJECT_NUMBER)), convertToHtml(Config_getString(PROJECT_BRIEF))); // additional HTML only keywords result = substitute(result,"$navpath",navPath); result = substitute(result,"$stylesheet",cssFile); result = substitute(result,"$treeview",treeViewCssJs); result = substitute(result,"$searchbox",searchBox); result = substitute(result,"$search",searchCssJs); result = substitute(result,"$mathjax",mathJaxJs); result = substitute(result,"$generatedby",generatedBy); result = substitute(result,"$extrastylesheet",extraCssText); result = substitute(result,"$relpath$",relPath); //<-- obsolete: for backwards compatibility only result = substitute(result,"$relpath^",relPath); //<-- must be last // additional HTML only conditional blocks result = selectBlock(result,"FULL_SIDEBAR",hasFullSideBar,OutputGenerator::Html); result = selectBlock(result,"DISABLE_INDEX",disableIndex,OutputGenerator::Html); result = selectBlock(result,"GENERATE_TREEVIEW",treeView,OutputGenerator::Html); result = selectBlock(result,"SEARCHENGINE",searchEngine,OutputGenerator::Html); result = selectBlock(result,"TITLEAREA",titleArea,OutputGenerator::Html); result = selectBlock(result,"PROJECT_NAME",hasProjectName,OutputGenerator::Html); result = selectBlock(result,"PROJECT_NUMBER",hasProjectNumber,OutputGenerator::Html); result = selectBlock(result,"PROJECT_BRIEF",hasProjectBrief,OutputGenerator::Html); result = selectBlock(result,"PROJECT_LOGO",hasProjectLogo,OutputGenerator::Html); result = removeEmptyLines(result); return result; } //-------------------------------------------------------------------------- HtmlCodeGenerator::HtmlCodeGenerator(TextStream &t) : m_t(t) { } HtmlCodeGenerator::HtmlCodeGenerator(TextStream &t,const QCString &relPath) : m_t(t), m_relPath(relPath) { } void HtmlCodeGenerator::setRelativePath(const QCString &path) { m_relPath = path; } void HtmlCodeGenerator::codify(const QCString &str) { int tabSize = Config_getInt(TAB_SIZE); if (!str.isEmpty()) { const char *p=str.data(); char c; int spacesToNextTabStop; while (*p) { c=*p++; switch(c) { case '\t': spacesToNextTabStop = tabSize - (m_col%tabSize); m_t << Doxygen::spaces.left(spacesToNextTabStop); m_col+=spacesToNextTabStop; break; case '\n': m_t << "\n"; m_col=0; break; case '\r': break; case '<': m_t << "<"; m_col++; break; case '>': m_t << ">"; m_col++; break; case '&': m_t << "&"; m_col++; break; case '\'': m_t << "'"; m_col++; // ' is not valid XHTML break; case '"': m_t << """; m_col++; break; case '\\': if (*p=='<') { m_t << "<"; p++; } else if (*p=='>') { m_t << ">"; p++; } else if (*p=='(') { m_t << "\\‍("; m_col++;p++; } else if (*p==')') { m_t << "\\‍)"; m_col++;p++; } else m_t << "\\"; m_col++; break; default: { uchar uc = static_cast(c); if (uc<32) { m_t << "$" << hex[uc>>4] << hex[uc&0xF] << ";"; m_col++; } else { p=writeUTF8Char(m_t,p-1); m_col++; } } break; } } } } void HtmlCodeGenerator::docify(const QCString &str) { //m_t << getHtmlDirEmbeddingChar(getTextDirByConfig(str)); if (!str.isEmpty()) { const char *p=str.data(); char c; while (*p) { c=*p++; switch(c) { case '<': m_t << "<"; break; case '>': m_t << ">"; break; case '&': m_t << "&"; break; case '"': m_t << """; break; case '\\': if (*p=='<') { m_t << "<"; p++; } else if (*p=='>') { m_t << ">"; p++; } else if (*p=='(') { m_t << "\\‍("; p++; } else if (*p==')') { m_t << "\\‍)"; p++; } else m_t << "\\"; break; default: { uchar uc = static_cast(c); if (uc<32 && !isspace(c)) { m_t << "$" << hex[uc>>4] << hex[uc&0xF] << ";"; } else { m_t << c; } } break; } } } } void HtmlCodeGenerator::writeLineNumber(const QCString &ref,const QCString &filename, const QCString &anchor,int l) { const int maxLineNrStr = 10; char lineNumber[maxLineNrStr]; char lineAnchor[maxLineNrStr]; qsnprintf(lineNumber,maxLineNrStr,"%5d",l); qsnprintf(lineAnchor,maxLineNrStr,"l%05d",l); if (!m_lineOpen) { m_t << "
"; m_lineOpen = TRUE; } m_t << ""; if (!filename.isEmpty()) { _writeCodeLink("line",ref,filename,anchor,lineNumber,QCString()); } else { codify(lineNumber); } m_t << ""; m_t << " "; m_col=0; } void HtmlCodeGenerator::writeCodeLink(const QCString &ref,const QCString &f, const QCString &anchor, const QCString &name, const QCString &tooltip) { //printf("writeCodeLink(ref=%s,f=%s,anchor=%s,name=%s,tooltip=%s)\n",ref,f,anchor,name,tooltip); _writeCodeLink("code",ref,f,anchor,name,tooltip); } void HtmlCodeGenerator::_writeCodeLink(const QCString &className, const QCString &ref,const QCString &f, const QCString &anchor, const QCString &name, const QCString &tooltip) { if (!ref.isEmpty()) { m_t << ""; docify(name); m_t << ""; m_col+=name.length(); } void HtmlCodeGenerator::writeTooltip(const QCString &id, const DocLinkInfo &docInfo, const QCString &decl, const QCString &desc, const SourceLinkInfo &defInfo, const SourceLinkInfo &declInfo) { m_t << "
"; m_t << "
"; if (!docInfo.url.isEmpty()) { m_t << ""; } docify(docInfo.name); if (!docInfo.url.isEmpty()) { m_t << ""; } m_t << "
"; if (!decl.isEmpty()) { m_t << "
"; docify(decl); m_t << "
"; } if (!desc.isEmpty()) { m_t << "
"; docify(desc); m_t << "
"; } if (!defInfo.file.isEmpty()) { m_t << "
Definition: "; if (!defInfo.url.isEmpty()) { m_t << ""; } m_t << defInfo.file << ":" << defInfo.line; if (!defInfo.url.isEmpty()) { m_t << ""; } m_t << "
"; } if (!declInfo.file.isEmpty()) { m_t << "
Declaration: "; if (!declInfo.url.isEmpty()) { m_t << ""; } m_t << declInfo.file << ":" << declInfo.line; if (!declInfo.url.isEmpty()) { m_t << ""; } m_t << "
"; } m_t << "
\n"; } void HtmlCodeGenerator::startCodeLine(bool) { m_col=0; if (!m_lineOpen) { m_t << "
"; m_lineOpen = TRUE; } } void HtmlCodeGenerator::endCodeLine() { if (m_col == 0) { m_t << " "; m_col++; } if (m_lineOpen) { m_t << "
\n"; m_lineOpen = FALSE; } } void HtmlCodeGenerator::startFontClass(const QCString &s) { m_t << ""; } void HtmlCodeGenerator::endFontClass() { m_t << ""; } void HtmlCodeGenerator::writeCodeAnchor(const QCString &anchor) { m_t << ""; } void HtmlCodeGenerator::startCodeFragment(const QCString &) { m_t << "
"; } void HtmlCodeGenerator::endCodeFragment(const QCString &) { //endCodeLine checks is there is still an open code line, if so closes it. endCodeLine(); m_t << "
"; } //-------------------------------------------------------------------------- HtmlGenerator::HtmlGenerator() : OutputGenerator(Config_getString(HTML_OUTPUT)), m_codeGen(m_t) { } HtmlGenerator::HtmlGenerator(const HtmlGenerator &og) : OutputGenerator(og), m_codeGen(og.m_codeGen) { } HtmlGenerator &HtmlGenerator::operator=(const HtmlGenerator &og) { OutputGenerator::operator=(og); return *this; } std::unique_ptr HtmlGenerator::clone() const { return std::make_unique(*this); } HtmlGenerator::~HtmlGenerator() { //printf("HtmlGenerator::~HtmlGenerator()\n"); } void HtmlGenerator::init() { QCString dname = Config_getString(HTML_OUTPUT); Dir d(dname.str()); if (!d.exists() && !d.mkdir(dname.str())) { term("Could not create output directory %s\n",qPrint(dname)); } //writeLogo(dname); if (!Config_getString(HTML_HEADER).isEmpty()) { g_header=fileToString(Config_getString(HTML_HEADER)); //printf("g_header='%s'\n",qPrint(g_header)); } else { g_header = ResourceMgr::instance().getAsString("header.html"); } if (!Config_getString(HTML_FOOTER).isEmpty()) { g_footer=fileToString(Config_getString(HTML_FOOTER)); //printf("g_footer='%s'\n",qPrint(g_footer)); } else { g_footer = ResourceMgr::instance().getAsString("footer.html"); } if (Config_getBool(USE_MATHJAX)) { if (!Config_getString(MATHJAX_CODEFILE).isEmpty()) { g_mathjax_code=fileToString(Config_getString(MATHJAX_CODEFILE)); //printf("g_mathjax_code='%s'\n",qPrint(g_mathjax_code)); } g_latex_macro=getConvertLatexMacro(); //printf("converted g_latex_macro='%s'\n",qPrint(g_latex_macro)); } createSubDirs(d); ResourceMgr &mgr = ResourceMgr::instance(); if (Config_getBool(HTML_DYNAMIC_MENUS)) { mgr.copyResourceAs("tabs.css",dname,"tabs.css"); } else // stylesheet for the 'old' static tabs { mgr.copyResourceAs("fixed_tabs.css",dname,"tabs.css"); } mgr.copyResource("jquery.js",dname); if (Config_getBool(INTERACTIVE_SVG)) { mgr.copyResource("svgpan.js",dname); } if (!Config_getBool(DISABLE_INDEX) && Config_getBool(HTML_DYNAMIC_MENUS)) { mgr.copyResource("menu.js",dname); } { std::ofstream f(dname.str()+"/dynsections.js",std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << mgr.getAsString("dynsections.js"); if (Config_getBool(SOURCE_BROWSER) && Config_getBool(SOURCE_TOOLTIPS)) { t << mgr.getAsString("dynsections_tooltips.js"); } } } } void HtmlGenerator::cleanup() { QCString dname = Config_getString(HTML_OUTPUT); Dir d(dname.str()); clearSubDirs(d); } /// Additional initialization after indices have been created void HtmlGenerator::writeTabData() { Doxygen::indexList->addStyleSheetFile("tabs.css"); QCString dname=Config_getString(HTML_OUTPUT); ResourceMgr &mgr = ResourceMgr::instance(); //writeColoredImgData(dname,colored_tab_data); mgr.copyResource("tab_a.lum",dname); mgr.copyResource("tab_b.lum",dname); mgr.copyResource("tab_h.lum",dname); mgr.copyResource("tab_s.lum",dname); mgr.copyResource("nav_h.lum",dname); mgr.copyResource("nav_f.lum",dname); mgr.copyResource("bc_s.luma",dname); mgr.copyResource("doxygen.svg",dname); mgr.copyResource("closed.luma",dname); mgr.copyResource("open.luma",dname); mgr.copyResource("bdwn.luma",dname); mgr.copyResource("sync_on.luma",dname); mgr.copyResource("sync_off.luma",dname); //{ // unsigned char shadow[6] = { 5, 5, 5, 5, 5, 5 }; // unsigned char shadow_alpha[6] = { 80, 60, 40, 20, 10, 0 }; // ColoredImage img(1,6,shadow,shadow_alpha,0,0,100); // img.save(dname+"/nav_g.png"); //} mgr.copyResource("nav_g.png",dname); } void HtmlGenerator::writeSearchData(const QCString &dname) { bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); //writeImgData(dname,serverBasedSearch ? search_server_data : search_client_data); ResourceMgr &mgr = ResourceMgr::instance(); mgr.copyResource("search_l.png",dname); Doxygen::indexList->addImageFile("search/search_l.png"); mgr.copyResource("search_m.png",dname); Doxygen::indexList->addImageFile("search/search_m.png"); mgr.copyResource("search_r.png",dname); Doxygen::indexList->addImageFile("search/search_r.png"); if (serverBasedSearch) { mgr.copyResource("mag.svg",dname); Doxygen::indexList->addImageFile("search/mag.svg"); } else { mgr.copyResource("close.svg",dname); Doxygen::indexList->addImageFile("search/close.svg"); mgr.copyResource("mag_sel.svg",dname); Doxygen::indexList->addImageFile("search/mag_sel.svg"); } QCString searchDirName = dname; std::ofstream f(searchDirName.str()+"/search.css",std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); QCString searchCss; if (Config_getBool(DISABLE_INDEX)) { if (Config_getBool(GENERATE_TREEVIEW) && Config_getBool(FULL_SIDEBAR)) { searchCss = mgr.getAsString("search_sidebar.css"); } else { searchCss = mgr.getAsString("search_nomenu.css"); } } else if (!Config_getBool(HTML_DYNAMIC_MENUS)) { searchCss = mgr.getAsString("search_fixedtabs.css"); } else { searchCss = mgr.getAsString("search.css"); } searchCss += mgr.getAsString("search_common.css"); searchCss = substitute(replaceColorMarkers(searchCss),"$doxygenversion",getDoxygenVersion()); t << searchCss; Doxygen::indexList->addStyleSheetFile("search/search.css"); } } void HtmlGenerator::writeStyleSheetFile(TextStream &t) { t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getDoxygenVersion())); } void HtmlGenerator::writeHeaderFile(TextStream &t, const QCString & /*cssname*/) { t << "\n"; t << ResourceMgr::instance().getAsString("header.html"); } void HtmlGenerator::writeFooterFile(TextStream &t) { t << "\n"; t << ResourceMgr::instance().getAsString("footer.html"); } static std::mutex g_indexLock; void HtmlGenerator::startFile(const QCString &name,const QCString &, const QCString &title,int id) { //printf("HtmlGenerator::startFile(%s)\n",qPrint(name)); m_relPath = relativePathToRoot(name); QCString fileName = addHtmlExtensionIfMissing(name); m_lastTitle=title; startPlainFile(fileName); m_codeGen.setId(id); m_codeGen.setRelativePath(m_relPath); { std::lock_guard lock(g_indexLock); Doxygen::indexList->addIndexFile(fileName); } m_lastFile = fileName; m_t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),m_relPath); m_t << "\n"; //bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); bool searchEngine = Config_getBool(SEARCHENGINE); if (searchEngine /*&& !generateTreeView*/) { m_t << "\n"; } //generateDynamicSections(t,relPath); m_sectionCount=0; } void HtmlGenerator::writeSearchInfo(TextStream &t,const QCString &) { bool searchEngine = Config_getBool(SEARCHENGINE); bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); if (searchEngine && !serverBasedSearch) { t << "\n"; t << "
\n"; t << "
\n"; t << "\n"; t << "\n"; t << "
\n"; t << "\n"; t << "
\n"; t << "\n"; } } void HtmlGenerator::writeSearchInfo() { writeSearchInfo(m_t,m_relPath); } QCString HtmlGenerator::writeLogoAsString(const QCString &path) { bool timeStamp = Config_getBool(HTML_TIMESTAMP); QCString result; if (timeStamp) { result += theTranslator->trGeneratedAt( dateToString(TRUE), Config_getString(PROJECT_NAME) ); } else { result += theTranslator->trGeneratedBy(); } result += " \n\n" "\"doxygen\"/ "; result += getDoxygenVersion(); result += " "; return result; } void HtmlGenerator::writeLogo() { m_t << writeLogoAsString(m_relPath); } void HtmlGenerator::writePageFooter(TextStream &t,const QCString &lastTitle, const QCString &relPath,const QCString &navPath) { t << substituteHtmlKeywords(g_footer,convertToHtml(lastTitle),relPath,navPath); } void HtmlGenerator::writeFooter(const QCString &navPath) { writePageFooter(m_t,m_lastTitle,m_relPath,navPath); } void HtmlGenerator::endFile() { endPlainFile(); } void HtmlGenerator::startProjectNumber() { m_t << "

"; } void HtmlGenerator::endProjectNumber() { m_t << "

"; } void HtmlGenerator::writeStyleInfo(int part) { //printf("writeStyleInfo(%d)\n",part); if (part==0) { if (Config_getString(HTML_STYLESHEET).isEmpty()) // write default style sheet { //printf("write doxygen.css\n"); startPlainFile("doxygen.css"); // alternative, cooler looking titles //t << "H1 { text-align: center; border-width: thin none thin none;\n"; //t << " border-style : double; border-color : blue; padding-left : 1em; padding-right : 1em }\n"; m_t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getDoxygenVersion())); endPlainFile(); Doxygen::indexList->addStyleSheetFile("doxygen.css"); } else // write user defined style sheet { QCString cssname=Config_getString(HTML_STYLESHEET); FileInfo cssfi(cssname.str()); if (!cssfi.exists() || !cssfi.isFile() || !cssfi.isReadable()) { err("style sheet %s does not exist or is not readable!", qPrint(Config_getString(HTML_STYLESHEET))); } else { // convert style sheet to string QCString fileStr = fileToString(cssname); // write the string into the output dir startPlainFile(cssfi.fileName().c_str()); m_t << fileStr; endPlainFile(); } Doxygen::indexList->addStyleSheetFile(cssfi.fileName().c_str()); } const StringVector &extraCssFiles = Config_getList(HTML_EXTRA_STYLESHEET); for (const auto &fileName : extraCssFiles) { if (!fileName.empty()) { FileInfo fi(fileName); if (fi.exists()) { Doxygen::indexList->addStyleSheetFile(fi.fileName().c_str()); } } } Doxygen::indexList->addStyleSheetFile("jquery.js"); Doxygen::indexList->addStyleSheetFile("dynsections.js"); if (Config_getBool(INTERACTIVE_SVG)) { Doxygen::indexList->addStyleSheetFile("svgpan.js"); } } } void HtmlGenerator::startDoxyAnchor(const QCString &,const QCString &, const QCString &anchor, const QCString &, const QCString &) { m_t << ""; } void HtmlGenerator::endDoxyAnchor(const QCString &,const QCString &) { } //void HtmlGenerator::newParagraph() //{ // t << "\n

\n"; //} void HtmlGenerator::startParagraph(const QCString &classDef) { if (!classDef.isEmpty()) m_t << "\n

"; else m_t << "\n

"; } void HtmlGenerator::endParagraph() { m_t << "

\n"; } void HtmlGenerator::writeString(const QCString &text) { m_t << text; } void HtmlGenerator::startIndexListItem() { m_t << "
  • "; } void HtmlGenerator::endIndexListItem() { m_t << "
  • \n"; } void HtmlGenerator::startIndexItem(const QCString &ref,const QCString &f) { //printf("HtmlGenerator::startIndexItem(%s,%s)\n",ref,f); if (!ref.isEmpty() || !f.isEmpty()) { if (!ref.isEmpty()) { m_t << ""; } else { m_t << ""; } } void HtmlGenerator::endIndexItem(const QCString &ref,const QCString &f) { //printf("HtmlGenerator::endIndexItem(%s,%s,%s)\n",ref,f,name); if (!ref.isEmpty() || !f.isEmpty()) { m_t << ""; } else { m_t << ""; } } void HtmlGenerator::writeStartAnnoItem(const QCString &,const QCString &f, const QCString &path,const QCString &name) { m_t << "
  • "; if (!path.isEmpty()) docify(path); m_t << ""; docify(name); m_t << " "; } void HtmlGenerator::writeObjectLink(const QCString &ref,const QCString &f, const QCString &anchor, const QCString &name) { if (!ref.isEmpty()) { m_t << ""; docify(name); m_t << ""; } void HtmlGenerator::startTextLink(const QCString &f,const QCString &anchor) { m_t << ""; } void HtmlGenerator::endTextLink() { m_t << ""; } void HtmlGenerator::startHtmlLink(const QCString &url) { bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); m_t << ""; } void HtmlGenerator::endHtmlLink() { m_t << ""; } void HtmlGenerator::startGroupHeader(int extraIndentLevel) { if (extraIndentLevel==2) { m_t << "

    "; } else if (extraIndentLevel==1) { m_t << "

    "; } else // extraIndentLevel==0 { m_t << "

    "; } } void HtmlGenerator::endGroupHeader(int extraIndentLevel) { if (extraIndentLevel==2) { m_t << "

    \n"; } else if (extraIndentLevel==1) { m_t << "\n"; } else { m_t << "\n"; } } void HtmlGenerator::startSection(const QCString &lab,const QCString &,SectionType type) { switch(type) { case SectionType::Page: m_t << "\n\n

    "; break; case SectionType::Section: m_t << "\n\n

    "; break; case SectionType::Subsection: m_t << "\n\n

    "; break; case SectionType::Subsubsection: m_t << "\n\n

    "; break; case SectionType::Paragraph: m_t << "\n\n

    "; break; default: ASSERT(0); break; } m_t << ""; } void HtmlGenerator::endSection(const QCString &,SectionType type) { switch(type) { case SectionType::Page: m_t << "
    "; break; case SectionType::Section: m_t << ""; break; case SectionType::Subsection: m_t << ""; break; case SectionType::Subsubsection: m_t << ""; break; case SectionType::Paragraph: m_t << ""; break; default: ASSERT(0); break; } } void HtmlGenerator::docify(const QCString &str) { docify(str,FALSE); } void HtmlGenerator::docify(const QCString &str,bool inHtmlComment) { if (!str.isEmpty()) { const char *p=str.data(); char c; while (*p) { c=*p++; switch(c) { case '<': m_t << "<"; break; case '>': m_t << ">"; break; case '&': m_t << "&"; break; case '"': m_t << """; break; case '-': if (inHtmlComment) m_t << "-"; else m_t << "-"; break; case '\\': if (*p=='<') { m_t << "<"; p++; } else if (*p=='>') { m_t << ">"; p++; } else if (*p=='(') { m_t << "\\‍("; p++; } else if (*p==')') { m_t << "\\‍)"; p++; } else m_t << "\\"; break; default: m_t << c; } } } } void HtmlGenerator::writeChar(char c) { char cs[2]; cs[0]=c; cs[1]=0; docify(cs); } //--- helper function for dynamic sections ------------------------- static void startSectionHeader(TextStream &t, const QCString &relPath,int sectionCount) { //t << ""; bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS); if (dynamicSections) { t << "
    \n"; t << " \"+\"/ "; } else { t << "
    \n"; } } static void endSectionHeader(TextStream &t) { //t << ""; t << "
    \n"; } static void startSectionSummary(TextStream &t,int sectionCount) { //t << ""; bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS); if (dynamicSections) { t << "
    \n"; } } static void endSectionSummary(TextStream &t) { //t << ""; bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS); if (dynamicSections) { t << "
    \n"; } } static void startSectionContent(TextStream &t,int sectionCount) { //t << ""; bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS); if (dynamicSections) { t << "
    \n"; } else { t << "
    \n"; } } static void endSectionContent(TextStream &t) { //t << ""; t << "
    \n"; } //---------------------------- void HtmlGenerator::startClassDiagram() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endClassDiagram(const ClassDiagram &d, const QCString &fileName,const QCString &name) { endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); TextStream tt; d.writeImage(tt,dir(),m_relPath,fileName); if (!tt.empty()) { m_t << "
    \n"; m_t << " \"\"/\n"; m_t << " \n"; m_t << tt.str(); m_t << " \n"; m_t << "
    "; } else { m_t << "
    \n"; m_t << " \"\"/\n"; m_t << "
    "; } endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::startMemberList() { DBG_HTML(m_t << "\n") } void HtmlGenerator::endMemberList() { DBG_HTML(m_t << "\n") } // anonymous type: // 0 = single column right aligned // 1 = double column left aligned // 2 = single column left aligned void HtmlGenerator::startMemberItem(const QCString &anchor,int annoType,const QCString &inheritId) { DBG_HTML(m_t << "\n") if (m_emptySection) { m_t << "\n"; m_emptySection=FALSE; } m_t << ""; insertMemberAlignLeft(annoType, true); } void HtmlGenerator::endMemberItem() { m_t << "\n"; } void HtmlGenerator::startMemberTemplateParams() { } void HtmlGenerator::endMemberTemplateParams(const QCString &anchor,const QCString &inheritId) { m_t << "\n"; m_t << ""; switch(annoType) { case 0: m_t << "
    "; } void HtmlGenerator::startCompoundTemplateParams() { m_t << "
    "; } void HtmlGenerator::endCompoundTemplateParams() { m_t << "
    "; } void HtmlGenerator::insertMemberAlign(bool templ) { DBG_HTML(m_t << "\n") QCString className = templ ? "memTemplItemRight" : "memItemRight"; m_t << " 
    "; } void HtmlGenerator::insertMemberAlignLeft(int annoType, bool initTag) { if (!initTag) m_t << " "; break; case 1: m_t << ""; break; case 2: m_t << ""; break; default: m_t << ""; break; } } void HtmlGenerator::startMemberDescription(const QCString &anchor,const QCString &inheritId, bool typ) { DBG_HTML(m_t << "\n") if (m_emptySection) { m_t << "\n"; m_emptySection=FALSE; } m_t << ""; m_t << ""; if (typ) m_t << ""; m_t << "\n"; } void HtmlGenerator::startMemberSections() { DBG_HTML(m_t << "\n") m_emptySection=TRUE; // we postpone writing
      ";; } void HtmlGenerator::endMemberDescription() { DBG_HTML(m_t << "\n") m_t << "
    until we actually // write a row to prevent empty tables, which // are not valid XHTML! } void HtmlGenerator::endMemberSections() { DBG_HTML(m_t << "\n") if (!m_emptySection) { m_t << "
    \n"; } } void HtmlGenerator::startMemberHeader(const QCString &anchor, int typ) { DBG_HTML(m_t << "\n") if (!m_emptySection) { m_t << "
    "; m_emptySection=TRUE; } if (m_emptySection) { m_t << "\n"; m_emptySection=FALSE; } m_t << "\n"; } void HtmlGenerator::startMemberSubtitle() { DBG_HTML(m_t << "\n") m_t << "\n"; } void HtmlGenerator::startIndexList() { m_t << "

    "; if (!anchor.isEmpty()) { m_t << "\n"; } } void HtmlGenerator::endMemberHeader() { DBG_HTML(m_t << "\n") m_t << "

    "; } void HtmlGenerator::endMemberSubtitle() { DBG_HTML(m_t << "\n") m_t << "
    \n"; } void HtmlGenerator::endIndexList() { m_t << "
    \n"; } void HtmlGenerator::startIndexKey() { // inserted 'class = ...', 02 jan 2002, jh m_t << " "; } void HtmlGenerator::endIndexKey() { m_t << ""; } void HtmlGenerator::startIndexValue(bool) { // inserted 'class = ...', 02 jan 2002, jh m_t << ""; } void HtmlGenerator::endIndexValue(const QCString &,bool) { m_t << "\n"; } void HtmlGenerator::startMemberDocList() { DBG_HTML(m_t << "\n";) } void HtmlGenerator::endMemberDocList() { DBG_HTML(m_t << "\n";) } void HtmlGenerator::startMemberDoc( const QCString &clName, const QCString &memName, const QCString &anchor, const QCString &title, int memCount, int memTotal, bool showInline) { DBG_HTML(m_t << "\n";) m_t << "\n

    " << "◆ "; docify(title); if (memTotal>1) { m_t << " [" << memCount << "/" << memTotal <<"]"; } m_t << "

    \n"; m_t << "\n
    \n"; m_t << "
    \n"; } void HtmlGenerator::startMemberDocPrefixItem() { DBG_HTML(m_t << "\n";) m_t << "
    \n"; } void HtmlGenerator::endMemberDocPrefixItem() { DBG_HTML(m_t << "\n";) m_t << "
    \n"; } void HtmlGenerator::startMemberDocName(bool /*align*/) { DBG_HTML(m_t << "\n";) m_t << " \n"; m_t << " \n"; m_t << " \n"; } void HtmlGenerator::startParameterList(bool openBracket) { DBG_HTML(m_t << "\n";) m_t << " \n"; } void HtmlGenerator::startParameterType(bool first,const QCString &key) { if (first) { DBG_HTML(m_t << "\n";) m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; } void HtmlGenerator::startParameterName(bool /*oneArgOnly*/) { DBG_HTML(m_t << "\n";) m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; } } void HtmlGenerator::endParameterList() { DBG_HTML(m_t << "\n";) m_t << "\n"; m_t << " \n"; } void HtmlGenerator::exceptionEntry(const QCString &prefix,bool closeBracket) { DBG_HTML(m_t << "\n";) m_t << "\n"; m_t << " \n"; m_t << " \n"; m_t << " \n"; } m_t << "
    "; } void HtmlGenerator::endMemberDocName() { DBG_HTML(m_t << "\n";) m_t << ""; if (openBracket) m_t << "("; m_t << ""; } else { DBG_HTML(m_t << "\n";) m_t << "
    " << key << ""; } } void HtmlGenerator::endParameterType() { DBG_HTML(m_t << "\n";) m_t << " "; } void HtmlGenerator::endParameterName(bool last,bool emptyList,bool closeBracket) { DBG_HTML(m_t << "\n";) if (last) { if (emptyList) { if (closeBracket) m_t << ")"; m_t << ""; } else { m_t << " 
    "; if (closeBracket) m_t << ")"; m_t << ""; } } else { m_t << "
    "; // colspan 2 so it gets both parameter type and parameter name columns if (!prefix.isEmpty()) m_t << prefix << "("; else if (closeBracket) m_t << ")"; else m_t << ""; } void HtmlGenerator::endMemberDoc(bool hasArgs) { DBG_HTML(m_t << "\n";) if (!hasArgs) { m_t << "
    \n"; // m_t << "
    \n"; } void HtmlGenerator::startDotGraph() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endDotGraph(DotClassGraph &g) { bool generateLegend = Config_getBool(GENERATE_LEGEND); bool umlLook = Config_getBool(UML_LOOK); endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); g.writeGraph(m_t,GOF_BITMAP,EOF_Html,dir(),fileName(),m_relPath,TRUE,TRUE,m_sectionCount); if (generateLegend && !umlLook) { m_t << "
    ["; startHtmlLink((m_relPath+"graph_legend"+Doxygen::htmlFileExtension)); m_t << theTranslator->trLegend(); endHtmlLink(); m_t << "]
    "; } endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::startInclDepGraph() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g) { endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); g.writeGraph(m_t,GOF_BITMAP,EOF_Html,dir(),fileName(),m_relPath,TRUE,m_sectionCount); endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::startGroupCollaboration() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g) { endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); g.writeGraph(m_t,GOF_BITMAP,EOF_Html,dir(),fileName(),m_relPath,TRUE,m_sectionCount); endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::startCallGraph() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endCallGraph(DotCallGraph &g) { endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); g.writeGraph(m_t,GOF_BITMAP,EOF_Html,dir(),fileName(),m_relPath,TRUE,m_sectionCount); endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::startDirDepGraph() { startSectionHeader(m_t,m_relPath,m_sectionCount); } void HtmlGenerator::endDirDepGraph(DotDirDeps &g) { endSectionHeader(m_t); startSectionSummary(m_t,m_sectionCount); endSectionSummary(m_t); startSectionContent(m_t,m_sectionCount); g.writeGraph(m_t,GOF_BITMAP,EOF_Html,dir(),fileName(),m_relPath,TRUE,m_sectionCount); endSectionContent(m_t); m_sectionCount++; } void HtmlGenerator::writeGraphicalHierarchy(DotGfxHierarchyTable &g) { g.writeGraph(m_t,dir(),fileName()); } void HtmlGenerator::startMemberGroupHeader(bool) { m_t << "
    "; } void HtmlGenerator::endMemberGroupHeader() { m_t << "
    \n"; } void HtmlGenerator::startMemberGroupDocs() { m_t << "
    "; } void HtmlGenerator::endMemberGroupDocs() { m_t << "
    \n"; } void HtmlGenerator::startMemberGroup() { } void HtmlGenerator::endMemberGroup(bool) { } void HtmlGenerator::startIndent() { DBG_HTML(m_t << "\n";) m_t << "
    \n"; } void HtmlGenerator::endIndent() { DBG_HTML(m_t << "\n";) m_t << "\n
    \n" << "
    \n"; } void HtmlGenerator::addIndexItem(const QCString &,const QCString &) { } void HtmlGenerator::writeNonBreakableSpace(int n) { int i; for (i=0;i\n" << "" << title << ""; } void HtmlGenerator::endDescTable() { m_t << "\n"; } void HtmlGenerator::startDescTableRow() { m_t << ""; } void HtmlGenerator::endDescTableRow() { m_t << "\n"; } void HtmlGenerator::startDescTableTitle() { m_t << ""; } void HtmlGenerator::endDescTableTitle() { m_t << " "; } void HtmlGenerator::startDescTableData() { m_t << ""; } void HtmlGenerator::endDescTableData() { m_t << ""; } void HtmlGenerator::startExamples() { m_t << "
    "; docify(theTranslator->trExamples()); m_t << "
    "; } void HtmlGenerator::endExamples() { m_t << "
    \n"; } void HtmlGenerator::startParamList(ParamListTypes, const QCString &title) { m_t << "
    "; docify(title); m_t << "
    "; } void HtmlGenerator::endParamList() { m_t << "
    "; } void HtmlGenerator::writeDoc(DocNode *n,const Definition *ctx,const MemberDef *,int id) { m_codeGen.setId(id); HtmlDocVisitor *visitor = new HtmlDocVisitor(m_t,m_codeGen,ctx); n->accept(visitor); delete visitor; } //---------------- helpers for index generation ----------------------------- static void startQuickIndexList(TextStream &t,bool compact,bool topLevel=TRUE) { if (compact) { if (topLevel) { t << "
    \n"; } else { t << "
    \n"; } t << "
      \n"; } else { t << "
        "; } } static void endQuickIndexList(TextStream &t,bool compact) { if (compact) { t << "
      \n"; t << "
    \n"; } else { t << "\n"; } } static void startQuickIndexItem(TextStream &t,const QCString &l, bool hl,bool /*compact*/, const QCString &relPath) { t << " "; if (!l.isEmpty()) t << ""; t << ""; } static void endQuickIndexItem(TextStream &t,const QCString &l) { t << ""; if (!l.isEmpty()) t << ""; t << "
  • \n"; } static bool quickLinkVisible(LayoutNavEntry::Kind kind) { bool showFiles = Config_getBool(SHOW_FILES); bool showNamespaces = Config_getBool(SHOW_NAMESPACES); switch (kind) { case LayoutNavEntry::MainPage: return TRUE; case LayoutNavEntry::User: return TRUE; case LayoutNavEntry::UserGroup: return TRUE; case LayoutNavEntry::Pages: return indexedPages>0; case LayoutNavEntry::Modules: return documentedGroups>0; case LayoutNavEntry::Namespaces: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceList: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceMembers: return documentedNamespaceMembers[NMHL_All]>0; case LayoutNavEntry::Concepts: return documentedConcepts>0; case LayoutNavEntry::Classes: return annotatedClasses>0; case LayoutNavEntry::ClassList: return annotatedClasses>0; case LayoutNavEntry::ClassIndex: return annotatedClasses>0; case LayoutNavEntry::ClassHierarchy: return hierarchyClasses>0; case LayoutNavEntry::ClassMembers: return documentedClassMembers[CMHL_All]>0; case LayoutNavEntry::Files: return documentedHtmlFiles>0 && showFiles; case LayoutNavEntry::FileList: return documentedHtmlFiles>0 && showFiles; case LayoutNavEntry::FileGlobals: return documentedFileMembers[FMHL_All]>0; case LayoutNavEntry::Examples: return !Doxygen::exampleLinkedMap->empty(); case LayoutNavEntry::Interfaces: return annotatedInterfaces>0; case LayoutNavEntry::InterfaceList: return annotatedInterfaces>0; case LayoutNavEntry::InterfaceIndex: return annotatedInterfaces>0; case LayoutNavEntry::InterfaceHierarchy: return hierarchyInterfaces>0; case LayoutNavEntry::Structs: return annotatedStructs>0; case LayoutNavEntry::StructList: return annotatedStructs>0; case LayoutNavEntry::StructIndex: return annotatedStructs>0; case LayoutNavEntry::Exceptions: return annotatedExceptions>0; case LayoutNavEntry::ExceptionList: return annotatedExceptions>0; case LayoutNavEntry::ExceptionIndex: return annotatedExceptions>0; case LayoutNavEntry::ExceptionHierarchy: return hierarchyExceptions>0; case LayoutNavEntry::None: // should never happen, means not properly initialized assert(kind != LayoutNavEntry::None); return FALSE; } return FALSE; } static void renderQuickLinksAsTree(TextStream &t,const QCString &relPath,LayoutNavEntry *root) { int count=0; for (const auto &entry : root->children()) { if (entry->visible() && quickLinkVisible(entry->kind())) count++; } if (count>0) // at least one item is visible { startQuickIndexList(t,FALSE); for (const auto &entry : root->children()) { if (entry->visible() && quickLinkVisible(entry->kind())) { QCString url = entry->url(); t << "
  • "; t << fixSpaces(entry->title()); t << "\n"; // recursive into child list renderQuickLinksAsTree(t,relPath,entry.get()); t << "
  • "; } } endQuickIndexList(t,FALSE); } } static void renderQuickLinksAsTabs(TextStream &t,const QCString &relPath, LayoutNavEntry *hlEntry,LayoutNavEntry::Kind kind, bool highlightParent,bool highlightSearch) { if (hlEntry->parent()) // first draw the tabs for the parent of hlEntry { renderQuickLinksAsTabs(t,relPath,hlEntry->parent(),kind,highlightParent,highlightSearch); } if (hlEntry->parent() && !hlEntry->parent()->children().empty()) // draw tabs for row containing hlEntry { bool topLevel = hlEntry->parent()->parent()==0; int count=0; for (const auto &entry : hlEntry->parent()->children()) { if (entry->visible() && quickLinkVisible(entry->kind())) count++; } if (count>0) // at least one item is visible { startQuickIndexList(t,TRUE,topLevel); for (const auto &entry : hlEntry->parent()->children()) { if (entry->visible() && quickLinkVisible(entry->kind())) { QCString url = entry->url(); startQuickIndexItem(t,url, entry.get()==hlEntry && (!entry->children().empty() || (entry->kind()==kind && !highlightParent) ), TRUE,relPath); t << fixSpaces(entry->title()); endQuickIndexItem(t,url); } } if (hlEntry->parent()==LayoutDocManager::instance().rootNavEntry()) // first row is special as it contains the search box { bool searchEngine = Config_getBool(SEARCHENGINE); bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); if (searchEngine) { t << "
  • \n"; if (!serverBasedSearch) // pure client side search { writeClientSearchBox(t,relPath); t << "
  • \n"; } else // server based search { writeServerSearchBox(t,relPath,highlightSearch); if (!highlightSearch) { t << " \n"; } } } if (!highlightSearch) // on the search page the index will be ended by the // page itself { endQuickIndexList(t,TRUE); } } else // normal case for other rows than first one { endQuickIndexList(t,TRUE); } } } } static void writeDefaultQuickLinks(TextStream &t,bool compact, HighlightedItem hli, const QCString &file, const QCString &relPath) { bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); bool searchEngine = Config_getBool(SEARCHENGINE); bool externalSearch = Config_getBool(EXTERNAL_SEARCH); LayoutNavEntry *root = LayoutDocManager::instance().rootNavEntry(); LayoutNavEntry::Kind kind = (LayoutNavEntry::Kind)-1; LayoutNavEntry::Kind altKind = (LayoutNavEntry::Kind)-1; // fall back for the old layout file bool highlightParent=FALSE; switch (hli) // map HLI enums to LayoutNavEntry::Kind enums { case HLI_Main: kind = LayoutNavEntry::MainPage; break; case HLI_Modules: kind = LayoutNavEntry::Modules; break; //case HLI_Directories: kind = LayoutNavEntry::Dirs; break; case HLI_Namespaces: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces; break; case HLI_ClassHierarchy: kind = LayoutNavEntry::ClassHierarchy; break; case HLI_InterfaceHierarchy: kind = LayoutNavEntry::InterfaceHierarchy; break; case HLI_ExceptionHierarchy: kind = LayoutNavEntry::ExceptionHierarchy; break; case HLI_Classes: kind = LayoutNavEntry::ClassIndex; altKind = LayoutNavEntry::Classes; break; case HLI_Concepts: kind = LayoutNavEntry::Concepts; break; case HLI_Interfaces: kind = LayoutNavEntry::InterfaceIndex; altKind = LayoutNavEntry::Interfaces; break; case HLI_Structs: kind = LayoutNavEntry::StructIndex; altKind = LayoutNavEntry::Structs; break; case HLI_Exceptions: kind = LayoutNavEntry::ExceptionIndex; altKind = LayoutNavEntry::Exceptions; break; case HLI_AnnotatedClasses: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; break; case HLI_AnnotatedInterfaces: kind = LayoutNavEntry::InterfaceList; altKind = LayoutNavEntry::Interfaces; break; case HLI_AnnotatedStructs: kind = LayoutNavEntry::StructList; altKind = LayoutNavEntry::Structs; break; case HLI_AnnotatedExceptions: kind = LayoutNavEntry::ExceptionList; altKind = LayoutNavEntry::Exceptions; break; case HLI_Files: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files; break; case HLI_NamespaceMembers: kind = LayoutNavEntry::NamespaceMembers; break; case HLI_Functions: kind = LayoutNavEntry::ClassMembers; break; case HLI_Globals: kind = LayoutNavEntry::FileGlobals; break; case HLI_Pages: kind = LayoutNavEntry::Pages; break; case HLI_Examples: kind = LayoutNavEntry::Examples; break; case HLI_UserGroup: kind = LayoutNavEntry::UserGroup; break; case HLI_ClassVisible: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; highlightParent = TRUE; break; case HLI_ConceptVisible: kind = LayoutNavEntry::Concepts; highlightParent = TRUE; break; case HLI_InterfaceVisible: kind = LayoutNavEntry::InterfaceList; altKind = LayoutNavEntry::Interfaces; highlightParent = TRUE; break; case HLI_StructVisible: kind = LayoutNavEntry::StructList; altKind = LayoutNavEntry::Structs; highlightParent = TRUE; break; case HLI_ExceptionVisible: kind = LayoutNavEntry::ExceptionList; altKind = LayoutNavEntry::Exceptions; highlightParent = TRUE; break; case HLI_NamespaceVisible: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces; highlightParent = TRUE; break; case HLI_FileVisible: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files; highlightParent = TRUE; break; case HLI_None: break; case HLI_Search: break; } if (compact && Config_getBool(HTML_DYNAMIC_MENUS)) { QCString searchPage; if (externalSearch) { searchPage = "search" + Doxygen::htmlFileExtension; } else { searchPage = "search.php"; } t << "\n"; t << "\n"; t << "\n"; t << "
    \n"; } else if (compact) // && !Config_getBool(HTML_DYNAMIC_MENUS) { // find highlighted index item LayoutNavEntry *hlEntry = root->find(kind,kind==LayoutNavEntry::UserGroup ? file : QCString()); if (!hlEntry && altKind!=(LayoutNavEntry::Kind)-1) { hlEntry=root->find(altKind); kind=altKind; } if (!hlEntry) // highlighted item not found in the index! -> just show the level 1 index... { highlightParent=TRUE; hlEntry = root->children().front().get(); if (hlEntry==0) { return; // argl, empty index! } } if (kind==LayoutNavEntry::UserGroup) { LayoutNavEntry *e = hlEntry->children().front().get(); if (e) { hlEntry = e; } } renderQuickLinksAsTabs(t,relPath,hlEntry,kind,highlightParent,hli==HLI_Search); } else { renderQuickLinksAsTree(t,relPath,root); } } void HtmlGenerator::endQuickIndices() { m_t << "
    \n"; } QCString HtmlGenerator::writeSplitBarAsString(const QCString &name,const QCString &relpath) { bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); QCString result; // write split bar if (generateTreeView) { if (!Config_getBool(DISABLE_INDEX) || !Config_getBool(FULL_SIDEBAR)) { result += QCString( "
    \n"); } result+= QCString( "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "\n" "
    \n"); } return result; } void HtmlGenerator::writeSplitBar(const QCString &name) { m_t << writeSplitBarAsString(name,m_relPath); } void HtmlGenerator::writeNavigationPath(const QCString &s) { m_t << substitute(s,"$relpath^",m_relPath); } void HtmlGenerator::startContents() { m_t << "
    \n"; } void HtmlGenerator::endContents() { m_t << "
    \n"; } void HtmlGenerator::startPageDoc(const QCString &pageTitle) { m_t << "
    "; } void HtmlGenerator::endPageDoc() { m_t << "
    \n"; } void HtmlGenerator::writeQuickLinks(bool compact,HighlightedItem hli,const QCString &file) { writeDefaultQuickLinks(m_t,compact,hli,file,m_relPath); } // PHP based search script void HtmlGenerator::writeSearchPage() { bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); bool disableIndex = Config_getBool(DISABLE_INDEX); QCString projectName = Config_getString(PROJECT_NAME); QCString htmlOutput = Config_getString(HTML_OUTPUT); // OPENSEARCH_PROVIDER { QCString configFileName = htmlOutput+"/search_config.php"; std::ofstream f(configFileName.str(),std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << " \"" << convertToHtml(projectName) << "\",\n"; t << " 'GENERATE_TREEVIEW' => " << (generateTreeView?"true":"false") << ",\n"; t << " 'DISABLE_INDEX' => " << (disableIndex?"true":"false") << ",\n"; t << ");\n\n"; t << "$translator = array(\n"; t << " 'search_results_title' => \"" << theTranslator->trSearchResultsTitle() << "\",\n"; t << " 'search_results' => array(\n"; t << " 0 => \"" << theTranslator->trSearchResults(0) << "\",\n"; t << " 1 => \"" << theTranslator->trSearchResults(1) << "\",\n"; t << " 2 => \"" << substitute(theTranslator->trSearchResults(2), "$", "\\$") << "\",\n"; t << " ),\n"; t << " 'search_matches' => \"" << theTranslator->trSearchMatches() << "\",\n"; t << " 'search' => \"" << theTranslator->trSearch() << "\",\n"; t << " 'split_bar' => \"" << substitute(substitute(writeSplitBarAsString("search",""), "\"","\\\""), "\n","\\n") << "\",\n"; t << " 'logo' => \"" << substitute(substitute(writeLogoAsString(""), "\"","\\\""), "\n","\\n") << "\",\n"; t << ");\n\n"; t << "?>\n"; } f.close(); ResourceMgr::instance().copyResource("search_functions.php",htmlOutput); ResourceMgr::instance().copyResource("search_opensearch.php",htmlOutput); // OPENSEARCH_PROVIDER } QCString fileName = htmlOutput+"/search.php"; f.open(fileName.str(),std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << substituteHtmlKeywords(g_header,"Search",""); t << "\n"; t << "\n"; if (!Config_getBool(DISABLE_INDEX)) { writeDefaultQuickLinks(t,TRUE,HLI_Search,QCString(),QCString()); } else { t << "
    \n"; } t << "\n"; // Write empty navigation path, to make footer connect properly if (generateTreeView) { t << "\n"; } writePageFooter(t,"Search","",""); } f.close(); QCString scriptName = htmlOutput+"/search/search.js"; f.open(scriptName.str(),std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << ResourceMgr::instance().getAsString("extsearch.js"); } else { err("Failed to open file '%s' for writing...\n",qPrint(scriptName)); } } void HtmlGenerator::writeExternalSearchPage() { bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); QCString dname = Config_getString(HTML_OUTPUT); QCString fileName = dname+"/search"+Doxygen::htmlFileExtension; std::ofstream f(fileName.str(),std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << substituteHtmlKeywords(g_header,"Search",""); t << "\n"; t << "\n"; if (!Config_getBool(DISABLE_INDEX)) { writeDefaultQuickLinks(t,TRUE,HLI_Search,QCString(),QCString()); t << " \n"; t << " \n"; t << "
    \n"; t << " \n"; t << " \n"; t << " \n"; t << " \n"; t << "\n"; } else { t << "\n"; } t << writeSplitBarAsString("search",""); t << "
    \n"; t << "
    \n"; t << "
    " << theTranslator->trSearchResultsTitle() << "
    \n"; t << "
    \n"; t << "
    \n"; t << "
    \n"; t << "
    \n"; t << "
    \n"; if (generateTreeView) { t << "\n"; } writePageFooter(t,"Search","",""); } f.close(); QCString scriptName = dname+"/search/search.js"; f.open(scriptName.str(),std::ofstream::out | std::ofstream::binary); if (f.is_open()) { TextStream t(&f); t << "var searchResultsText=[" << "\"" << theTranslator->trSearchResults(0) << "\"," << "\"" << theTranslator->trSearchResults(1) << "\"," << "\"" << theTranslator->trSearchResults(2) << "\"];\n"; t << "var serverUrl=\"" << Config_getString(SEARCHENGINE_URL) << "\";\n"; t << "var tagMap = {\n"; bool first=TRUE; // add search mappings const StringVector &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS); for (const auto &ml : extraSearchMappings) { QCString mapLine = ml.c_str(); int eqPos = mapLine.find('='); if (eqPos!=-1) // tag command contains a destination { QCString tagName = mapLine.left(eqPos).stripWhiteSpace(); QCString destName = mapLine.right(mapLine.length()-eqPos-1).stripWhiteSpace(); if (!tagName.isEmpty()) { if (!first) t << ",\n"; t << " \"" << tagName << "\": \"" << destName << "\""; first=FALSE; } } } if (!first) t << "\n"; t << "};\n\n"; t << ResourceMgr::instance().getAsString("extsearch.js"); t << "\n"; t << "$(document).ready(function() {\n"; t << " var query = trim(getURLParameter('query'));\n"; t << " if (query) {\n"; t << " searchFor(query,0,20);\n"; t << " } else {\n"; t << " var results = $('#results');\n"; t << " results.html('

    " << theTranslator->trSearchResults(0) << "

    ');\n"; t << " }\n"; t << "});\n"; } else { err("Failed to open file '%s' for writing...\n",qPrint(scriptName)); } } void HtmlGenerator::startConstraintList(const QCString &header) { m_t << "
    \n"; m_t << "
    " << header << "
    \n"; m_t << "\n"; } void HtmlGenerator::startConstraintParam() { m_t << ""; } void HtmlGenerator::startConstraintType() { m_t << ""; } void HtmlGenerator::startConstraintDocs() { m_t << "\n"; } void HtmlGenerator::endConstraintList() { m_t << "
    "; } void HtmlGenerator::endConstraintParam() { m_t << " :"; } void HtmlGenerator::endConstraintType() { m_t << " "; } void HtmlGenerator::endConstraintDocs() { m_t << "
    \n"; m_t << "
    \n"; m_t << "
    \n"; m_t << "
    \n"; } void HtmlGenerator::lineBreak(const QCString &style) { if (!style.isEmpty()) { m_t << "
    \n"; } else { m_t << "
    \n"; } } void HtmlGenerator::startHeaderSection() { m_t << "
    \n"; } void HtmlGenerator::startTitleHead(const QCString &) { m_t << "
    "; startTitle(); } void HtmlGenerator::endTitleHead(const QCString &,const QCString &) { endTitle(); m_t << "
    \n"; } void HtmlGenerator::endHeaderSection() { m_t << "
    \n"; } void HtmlGenerator::startInlineHeader() { if (m_emptySection) { m_t << "\n"; m_emptySection=FALSE; } m_t << "\n"; } void HtmlGenerator::startMemberDocSimple(bool isEnum) { DBG_HTML(m_t << "\n";) m_t << "

    "; } void HtmlGenerator::endInlineHeader() { m_t << "

    \n"; m_t << "\n"; } void HtmlGenerator::endMemberDocSimple(bool) { DBG_HTML(m_t << "\n";) m_t << "
    "; m_t << (isEnum? theTranslator->trEnumerationValues() : theTranslator->trCompoundMembers()) << "
    \n"; } void HtmlGenerator::startInlineMemberType() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::endInlineMemberType() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::startInlineMemberName() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::endInlineMemberName() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::startInlineMemberDoc() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::endInlineMemberDoc() { DBG_HTML(m_t << "\n";) m_t << "\n"; } void HtmlGenerator::startLabels() { DBG_HTML(m_t << "\n";) m_t << ""; } void HtmlGenerator::writeLabel(const QCString &l,bool /*isLast*/) { DBG_HTML(m_t << "\n";) //m_t << "[" << l << "]"; //if (!isLast) m_t << ", "; m_t << "" << l << ""; } void HtmlGenerator::endLabels() { DBG_HTML(m_t << "\n";) m_t << ""; } void HtmlGenerator::writeInheritedSectionTitle( const QCString &id, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &title, const QCString &name) { DBG_HTML(m_t << "\n";) QCString a = anchor; if (!a.isEmpty()) a.prepend("#"); QCString classLink = QCString("")+convertToHtml(name,FALSE)+""; m_t << "" << "" << "\"-\"/ " << theTranslator->trInheritedFrom(convertToHtml(title,FALSE),classLink) << "\n"; } void HtmlGenerator::writeSummaryLink(const QCString &file,const QCString &anchor,const QCString &title,bool first) { if (first) { m_t << "
    \n"; } else { m_t << " |\n"; } m_t << ""; m_t << title; m_t << ""; } void HtmlGenerator::endMemberDeclaration(const QCString &anchor,const QCString &inheritId) { m_t << " \n"; } void HtmlGenerator::setCurrentDoc(const Definition *context,const QCString &anchor,bool isSourceFile) { if (Doxygen::searchIndex) { Doxygen::searchIndex->setCurrentDoc(context,anchor,isSourceFile); } } void HtmlGenerator::addWord(const QCString &word,bool hiPriority) { if (Doxygen::searchIndex) { Doxygen::searchIndex->addWord(word,hiPriority); } } QCString HtmlGenerator::getMathJaxMacros() { return getConvertLatexMacro(); }