/****************************************************************************** * * * * Copyright (C) 1997-2015 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" //#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 bool DoxyCodeLineOpen = FALSE; // 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(FTextStream &t,const char *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(FTextStream &t,const char *relPath,bool highlightSearch) { static 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 = QFileInfo(macrofile).absFilePath().utf8(); 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(); } //------------------------------------------------------------------------ /// Clear a text block \a s from \a begin to \a end markers QCString clearBlock(const char *s,const char *begin,const char *end) { if (s==0 || begin==0 || end==0) return s; const char *p, *q; int beginLen = qstrlen(begin); int endLen = qstrlen(end); int resLen = 0; for (p=s; (q=strstr(p,begin))!=0; p=q+endLen) { resLen+=(int)(q-p); p=q+beginLen; if ((q=strstr(p,end))==0) { resLen+=beginLen; break; } } resLen+=qstrlen(p); // resLen is the length of the string without the marked block QCString result(resLen+1); char *r; for (r=result.rawData(), p=s; (q=strstr(p,begin))!=0; p=q+endLen) { int l = (int)(q-p); memcpy(r,p,l); r+=l; p=q+beginLen; if ((q=strstr(p,end))==0) { memcpy(r,begin,beginLen); r+=beginLen; break; } } qstrcpy(r,p); return result; } //---------------------------------------------------------------------- QCString selectBlock(const QCString& s,const QCString &name,bool enable) { // TODO: this is an expensive function that is called a lot -> optimize it const QCString begin = ""; const QCString end = ""; const QCString nobegin = ""; const QCString noend = ""; QCString result = s; if (enable) { result = substitute(result, begin, ""); result = substitute(result, end, ""); result = clearBlock(result, nobegin, noend); } else { result = substitute(result, nobegin, ""); result = substitute(result, noend, ""); result = clearBlock(result, begin, end); } return result; } static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch) { QGString result; FTextStream t(&result); if (serverSide) { writeServerSearchBox(t, relPath, highlightSearch); } else { writeClientSearchBox(t, relPath); } return QCString(result); } static QCString removeEmptyLines(const QCString &s) { BufStr out(s.length()+1); const char *p=s.data(); if (p) { char c; while ((c=*p++)) { if (c=='\n') { const char *e = p; while (*e==' ' || *e=='\t') e++; if (*e=='\n') { p=e; } else out.addChar(c); } else { out.addChar(c); } } } out.addChar('\0'); //printf("removeEmptyLines(%s)=%s\n",s.data(),out.data()); return out.data(); } 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; QStrList extraCssFile; QCString generatedBy; QCString treeViewCssJs; QCString searchCssJs; QCString searchBox; QCString mathJaxJs; QCString extraCssText; static QCString projectName = Config_getString(PROJECT_NAME); static bool timeStamp = Config_getBool(HTML_TIMESTAMP); static bool treeView = Config_getBool(GENERATE_TREEVIEW); static bool searchEngine = Config_getBool(SEARCHENGINE); static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); static bool mathJax = Config_getBool(USE_MATHJAX); static QCString mathJaxFormat = Config_getEnum(MATHJAX_FORMAT); static bool disableIndex = Config_getBool(DISABLE_INDEX); static bool hasProjectName = !projectName.isEmpty(); static bool hasProjectNumber = !Config_getString(PROJECT_NUMBER).isEmpty(); static bool hasProjectBrief = !Config_getString(PROJECT_BRIEF).isEmpty(); static bool hasProjectLogo = !Config_getString(PROJECT_LOGO).isEmpty(); static bool titleArea = (hasProjectName || hasProjectBrief || hasProjectLogo || (disableIndex && searchEngine)); cssFile = Config_getString(HTML_STYLESHEET); if (cssFile.isEmpty()) { cssFile = "doxygen.css"; } else { QFileInfo cssfi(cssFile); if (cssfi.exists()) { cssFile = cssfi.fileName().utf8(); } else { cssFile = "doxygen.css"; } } extraCssText = ""; extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); for (uint i=0; i\n"; } } } if (timeStamp) { generatedBy = theTranslator->trGeneratedAt(dateToString(TRUE), convertToHtml(Config_getString(PROJECT_NAME))); } else { generatedBy = theTranslator->trGeneratedBy(); } if (treeView) { treeViewCssJs = "\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 path = Config_getString(MATHJAX_RELPATH); if (path.isEmpty() || path.left(2)=="..") // relative path { path.prepend(relPath); } mathJaxJs = "\n"; if (!g_latex_macro.isEmpty()) { 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,"DISABLE_INDEX",disableIndex); result = selectBlock(result,"GENERATE_TREEVIEW",treeView); result = selectBlock(result,"SEARCHENGINE",searchEngine); result = selectBlock(result,"TITLEAREA",titleArea); result = selectBlock(result,"PROJECT_NAME",hasProjectName); result = selectBlock(result,"PROJECT_NUMBER",hasProjectNumber); result = selectBlock(result,"PROJECT_BRIEF",hasProjectBrief); result = selectBlock(result,"PROJECT_LOGO",hasProjectLogo); result = removeEmptyLines(result); return result; } //-------------------------------------------------------------------------- HtmlCodeGenerator::HtmlCodeGenerator() : m_streamSet(FALSE), m_col(0) { } HtmlCodeGenerator::HtmlCodeGenerator(FTextStream &t,const QCString &relPath) : m_col(0), m_relPath(relPath) { setTextStream(t); } void HtmlCodeGenerator::setTextStream(FTextStream &t) { m_streamSet = t.device()!=0; m_t.setDevice(t.device()); } void HtmlCodeGenerator::setRelativePath(const QCString &path) { m_relPath = path; } void HtmlCodeGenerator::codify(const char *str) { static int tabSize = Config_getInt(TAB_SIZE); if (str && m_streamSet) { const char *p=str; 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 m_t << "\\"; m_col++; break; default: p=writeUtf8Char(m_t,p-1); m_col++; break; } } } } void HtmlCodeGenerator::docify(const char *str) { m_t << getHtmlDirEmbeddingChar(getTextDirByConfig(str)); if (str && m_streamSet) { const char *p=str; 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 m_t << "\\"; break; default: m_t << c; } } } } void HtmlCodeGenerator::writeLineNumber(const char *ref,const char *filename, const char *anchor,int l) { if (!m_streamSet) return; const int maxLineNrStr = 10; char lineNumber[maxLineNrStr]; char lineAnchor[maxLineNrStr]; qsnprintf(lineNumber,maxLineNrStr,"%5d",l); qsnprintf(lineAnchor,maxLineNrStr,"l%05d",l); if (!DoxyCodeLineOpen) { m_t << "
"; DoxyCodeLineOpen = TRUE; } m_t << ""; if (filename) { _writeCodeLink("line",ref,filename,anchor,lineNumber,0); } else { codify(lineNumber); } m_t << ""; m_t << " "; m_col=0; } void HtmlCodeGenerator::writeCodeLink(const char *ref,const char *f, const char *anchor, const char *name, const char *tooltip) { if (!m_streamSet) return; //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 char *className, const char *ref,const char *f, const char *anchor, const char *name, const char *tooltip) { if (ref) { m_t << ""; docify(name); m_t << ""; m_col+=qstrlen(name); } void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo, const char *decl, const char *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) { m_t << "
"; docify(decl); m_t << "
"; } if (desc) { 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 << "
" << endl; } void HtmlCodeGenerator::startCodeLine(bool) { if (m_streamSet) { m_col=0; if (!DoxyCodeLineOpen) { m_t << "
"; DoxyCodeLineOpen = TRUE; } } } void HtmlCodeGenerator::endCodeLine() { if (m_streamSet) { if (m_col == 0) { m_t << " "; m_col++; } if (DoxyCodeLineOpen) { m_t << "
\n"; DoxyCodeLineOpen = FALSE; } } } void HtmlCodeGenerator::startFontClass(const char *s) { if (m_streamSet) m_t << ""; } void HtmlCodeGenerator::endFontClass() { if (m_streamSet) m_t << ""; } void HtmlCodeGenerator::writeCodeAnchor(const char *anchor) { if (m_streamSet) m_t << ""; } //-------------------------------------------------------------------------- HtmlGenerator::HtmlGenerator() : OutputGenerator() { m_dir=Config_getString(HTML_OUTPUT); m_emptySection=FALSE; m_sectionCount=0; } HtmlGenerator::~HtmlGenerator() { //printf("HtmlGenerator::~HtmlGenerator()\n"); } void HtmlGenerator::init() { QCString dname=Config_getString(HTML_OUTPUT); QDir d(dname); if (!d.exists() && !d.mkdir(dname)) { term("Could not create output directory %s\n",dname.data()); } //writeLogo(dname); if (!Config_getString(HTML_HEADER).isEmpty()) { g_header=fileToString(Config_getString(HTML_HEADER)); //printf("g_header='%s'\n",g_header.data()); } 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",g_footer.data()); } 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",g_mathjax_code.data()); } g_latex_macro=getConvertLatexMacro(); //printf("converted g_latex_macro='%s'\n",g_latex_macro.data()); } 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); } { QFile f(dname+"/dynsections.js"); if (f.open(IO_WriteOnly)) { FTextStream t(&f); t << mgr.getAsString("dynsections.js"); if (Config_getBool(SOURCE_BROWSER) && Config_getBool(SOURCE_TOOLTIPS)) { t << endl << "$(document).ready(function() {\n" " $('.code,.codeRef').each(function() {\n" " $(this).data('powertip',$('#a'+$(this).attr('href').replace(/.*\\//,'').replace(/[^a-z_A-Z0-9]/g,'_')).html());\n" " $(this).powerTip({ placement: 's', smartPlacement: true, mouseOnToPopup: true });\n" " });\n" "});\n"; } } } } /// 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.luma",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 char *dir) { static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); //writeImgData(dir,serverBasedSearch ? search_server_data : search_client_data); ResourceMgr &mgr = ResourceMgr::instance(); mgr.copyResource("search_l.png",dir); Doxygen::indexList->addImageFile("search/search_l.png"); mgr.copyResource("search_m.png",dir); Doxygen::indexList->addImageFile("search/search_m.png"); mgr.copyResource("search_r.png",dir); Doxygen::indexList->addImageFile("search/search_r.png"); if (serverBasedSearch) { mgr.copyResource("mag.png",dir); Doxygen::indexList->addImageFile("search/mag.png"); } else { mgr.copyResource("close.png",dir); Doxygen::indexList->addImageFile("search/close.png"); mgr.copyResource("mag_sel.png",dir); Doxygen::indexList->addImageFile("search/mag_sel.png"); } QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search"; QFile f(searchDirName+"/search.css"); if (f.open(IO_WriteOnly)) { FTextStream t(&f); QCString searchCss; if (Config_getBool(DISABLE_INDEX)) { 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 = substitute(replaceColorMarkers(searchCss),"$doxygenversion",getVersion()); t << searchCss; Doxygen::indexList->addStyleSheetFile("search/search.css"); } } void HtmlGenerator::writeStyleSheetFile(QFile &file) { FTextStream t(&file); t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getVersion())); } void HtmlGenerator::writeHeaderFile(QFile &file, const char * /*cssname*/) { FTextStream t(&file); t << "" << endl; t << ResourceMgr::instance().getAsString("header.html"); } void HtmlGenerator::writeFooterFile(QFile &file) { FTextStream t(&file); t << "" << endl; t << ResourceMgr::instance().getAsString("footer.html"); } void HtmlGenerator::startFile(const char *name,const char *, const char *title) { //printf("HtmlGenerator::startFile(%s)\n",name); m_relPath = relativePathToRoot(name); QCString fileName = addHtmlExtensionIfMissing(name); m_lastTitle=title; startPlainFile(fileName); m_codeGen.setTextStream(t); m_codeGen.setRelativePath(m_relPath); Doxygen::indexList->addIndexFile(fileName); m_lastFile = fileName; t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),m_relPath); t << "" << endl; //static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); static bool searchEngine = Config_getBool(SEARCHENGINE); if (searchEngine /*&& !generateTreeView*/) { t << "\n"; } //generateDynamicSections(t,relPath); m_sectionCount=0; } void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &) { static bool searchEngine = Config_getBool(SEARCHENGINE); static 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(t,m_relPath); } QCString HtmlGenerator::writeLogoAsString(const char *path) { static 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 += getVersion(); result += " "; return result; } void HtmlGenerator::writeLogo() { t << writeLogoAsString(m_relPath); } void HtmlGenerator::writePageFooter(FTextStream &t,const QCString &lastTitle, const QCString &relPath,const QCString &navPath) { t << substituteHtmlKeywords(g_footer,convertToHtml(lastTitle),relPath,navPath); } void HtmlGenerator::writeFooter(const char *navPath) { // Currently only tooltips in HTML TooltipManager::instance()->writeTooltips(m_codeGen); writePageFooter(t,m_lastTitle,m_relPath,navPath); } void HtmlGenerator::endFile() { endPlainFile(); } void HtmlGenerator::startProjectNumber() { t << "

"; } void HtmlGenerator::endProjectNumber() { 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;" << endl; //t << " border-style : double; border-color : blue; padding-left : 1em; padding-right : 1em }" << endl; t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getVersion())); endPlainFile(); Doxygen::indexList->addStyleSheetFile("doxygen.css"); } else // write user defined style sheet { QCString cssname=Config_getString(HTML_STYLESHEET); QFileInfo cssfi(cssname); if (!cssfi.exists() || !cssfi.isFile() || !cssfi.isReadable()) { err("style sheet %s does not exist or is not readable!", Config_getString(HTML_STYLESHEET).data()); } else { // convert style sheet to string QCString fileStr = fileToString(cssname); // write the string into the output dir startPlainFile(cssfi.fileName().utf8()); t << fileStr; endPlainFile(); } Doxygen::indexList->addStyleSheetFile(cssfi.fileName().utf8()); } static QStrList extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); for (uint i=0; iaddStyleSheetFile(fi.fileName().utf8()); } } } Doxygen::indexList->addStyleSheetFile("jquery.js"); Doxygen::indexList->addStyleSheetFile("dynsections.js"); if (Config_getBool(INTERACTIVE_SVG)) { Doxygen::indexList->addStyleSheetFile("svgpan.js"); } } } void HtmlGenerator::startDoxyAnchor(const char *,const char *, const char *anchor, const char *, const char *) { t << ""; } void HtmlGenerator::endDoxyAnchor(const char *,const char *) { } //void HtmlGenerator::newParagraph() //{ // t << endl << "

" << endl; //} void HtmlGenerator::startParagraph(const char *classDef) { if (classDef) t << endl << "

"; else t << endl << "

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

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

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

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

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

    " << endl; } else if (extraIndentLevel==1) { t << "" << endl; } else { t << "" << endl; } } void HtmlGenerator::startSection(const char *lab,const char *,SectionType type) { switch(type) { case SectionType::Page: t << "\n\n

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

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

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

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

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

    "; if (anchor) { t << "" << endl; } } void HtmlGenerator::endMemberHeader() { DBG_HTML(t << "" << endl) t << "

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

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

    " << endl; t << "\n
    " << endl; t << "
    " << endl; } void HtmlGenerator::startMemberDocPrefixItem() { DBG_HTML(t << "" << endl;) t << "
    " << endl; } void HtmlGenerator::endMemberDocPrefixItem() { DBG_HTML(t << "" << endl;) t << "
    " << endl; } void HtmlGenerator::startMemberDocName(bool /*align*/) { DBG_HTML(t << "" << endl;) t << " " << endl; t << " " << endl; t << " " << endl; } void HtmlGenerator::startParameterList(bool openBracket) { DBG_HTML(t << "" << endl;) t << " " << endl; } void HtmlGenerator::startParameterType(bool first,const char *key) { if (first) { DBG_HTML(t << "" << endl;) t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; } void HtmlGenerator::startParameterName(bool /*oneArgOnly*/) { DBG_HTML(t << "" << endl;) t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; t << " " << endl; } } void HtmlGenerator::endParameterList() { DBG_HTML(t << "" << endl;) t << "" << endl; t << " " << endl; } void HtmlGenerator::exceptionEntry(const char* prefix,bool closeBracket) { DBG_HTML(t << "" << endl;) t << "" << endl; t << " " << endl; t << " " << endl; t << " " << endl; } t << "
    "; } void HtmlGenerator::endMemberDocName() { DBG_HTML(t << "" << endl;) t << ""; if (openBracket) t << "("; t << ""; } else { DBG_HTML(t << "" << endl;) t << "
    "; if (key) t << key; t << ""; } } void HtmlGenerator::endParameterType() { DBG_HTML(t << "" << endl;) t << " "; } void HtmlGenerator::endParameterName(bool last,bool emptyList,bool closeBracket) { DBG_HTML(t << "" << endl;) if (last) { if (emptyList) { if (closeBracket) t << ")"; t << ""; } else { t << " 
    "; if (closeBracket) t << ")"; t << ""; } } else { t << "
    "; // colspan 2 so it gets both parameter type and parameter name columns if (prefix) t << prefix << "("; else if (closeBracket) t << ")"; else t << ""; } void HtmlGenerator::endMemberDoc(bool hasArgs) { DBG_HTML(t << "" << endl;) if (!hasArgs) { t << "
    " << endl; // t << "
    " << endl; } void HtmlGenerator::startDotGraph() { startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endDotGraph(DotClassGraph &g) { bool generateLegend = Config_getBool(GENERATE_LEGEND); bool umlLook = Config_getBool(UML_LOOK); endSectionHeader(t); startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,TRUE,m_sectionCount); if (generateLegend && !umlLook) { t << "
    ["; startHtmlLink(m_relPath+"graph_legend"+Doxygen::htmlFileExtension); t << theTranslator->trLegend(); endHtmlLink(); t << "]
    "; } endSectionContent(t); m_sectionCount++; } void HtmlGenerator::startInclDepGraph() { startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g) { endSectionHeader(t); startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; } void HtmlGenerator::startGroupCollaboration() { startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g) { endSectionHeader(t); startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; } void HtmlGenerator::startCallGraph() { startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endCallGraph(DotCallGraph &g) { endSectionHeader(t); startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; } void HtmlGenerator::startDirDepGraph() { startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endDirDepGraph(DotDirDeps &g) { endSectionHeader(t); startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; } void HtmlGenerator::writeGraphicalHierarchy(DotGfxHierarchyTable &g) { g.writeGraph(t,m_dir,m_fileName); } void HtmlGenerator::startMemberGroupHeader(bool) { t << "
    "; } void HtmlGenerator::endMemberGroupHeader() { t << "
    " << endl; } void HtmlGenerator::startMemberGroupDocs() { t << "
    "; } void HtmlGenerator::endMemberGroupDocs() { t << "
    " << endl; } void HtmlGenerator::startMemberGroup() { } void HtmlGenerator::endMemberGroup(bool) { } void HtmlGenerator::startIndent() { DBG_HTML(t << "" << endl;) t << "
    \n"; } void HtmlGenerator::endIndent() { DBG_HTML(t << "" << endl;) t << endl << "
    " << endl << "
    " << endl; } void HtmlGenerator::addIndexItem(const char *,const char *) { } void HtmlGenerator::writeNonBreakableSpace(int n) { int i; for (i=0;i" << endl << "" << title << ""; } void HtmlGenerator::endDescTable() { t << "" << endl; } void HtmlGenerator::startDescTableRow() { t << ""; } void HtmlGenerator::endDescTableRow() { t << "" << endl; } void HtmlGenerator::startDescTableTitle() { t << ""; } void HtmlGenerator::endDescTableTitle() { t << " "; } void HtmlGenerator::startDescTableData() { t << ""; } void HtmlGenerator::endDescTableData() { t << ""; } void HtmlGenerator::startExamples() { t << "
    "; docify(theTranslator->trExamples()); t << "
    "; } void HtmlGenerator::endExamples() { t << "
    " << endl; } void HtmlGenerator::startParamList(ParamListTypes, const char *title) { t << "
    "; docify(title); t << "
    "; } void HtmlGenerator::endParamList() { t << "
    "; } void HtmlGenerator::writeDoc(DocNode *n,const Definition *ctx,const MemberDef *) { HtmlDocVisitor *visitor = new HtmlDocVisitor(t,m_codeGen,ctx); n->accept(visitor); delete visitor; } //---------------- helpers for index generation ----------------------------- static void startQuickIndexList(FTextStream &t,bool compact,bool topLevel=TRUE) { if (compact) { if (topLevel) { t << "
    \n"; } else { t << "
    \n"; } t << "
      \n"; } else { t << "
        "; } } static void endQuickIndexList(FTextStream &t,bool compact) { if (compact) { t << "
      \n"; t << "
    \n"; } else { t << "\n"; } } static void startQuickIndexItem(FTextStream &t,const char *l, bool hl,bool /*compact*/, const QCString &relPath) { t << " "; if (l) t << ""; t << ""; } static void endQuickIndexItem(FTextStream &t,const char *l) { t << ""; if (l) t << ""; t << "
  • \n"; } static bool quickLinkVisible(LayoutNavEntry::Kind kind) { static bool showFiles = Config_getBool(SHOW_FILES); static 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::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::exampleSDict->count()>0; 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(FTextStream &t,const QCString &relPath,LayoutNavEntry *root) { QListIterator li(root->children()); LayoutNavEntry *entry; int count=0; for (li.toFirst();(entry=li.current());++li) { if (entry->visible() && quickLinkVisible(entry->kind())) count++; } if (count>0) // at least one item is visible { startQuickIndexList(t,FALSE); for (li.toFirst();(entry=li.current());++li) { 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); t << "
  • "; } } endQuickIndexList(t,FALSE); } } static void renderQuickLinksAsTabs(FTextStream &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().count()>0) // draw tabs for row containing hlEntry { bool topLevel = hlEntry->parent()->parent()==0; QListIterator li(hlEntry->parent()->children()); LayoutNavEntry *entry; int count=0; for (li.toFirst();(entry=li.current());++li) { if (entry->visible() && quickLinkVisible(entry->kind())) count++; } if (count>0) // at least one item is visible { startQuickIndexList(t,TRUE,topLevel); for (li.toFirst();(entry=li.current());++li) { if (entry->visible() && quickLinkVisible(entry->kind())) { QCString url = entry->url(); startQuickIndexItem(t,url, entry==hlEntry && (entry->children().count()>0 || (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 { static bool searchEngine = Config_getBool(SEARCHENGINE); static 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(FTextStream &t,bool compact, HighlightedItem hli, const char *file, const QCString &relPath) { static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); static bool searchEngine = Config_getBool(SEARCHENGINE); static 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_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_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 << "" << endl; t << "" << endl; t << "" << endl; t << "
    " << endl; } else if (compact) // && !Config_getBool(HTML_DYNAMIC_MENUS) { // find highlighted index item LayoutNavEntry *hlEntry = root->find(kind,kind==LayoutNavEntry::UserGroup ? file : 0); 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().getFirst(); if (hlEntry==0) { return; // argl, empty index! } } if (kind==LayoutNavEntry::UserGroup) { LayoutNavEntry *e = hlEntry->children().getFirst(); if (e) { hlEntry = e; } } renderQuickLinksAsTabs(t,relPath,hlEntry,kind,highlightParent,hli==HLI_Search); } else { renderQuickLinksAsTree(t,relPath,root); } } void HtmlGenerator::endQuickIndices() { t << "
    " << endl; } QCString HtmlGenerator::writeSplitBarAsString(const char *name,const char *relpath) { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); QCString result; // write split bar if (generateTreeView) { result = QCString( "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "
    \n" "\n" "
    \n"); } return result; } void HtmlGenerator::writeSplitBar(const char *name) { t << writeSplitBarAsString(name,m_relPath); } void HtmlGenerator::writeNavigationPath(const char *s) { t << substitute(s,"$relpath^",m_relPath); } void HtmlGenerator::startContents() { t << "
    " << endl; } void HtmlGenerator::endContents() { t << "
    " << endl; } void HtmlGenerator::startPageDoc(const char *pageTitle) { t << ""; } void HtmlGenerator::endPageDoc() { t << "
    " << endl; } void HtmlGenerator::writeQuickLinks(bool compact,HighlightedItem hli,const char *file) { writeDefaultQuickLinks(t,compact,hli,file,m_relPath); } // PHP based search script void HtmlGenerator::writeSearchPage() { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); static bool disableIndex = Config_getBool(DISABLE_INDEX); static QCString projectName = Config_getString(PROJECT_NAME); static QCString htmlOutput = Config_getString(HTML_OUTPUT); // OPENSEARCH_PROVIDER { QCString configFileName = htmlOutput+"/search_config.php"; QFile cf(configFileName); if (cf.open(IO_WriteOnly)) { FTextStream t(&cf); 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"; } ResourceMgr::instance().copyResource("search_functions.php",htmlOutput); ResourceMgr::instance().copyResource("search_opensearch.php",htmlOutput); // OPENSEARCH_PROVIDER } QCString fileName = htmlOutput+"/search.php"; QFile f(fileName); if (f.open(IO_WriteOnly)) { FTextStream t(&f); t << substituteHtmlKeywords(g_header,"Search",""); t << "" << endl; t << "\n"; if (!Config_getBool(DISABLE_INDEX)) { writeDefaultQuickLinks(t,TRUE,HLI_Search,0,""); } else { t << "" << endl; } t << "\n"; // Write empty navigation path, to make footer connect properly if (generateTreeView) { t << "\n"; } writePageFooter(t,"Search","",""); } QCString scriptName = htmlOutput+"/search/search.js"; QFile sf(scriptName); if (sf.open(IO_WriteOnly)) { FTextStream t(&sf); t << ResourceMgr::instance().getAsString("extsearch.js"); } else { err("Failed to open file '%s' for writing...\n",scriptName.data()); } } void HtmlGenerator::writeExternalSearchPage() { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); QCString fileName = Config_getString(HTML_OUTPUT)+"/search"+Doxygen::htmlFileExtension; QFile f(fileName); if (f.open(IO_WriteOnly)) { FTextStream t(&f); t << substituteHtmlKeywords(g_header,"Search",""); t << "" << endl; t << "\n"; if (!Config_getBool(DISABLE_INDEX)) { writeDefaultQuickLinks(t,TRUE,HLI_Search,0,""); t << " \n"; t << " \n"; t << "
    \n"; t << " \n"; t << " \n"; t << " \n"; t << " \n"; t << "\n"; } else { t << "" << endl; } t << writeSplitBarAsString("search",""); t << "
    " << endl; t << "
    " << endl; t << "
    " << theTranslator->trSearchResultsTitle() << "
    " << endl; t << "
    " << endl; t << "
    " << endl; t << "
    " << endl; t << "
    " << endl; t << "
    " << endl; if (generateTreeView) { t << "" << endl; } writePageFooter(t,"Search","",""); } QCString scriptName = Config_getString(HTML_OUTPUT)+"/search/search.js"; QFile sf(scriptName); if (sf.open(IO_WriteOnly)) { FTextStream t(&sf); t << "var searchResultsText=[" << "\"" << theTranslator->trSearchResults(0) << "\"," << "\"" << theTranslator->trSearchResults(1) << "\"," << "\"" << theTranslator->trSearchResults(2) << "\"];" << endl; t << "var serverUrl=\"" << Config_getString(SEARCHENGINE_URL) << "\";" << endl; t << "var tagMap = {" << endl; bool first=TRUE; // add search mappings QStrList &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS); char *ml=extraSearchMappings.first(); while (ml) { QCString mapLine = ml; 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 << "," << endl; t << " \"" << tagName << "\": \"" << destName << "\""; first=FALSE; } } ml=extraSearchMappings.next(); } if (!first) t << endl; t << "};" << endl << endl; t << ResourceMgr::instance().getAsString("extsearch.js"); t << endl; t << "$(document).ready(function() {" << endl; t << " var query = trim(getURLParameter('query'));" << endl; t << " if (query) {" << endl; t << " searchFor(query,0,20);" << endl; t << " } else {" << endl; t << " var results = $('#results');" << endl; t << " results.html('

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

    ');" << endl; t << " }" << endl; t << "});" << endl; } else { err("Failed to open file '%s' for writing...\n",scriptName.data()); } } void HtmlGenerator::startConstraintList(const char *header) { t << "
    " << endl; t << "
    " << header << "
    " << endl; t << "" << endl; } void HtmlGenerator::startConstraintParam() { t << ""; } void HtmlGenerator::startConstraintType() { t << ""; } void HtmlGenerator::startConstraintDocs() { t << "" << endl; } void HtmlGenerator::endConstraintList() { t << "
    "; } void HtmlGenerator::endConstraintParam() { t << " :"; } void HtmlGenerator::endConstraintType() { t << " "; } void HtmlGenerator::endConstraintDocs() { t << "
    " << endl; t << "
    " << endl; t << "
    " << endl; t << "
    " << endl; } void HtmlGenerator::startCodeFragment() { t << PREFRAG_START; } void HtmlGenerator::endCodeFragment() { //endCodeLine checks is there is still an open code line, if so closes it. endCodeLine(); t << PREFRAG_END; } void HtmlGenerator::lineBreak(const char *style) { if (style) { t << "
    " << endl; } else { t << "
    " << endl; } } void HtmlGenerator::startHeaderSection() { t << "
    " << endl; } void HtmlGenerator::startTitleHead(const char *) { t << "
    " << endl; startTitle(); } void HtmlGenerator::endTitleHead(const char *,const char *) { endTitle(); t << "
    " << endl; } void HtmlGenerator::endHeaderSection() { t << "
    " << endl; } void HtmlGenerator::startInlineHeader() { if (m_emptySection) { t << "" << endl; m_emptySection=FALSE; } t << "" << endl; } void HtmlGenerator::startMemberDocSimple(bool isEnum) { DBG_HTML(t << "" << endl;) t << "

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

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