Doxygen
Loading...
Searching...
No Matches
htmlgen.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2023 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include <stdlib.h>
17#include <assert.h>
18
19#include <mutex>
20
21#include "message.h"
22#include "htmlgen.h"
23#include "config.h"
24#include "util.h"
25#include "doxygen.h"
26#include "diagram.h"
27#include "version.h"
28#include "dot.h"
29#include "dotcallgraph.h"
30#include "dotclassgraph.h"
31#include "dotdirdeps.h"
34#include "dotincldepgraph.h"
35#include "language.h"
36#include "htmlhelp.h"
37#include "docparser.h"
38#include "docnode.h"
39#include "htmldocvisitor.h"
40#include "searchindex.h"
41#include "pagedef.h"
42#include "debug.h"
43#include "dirdef.h"
44#include "vhdldocgen.h"
45#include "layout.h"
46#include "image.h"
47#include "ftvhelp.h"
48#include "resourcemgr.h"
49#include "tooltip.h"
50#include "fileinfo.h"
51#include "dir.h"
52#include "utf8.h"
53#include "textstream.h"
54#include "indexlist.h"
55#include "datetime.h"
56#include "portable.h"
57#include "outputlist.h"
58#include "stringutil.h"
59
60//#define DBG_HTML(x) x;
61#define DBG_HTML(x)
62
69static bool g_build_date = false;
70static constexpr auto hex="0123456789ABCDEF";
71
72static const SelectionMarkerInfo htmlMarkerInfo = { '<', "<!--BEGIN ",10,"<!--END ",8,"-->",3 };
73
74// note: this is only active if DISABLE_INDEX=YES, if DISABLE_INDEX is disabled, this
75// part will be rendered inside menu.js
76static void writeClientSearchBox(TextStream &t,const QCString &relPath)
77{
78 t << " <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n";
79 t << " <span class=\"left\">\n";
80 t << " <span id=\"MSearchSelect\" class=\"search-icon\" ";
81 t << "onmouseover=\"return searchBox.OnSearchSelectShow()\" ";
82 t << "onmouseout=\"return searchBox.OnSearchSelectHide()\">";
83 t << "<span class=\"search-icon-dropdown\"></span></span>\n";
84 t << " <input type=\"text\" id=\"MSearchField\" value=\"\" placeholder=\""
85 << theTranslator->trSearch() << "\" accesskey=\"S\"\n";
86 t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
87 t << " onblur=\"searchBox.OnSearchFieldFocus(false)\" \n";
88 t << " onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n";
89 t << " </span><span class=\"right\">\n";
90 t << " <a id=\"MSearchClose\" href=\"javascript:searchBox.CloseResultsWindow()\">"
91 << "<div id=\"MSearchCloseImg\" class=\"close-icon\"></div></a>\n";
92 t << " </span>\n";
93 t << " </div>\n";
94}
95
96// note: this is only active if DISABLE_INDEX=YES. if DISABLE_INDEX is disabled, this
97// part will be rendered inside menu.js
98static void writeServerSearchBox(TextStream &t,const QCString &relPath,bool highlightSearch)
99{
100 bool externalSearch = Config_getBool(EXTERNAL_SEARCH);
101 t << " <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n";
102 t << " <div class=\"left\">\n";
103 t << " <form id=\"FSearchBox\" action=\"" << relPath;
104 if (externalSearch)
105 {
106 t << "search" << Doxygen::htmlFileExtension;
107 }
108 else
109 {
110 t << "search.php";
111 }
112 t << "\" method=\"get\">\n";
113 t << " <span id=\"MSearchSelectExt\" class=\"search-icon\"></span>\n";
114 if (!highlightSearch || !Config_getBool(HTML_DYNAMIC_MENUS))
115 {
116 t << " <input type=\"text\" id=\"MSearchField\" name=\"query\" value=\"\" placeholder=\""
117 << theTranslator->trSearch() << "\" size=\"20\" accesskey=\"S\" \n";
118 t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
119 t << " onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n";
120 t << " </form>\n";
121 t << " </div><div class=\"right\"></div>\n";
122 t << " </div>\n";
123 }
124}
125
126//------------------------------------------------------------------------
127/// Convert a set of LaTeX commands `\‍(re)newcommand` to a form readable by MathJax
128/// LaTeX syntax:
129/// ```
130/// \newcommand{\cmd}{replacement}
131/// or
132/// \renewcommand{\cmd}{replacement}
133/// ```
134/// MathJax syntax:
135/// ```
136/// cmd: "{replacement}"
137/// ```
138///
139/// LaTeX syntax:
140/// ```
141/// \newcommand{\cmd}[nr]{replacement}
142/// or
143/// \renewcommand{\cmd}[nr]{replacement}
144/// ```
145/// MathJax syntax:
146/// ```
147/// cmd: ["{replacement}",nr]
148/// ```
150{
151 QCString macrofile = Config_getString(FORMULA_MACROFILE);
152 if (macrofile.isEmpty()) return "";
153 QCString s = fileToString(macrofile);
154 macrofile = FileInfo(macrofile.str()).absFilePath();
155 size_t size = s.length();
156 QCString result;
157 result.reserve(size+8);
158 const char *data = s.data();
159 int line = 1;
160 int cnt = 0;
161 size_t i = 0;
162 QCString nr;
163 while (i < size)
164 {
165 nr = "";
166 // skip initial white space, but count lines
167 while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n'))
168 {
169 if (data[i] == '\n') line++;
170 i++;
171 }
172 if (i >= size) break;
173 // check for \newcommand or \renewcommand
174 if (data[i] != '\\')
175 {
176 warn(macrofile,line, "file contains non valid code, expected '\\' got '{:c}'",data[i]);
177 return "";
178 }
179 i++;
180 if (literal_at(data+i,"newcommand"))
181 {
182 i += strlen("newcommand");
183 }
184 else if (literal_at(data+i,"renewcommand"))
185 {
186 i += strlen("renewcommand");
187 }
188 else
189 {
190 warn(macrofile,line, "file contains non valid code, expected 'newcommand' or 'renewcommand'");
191 return "";
192 }
193 // handle {cmd}
194 if (data[i] != '{')
195 {
196 warn(macrofile,line, "file contains non valid code, expected '{{' got '{:c}'",data[i]);
197 return "";
198 }
199 i++;
200 if (data[i] != '\\')
201 {
202 warn(macrofile,line, "file contains non valid code, expected '\\' got '{:c}'",data[i]);
203 return "";
204 }
205 i++;
206 // run till }, i.e. cmd
207 result+=" ";
208 while (i < size && (data[i] != '}')) result+=data[i++];
209 if (i >= size)
210 {
211 warn(macrofile,line, "file contains non valid code, no closing '}}' for command");
212 return "";
213 }
214 result+=": ";
215 i++;
216
217 if (data[i] == '[')
218 {
219 // handle [nr]
220 // run till ]
221 result+='[';
222 i++;
223 while (i < size && (data[i] != ']')) nr += data[i++];
224 if (i >= size)
225 {
226 warn(macrofile,line, "file contains non valid code, no closing ']'");
227 return "";
228 }
229 i++;
230 }
231 else if (data[i] != '{')
232 {
233 warn(macrofile,line, "file contains non valid code, expected '[' or '{{' got '{:c}'",data[i]);
234 return "";
235 }
236 // handle {replacement}
237 // retest as the '[' part might have advanced so we can have a new '{'
238 if (data[i] != '{')
239 {
240 warn(macrofile,line, "file contains non valid code, expected '{{' got '{:c}'",data[i]);
241 return "";
242 }
243 result+="\"{";
244 i++;
245 // run till }
246 cnt = 1;
247 while (i < size && cnt)
248 {
249 switch(data[i])
250 {
251 case '\\':
252 result+="\\\\"; // need to escape it for MathJax js code
253 i++;
254 if (data[i] == '\\') // we have an escaped backslash
255 {
256 result+="\\\\";
257 i++;
258 }
259 else if (data[i] != '"') result+=data[i++]; // double quote handled separately
260 break;
261 case '{':
262 cnt++;
263 result+=data[i++];
264 break;
265 case '}':
266 cnt--;
267 if (cnt) result+=data[i];
268 i++;
269 break;
270 case '"':
271 result+='\\'; // need to escape it for MathJax js code
272 result+=data[i++];
273 break;
274 case '\n':
275 line++;
276 result+=data[i++];
277 break;
278 default:
279 result+=data[i++];
280 break;
281 }
282 }
283 if (i > size)
284 {
285 warn(macrofile,line, "file contains non valid code, no closing '}}' for replacement");
286 return "";
287 }
288 result+="}\"";
289 if (!nr.isEmpty())
290 {
291 result+=',';
292 result+=nr;
293 result+=']';
294 }
295 result+=",\n";
296 }
297 return result;
298}
299
300static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch)
301{
302 TextStream t;
303 if (serverSide)
304 {
305 writeServerSearchBox(t, relPath, highlightSearch);
306 }
307 else
308 {
309 writeClientSearchBox(t, relPath);
310 }
311 return t.str();
312}
313
315 const QCString &str,
316 const QCString &title,
317 const QCString &relPath,
318 const QCString &navPath=QCString(),
319 bool isSource = false)
320{
321 // Build CSS/JavaScript tags depending on treeview, search engine settings
322 QCString cssFile;
323 QCString generatedBy;
324 QCString treeViewCssJs;
325 QCString searchCssJs;
326 QCString searchBox;
327 QCString mathJaxJs;
328 QCString mermaidJs;
329 QCString extraCssText;
330
331 QCString projectName = Config_getString(PROJECT_NAME);
332 bool treeView = Config_getBool(GENERATE_TREEVIEW);
333 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
334 bool codeFolding = Config_getBool(HTML_CODE_FOLDING);
335 bool searchEngine = Config_getBool(SEARCHENGINE);
336 bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
337 bool mathJax = Config_getBool(USE_MATHJAX);
338 bool disableIndex = Config_getBool(DISABLE_INDEX);
339 bool hasProjectName = !projectName.isEmpty();
340 bool hasProjectNumber = !Config_getString(PROJECT_NUMBER).isEmpty();
341 bool hasProjectBrief = !Config_getString(PROJECT_BRIEF).isEmpty();
342 bool hasProjectLogo = !Config_getString(PROJECT_LOGO).isEmpty();
343 bool hasProjectIcon = !Config_getString(PROJECT_ICON).isEmpty();
344 bool hasFullSideBar = Config_getBool(FULL_SIDEBAR) && /*disableIndex &&*/ treeView;
345 bool hasCopyClipboard = Config_getBool(HTML_COPY_CLIPBOARD);
346 bool hasCookie = treeView || searchEngine || Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE;
347 static bool titleArea = (hasProjectName || hasProjectBrief || hasProjectLogo || (disableIndex && searchEngine));
348
349 cssFile = Config_getString(HTML_STYLESHEET);
350 if (cssFile.isEmpty())
351 {
352 cssFile = "doxygen.css";
353 }
354 else
355 {
356 if (!cssFile.startsWith("http:") && !cssFile.startsWith("https:"))
357 {
358 FileInfo cssfi(cssFile.str());
359 if (cssfi.exists())
360 {
361 cssFile = cssfi.fileName();
362 }
363 else
364 {
365 cssFile = "doxygen.css";
366 }
367 }
368 }
369
370 extraCssText = "";
371 const StringVector &extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET);
372 for (const auto &fileName : extraCssFile)
373 {
374 if (!fileName.empty())
375 {
376 QCString htmlStyleSheet = fileName;
377 if (htmlStyleSheet.startsWith("http:") || htmlStyleSheet.startsWith("https:"))
378 {
379 extraCssText += "<link href=\""+htmlStyleSheet+"\" rel=\"stylesheet\" type=\"text/css\"/>\n";
380 }
381 else
382 {
383 FileInfo fi(fileName);
384 if (fi.exists())
385 {
386 extraCssText += "<link href=\"$relpath^"+stripPath(fileName)+"\" rel=\"stylesheet\" type=\"text/css\"/>\n";
387 }
388 }
389 }
390 }
391
392 switch (Config_getEnum(TIMESTAMP))
393 {
394 case TIMESTAMP_t::NO:
395 generatedBy = theTranslator->trGeneratedBy();
396 break;
397 default:
398 generatedBy = theTranslator->trGeneratedAt("<span class=\"timestamp\"></span>",
399 convertToHtml(Config_getString(PROJECT_NAME)));
400 break;
401 }
402 if (treeView)
403 {
404 treeViewCssJs = "<link href=\"$relpath^navtree.css\" rel=\"stylesheet\" type=\"text/css\"/>\n"
405 "<script type=\"text/javascript\" src=\"$relpath^navtreedata.js\"></script>\n"
406 "<script type=\"text/javascript\" src=\"$relpath^navtree.js\"></script>\n";
407 }
408
409 if (searchEngine)
410 {
411 searchCssJs = "<link href=\"$relpath^search/search.css\" rel=\"stylesheet\" type=\"text/css\"/>\n";
412 if (!serverBasedSearch)
413 {
414 searchCssJs += "<script type=\"text/javascript\" src=\"$relpath^search/searchdata.js\"></script>\n";
415 }
416 searchCssJs += "<script type=\"text/javascript\" src=\"$relpath^search/search.js\"></script>\n";
417
418 if (!serverBasedSearch)
419 {
420 if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS) || Config_getBool(FULL_SIDEBAR))
421 {
422 searchCssJs += "<script type=\"text/javascript\">\n"
423 "document.addEventListener('DOMContentLoaded', init_search);\n"
424 "</script>";
425 }
426 }
427 else
428 {
429 if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS))
430 {
431 searchCssJs += "<script type=\"text/javascript\">\n"
432 "document.addEventListener('DOMContentLoaded', () => {\n"
433 " if (document.querySelector('.searchresults')) { searchBox.DOMSearchField().focus(); }\n"
434 "});\n"
435 "</script>\n";
436 }
437
438 // OPENSEARCH_PROVIDER {
439 searchCssJs += "<link rel=\"search\" href=\"" + relPath +
440 "search_opensearch.php?v=opensearch.xml\" "
441 "type=\"application/opensearchdescription+xml\" title=\"" +
442 (hasProjectName ? projectName : QCString("Doxygen")) +
443 "\"/>";
444 // OPENSEARCH_PROVIDER }
445 }
446 searchBox = getSearchBox(serverBasedSearch, relPath, FALSE);
447 }
448
449 if (mathJax && !isSource)
450 {
451 auto mathJaxVersion = Config_getEnum(MATHJAX_VERSION);
452 QCString path = Config_getString(MATHJAX_RELPATH);
453 if (path.isEmpty() || path.startsWith("..")) // relative path
454 {
455 path.prepend(relPath);
456 }
457
458 auto writeMathJax3Packages = [&mathJaxJs](const StringVector &mathJaxExtensions)
459 {
460 mathJaxJs += " packages: ['base','configmacros'";
461 if (!g_latex_macro.isEmpty())
462 {
463 mathJaxJs+= ",'newcommand'";
464 }
465 for (const auto &s : mathJaxExtensions)
466 {
467 mathJaxJs+= ",'"+s+"'";
468 }
469 mathJaxJs += "]\n";
470 };
471
472 auto writeMathJax4Packages = [&mathJaxJs](const StringVector &mathJaxExtensions)
473 {
474 mathJaxJs += " packages: {\n";
475 bool first = true;
476 for (const auto &s : mathJaxExtensions)
477 {
478 if (!first) mathJaxJs+= ",";
479 if (s.at(0) =='-')
480 {
481 mathJaxJs+= "\n '[-]': ['";
482 mathJaxJs+=s.data()+1;
483 mathJaxJs+="']";
484 }
485 else
486 {
487 mathJaxJs+= "\n '[+]': ['"+s+"']";
488 }
489 first = false;
490 }
491 mathJaxJs += "\n }\n";
492 };
493
494 auto writeMathJaxScript = [&path,&mathJaxJs](const QCString &pathPostfix,
495 std::function<void(const StringVector&)> writePackages)
496 {
497 QCString mathJaxFormat = Config_getEnumAsString(MATHJAX_FORMAT);
498 mathJaxJs += "<script type=\"text/javascript\">\n"
499 "window.MathJax = {\n"
500 " options: {\n"
501 " ignoreHtmlClass: 'tex2jax_ignore',\n"
502 " processHtmlClass: 'tex2jax_process'\n"
503 " }";
504 // MACRO / EXT
505 const StringVector &mathJaxExtensions = Config_getList(MATHJAX_EXTENSIONS);
506 if (!mathJaxExtensions.empty() || !g_latex_macro.isEmpty())
507 {
508 mathJaxJs+= ",\n";
509 if (!mathJaxExtensions.empty())
510 {
511 bool first = true;
512 mathJaxJs+= " loader: {\n"
513 " load: [";
514 for (const auto &s : mathJaxExtensions)
515 {
516 if (s.at(0) !='-')
517 {
518 if (!first) mathJaxJs+= ",";
519 mathJaxJs+= "'[tex]/"+s+"'"; // packages preceded by a minus sign should not be loaded
520 first = false;
521 }
522 }
523 mathJaxJs+= "]\n"
524 " },\n";
525 }
526 mathJaxJs+= " tex: {\n"
527 " macros: {";
528 if (!g_latex_macro.isEmpty())
529 {
530 mathJaxJs += g_latex_macro+" ";
531 }
532 mathJaxJs+="},\n";
533 writePackages(mathJaxExtensions);
534 mathJaxJs += " }\n";
535 }
536 else
537 {
538 mathJaxJs += "\n";
539 }
540 mathJaxJs += "};\n";
541 // MATHJAX_CODEFILE
542 if (!g_mathjax_code.isEmpty())
543 {
544 mathJaxJs += g_mathjax_code;
545 mathJaxJs += "\n";
546 }
547 mathJaxJs+="</script>\n";
548 mathJaxJs += "<script type=\"text/javascript\" id=\"MathJax-script\" async=\"async\" src=\"" +
549 path + pathPostfix + "tex-" + mathJaxFormat.lower() + ".js\">";
550 mathJaxJs+="</script>\n";
551 };
552
553 switch (mathJaxVersion)
554 {
555 case MATHJAX_VERSION_t::MathJax_4:
556 writeMathJaxScript("",writeMathJax4Packages);
557 break;
558 case MATHJAX_VERSION_t::MathJax_3:
559 writeMathJaxScript("es5/",writeMathJax3Packages);
560 break;
561 case MATHJAX_VERSION_t::MathJax_2:
562 {
563 QCString mathJaxFormat = Config_getEnumAsString(MATHJAX_FORMAT);
564 mathJaxJs = "<script type=\"text/x-mathjax-config\">\n"
565 "MathJax.Hub.Config({\n"
566 " extensions: [\"tex2jax.js\"";
567 const StringVector &mathJaxExtensions = Config_getList(MATHJAX_EXTENSIONS);
568 for (const auto &s : mathJaxExtensions)
569 {
570 mathJaxJs+= ", \""+QCString(s)+".js\"";
571 }
572 if (mathJaxFormat.isEmpty())
573 {
574 mathJaxFormat = "HTML-CSS";
575 }
576 mathJaxJs += "],\n"
577 " jax: [\"input/TeX\",\"output/"+mathJaxFormat+"\"],\n";
578 if (!g_latex_macro.isEmpty())
579 {
580 mathJaxJs += " TeX: { Macros: {\n";
581 mathJaxJs += g_latex_macro;
582 mathJaxJs += "\n"
583 " } }\n";
584 }
585 mathJaxJs += "});\n";
586 if (!g_mathjax_code.isEmpty())
587 {
588 mathJaxJs += g_mathjax_code;
589 mathJaxJs += "\n";
590 }
591 mathJaxJs += "</script>\n";
592 mathJaxJs += "<script type=\"text/javascript\" async=\"async\" src=\"" + path + "MathJax.js\"></script>\n";
593 }
594 break;
595 }
596 }
597
598 QCString darkModeJs;
599 if (Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE)
600 {
601 darkModeJs="<script type=\"text/javascript\" src=\"$relpath^darkmode_toggle.js\"></script>\n";
602 }
603
604 QCString mermaidRenderMode = Config_getEnumAsString(MERMAID_RENDER_MODE);
605 if (mermaidRenderMode=="CLIENT_SIDE" || mermaidRenderMode=="AUTO")
606 {
607 QCString mermaidJsUrl = Config_getString(MERMAID_JS_URL);
608 mermaidJs = "<script type=\"module\">\n"
609 "import mermaid from '" + mermaidJsUrl + "';\n"
610 "const theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'default';\n"
611 "mermaid.initialize({ startOnLoad: true, theme: theme });\n"
612 "</script>\n";
613 }
614
615 if (hasCookie) // extend the $treeview tag to avoid breaking old files used with HTML_HEADER
616 {
617 treeViewCssJs+="<script type=\"text/javascript\" src=\"$relpath^cookie.js\"></script>\n";
618 }
619
620 // first substitute generic keywords
621 QCString result = substituteKeywords(file,str,title,
622 convertToHtml(Config_getString(PROJECT_NAME)),
623 convertToHtml(Config_getString(PROJECT_NUMBER)),
624 convertToHtml(Config_getString(PROJECT_BRIEF)));
625
626 // then do the HTML specific keywords
627 result = substituteKeywords(file,result,
628 {
629 // keyword value getter
630 { "$datetime", [&]() -> QCString { return "<span class=\"datetime\"></span>"; } },
631 { "$date", [&]() -> QCString { return "<span class=\"date\"></span>"; } },
632 { "$time", [&]() -> QCString { return "<span class=\"time\"></span>"; } },
633 { "$year", [&]() -> QCString { return "<span class=\"year\"></span>"; } },
634 { "$navpath", [&]() -> QCString { return navPath; } },
635 { "$stylesheet", [&]() -> QCString { return cssFile; } },
636 { "$treeview", [&]() -> QCString { return treeViewCssJs; } },
637 { "$searchbox", [&]() -> QCString { return searchBox; } },
638 { "$search", [&]() -> QCString { return searchCssJs; } },
639 { "$mathjax", [&]() -> QCString { return mathJaxJs; } },
640 { "$mermaidjs", [&]() -> QCString { return mermaidJs; } },
641 { "$darkmode", [&]() -> QCString { return darkModeJs; } },
642 { "$generatedby", [&]() -> QCString { return generatedBy; } },
643 { "$extrastylesheet",[&]() -> QCString { return extraCssText; } },
644 { "$relpath$", [&]() -> QCString { return relPath; } } //<-- obsolete: for backwards compatibility only
645 });
646
647 result = substitute(result,"$relpath^",relPath); //<-- must be done after the previous substitutions
648
649 // remove conditional blocks
650 result = selectBlocks(result,
651 {
652 // keyword, is enabled
653 { "FULL_SIDEBAR", hasFullSideBar },
654 { "DISABLE_INDEX", disableIndex },
655 { "GENERATE_TREEVIEW", treeView },
656 { "SEARCHENGINE", searchEngine },
657 { "TITLEAREA", titleArea },
658 { "PROJECT_NAME", hasProjectName },
659 { "PROJECT_NUMBER", hasProjectNumber },
660 { "PROJECT_BRIEF", hasProjectBrief },
661 { "PROJECT_LOGO", hasProjectLogo },
662 { "PROJECT_ICON", hasProjectIcon },
663 { "COPY_CLIPBOARD", hasCopyClipboard },
664 { "HTML_CODE_FOLDING", codeFolding },
665 { "HTML_DYNAMIC_SECTIONS", dynamicSections},
667
668 result = removeEmptyLines(result);
669
670 return result;
671}
672
673//---------------------------------------------------------------------------------------------
674
677
678static void fillColorStyleMap(const QCString &definitions,StringUnorderedMap &map)
679{
680 int p=0,i=0;
681 while ((i=definitions.find('\n',p))!=-1)
682 {
683 QCString line = definitions.mid(p,i-p);
684 if (line.startsWith("--"))
685 {
686 int separator = line.find(':');
687 assert(separator!=-1);
688 std::string key = line.left(separator).str();
689 int semi = line.findRev(';');
690 assert(semi!=-1);
691 std::string value = line.mid(separator+1,semi-separator-1).stripWhiteSpace().str();
692 map.emplace(key,value);
693 //printf("var(%s)=%s\n",qPrint(key),qPrint(value));
694 }
695 p=i+1;
696 }
697}
698
700{
702 auto colorStyle = Config_getEnum(HTML_COLORSTYLE);
703 if (colorStyle==HTML_COLORSTYLE_t::LIGHT)
704 {
705 fillColorStyleMap(replaceColorMarkers(mgr.getAsString("lightmode_settings.css")),g_lightMap);
706 }
707 else if (colorStyle==HTML_COLORSTYLE_t::DARK)
708 {
709 fillColorStyleMap(replaceColorMarkers(mgr.getAsString("darkmode_settings.css")),g_darkMap);
710 }
711}
712
714{
715 auto doReplacements = [&input](const StringUnorderedMap &mapping) -> QCString
716 {
717 QCString result;
718 result.reserve(input.length());
719 int p=0,i=0;
720 while ((i=input.find("var(",p))!=-1)
721 {
722 result+=input.mid(p,i-p);
723 int j=input.find(")",i+4);
724 assert(j!=-1);
725 auto it = mapping.find(input.mid(i+4,j-i-4).str()); // find variable
726 if (it==mapping.end())
727 { // should be found
728 err("failed to find value variable {}. It is not longer defined in doxygen.css\n",input.mid(i+4,j-i-4));
729 }
730 else
731 {
732 //printf("replace '%s' by '%s'\n",qPrint(input.mid(i+4,j-i-4)),qPrint(it->second));
733 result+=it->second; // add it value
734 }
735 p=j+1;
736 }
737 result+=input.mid(p,input.length()-p);
738 return result;
739 };
740
741 auto colorStyle = Config_getEnum(HTML_COLORSTYLE);
742 if (colorStyle==HTML_COLORSTYLE_t::LIGHT)
743 {
744 return doReplacements(g_lightMap);
745 }
746 else if (colorStyle==HTML_COLORSTYLE_t::DARK)
747 {
748 return doReplacements(g_darkMap);
749 }
750 else
751 {
752 return input;
753 }
754}
755
756//----------------------------------------------------------------------------------------------
757
758
759//--------------------------------------------------------------------------
760
762{
763 //printf("%p:HtmlCodeGenerator()\n",(void*)this);
764}
765
767 : m_t(t), m_relPath(relPath)
768{
769 //printf("%p:HtmlCodeGenerator()\n",(void*)this);
770}
771
773{
774 m_relPath = path;
775}
776
778{
779 if (!str.isEmpty())
780 {
781 int tabSize = Config_getInt(TAB_SIZE);
782 const char *p=str.data();
783 if (m_hide) // only update column count
784 {
786 }
787 else // actually output content and keep track of m_col
788 {
789 while (*p)
790 {
791 char c=*p++;
792 switch(c)
793 {
794 case '\t': {
795 int spacesToNextTabStop = tabSize - (m_col%tabSize);
796 while (spacesToNextTabStop--)
797 {
798 if (m_col>=m_stripIndentAmount) *m_t << " ";
799 m_col++;
800 }
801 }
802 break;
803 case ' ': if (m_col>=m_stripIndentAmount) *m_t << " ";
804 m_col++;
805 break;
806 case '\n': *m_t << "\n"; m_col=0;
807 break;
808 case '\r': break;
809 case '<': *m_t << "&lt;"; m_col++;
810 break;
811 case '>': *m_t << "&gt;"; m_col++;
812 break;
813 case '&': *m_t << "&amp;"; m_col++;
814 break;
815 case '\'': *m_t << "&#39;"; m_col++; // &apos; is not valid XHTML
816 break;
817 case '"': *m_t << "&quot;"; m_col++;
818 break;
819 case '\\':
820 if (*p=='<')
821 { *m_t << "&lt;"; p++; }
822 else if (*p=='>')
823 { *m_t << "&gt;"; p++; }
824 else if (*p=='[')
825 { *m_t << "\\&zwj;["; m_col++;p++; }
826 else if (*p==']')
827 { *m_t << "\\&zwj;]"; m_col++;p++; }
828 else if (*p=='(')
829 { *m_t << "\\&zwj;("; m_col++;p++; }
830 else if (*p==')')
831 { *m_t << "\\&zwj;)"; m_col++;p++; }
832 else
833 *m_t << "\\";
834 m_col++;
835 break;
836 default:
837 {
838 uint8_t uc = static_cast<uint8_t>(c);
839 if (uc<32)
840 {
841 *m_t << "&#x24" << hex[uc>>4] << hex[uc&0xF] << ";";
842 m_col++;
843 }
844 else if (uc<0x80) // printable ASCII char
845 {
846 *m_t << c;
847 m_col++;
848 }
849 else // multibyte UTF-8 char
850 {
851 p=writeUTF8Char(*m_t,p-1);
852 m_col++;
853 }
854 }
855 break;
856 }
857 }
858 }
859 }
860}
861
866
868{
870 //*m_t << "[START]";
871}
872
874{
875 //*m_t << "[END]";
876 m_hide = false;
877}
878
880{
881 m_stripIndentAmount = amount;
882}
883
885 const QCString &anchor,int l,bool writeLineAnchor)
886{
887 m_lastLineInfo = LineInfo(ref,filename,anchor,l,writeLineAnchor);
888 if (m_hide) return;
889 const int maxLineNrStr = 10;
890 char lineNumber[maxLineNrStr];
891 char lineAnchor[maxLineNrStr];
892 qsnprintf(lineNumber,maxLineNrStr,"%5d",l);
893 qsnprintf(lineAnchor,maxLineNrStr,"l%05d",l);
894
895 //printf("writeLineNumber open=%d\n",m_lineOpen);
896 if (!m_lineOpen)
897 {
898 *m_t << "<div class=\"line\">";
900 }
901
902 if (writeLineAnchor) *m_t << "<a id=\"" << lineAnchor << "\" name=\"" << lineAnchor << "\"></a>";
903 *m_t << "<span class=\"lineno\">";
904 if (!filename.isEmpty())
905 {
906 _writeCodeLink("line",ref,filename,anchor,lineNumber,QCString());
907 }
908 else
909 {
910 codify(lineNumber);
911 }
912 *m_t << "</span>";
913 m_col=0;
914}
915
917 const QCString &ref,const QCString &f,
918 const QCString &anchor, const QCString &name,
919 const QCString &tooltip)
920{
921 if (m_hide) return;
922 const char *hl = codeSymbolType2Str(type);
923 QCString hlClass = "code";
924 if (hl)
925 {
926 hlClass+=" hl_";
927 hlClass+=hl;
928 }
929 _writeCodeLink(hlClass,ref,f,anchor,name,tooltip);
930}
931
933 const QCString &ref,const QCString &f,
934 const QCString &anchor, const QCString &name,
935 const QCString &tooltip)
936{
937 m_col+=name.length();
938 if (m_hide) return;
939 if (!ref.isEmpty())
940 {
941 *m_t << "<a class=\"" << className << "Ref\" ";
943 }
944 else
945 {
946 *m_t << "<a class=\"" << className << "\" ";
947 }
948 *m_t << "href=\"";
949 QCString fn = f;
951 *m_t << createHtmlUrl(m_relPath,ref,true,
952 fileName()==fn,fn,anchor);
953 *m_t << "\"";
954 if (!tooltip.isEmpty()) *m_t << " title=\"" << convertToHtml(tooltip) << "\"";
955 *m_t << ">";
956 codify(name);
957 *m_t << "</a>";
958}
959
961 const QCString &decl, const QCString &desc,
962 const SourceLinkInfo &defInfo,
963 const SourceLinkInfo &declInfo)
964{
965 if (m_hide) return;
966 *m_t << "<div class=\"ttc\" id=\"" << id << "\">";
967 *m_t << "<div class=\"ttname\">";
968 if (!docInfo.url.isEmpty())
969 {
970 *m_t << "<a href=\"";
971 QCString fn = docInfo.url;
973 *m_t << createHtmlUrl(m_relPath,docInfo.ref,true,
974 fileName()==fn,fn,docInfo.anchor);
975 *m_t << "\">";
976 }
977 codify(docInfo.name);
978 if (!docInfo.url.isEmpty())
979 {
980 *m_t << "</a>";
981 }
982 *m_t << "</div>";
983
984 if (!decl.isEmpty())
985 {
986 *m_t << "<div class=\"ttdeci\">";
987 codify(decl);
988 *m_t << "</div>";
989 }
990
991 if (!desc.isEmpty())
992 {
993 *m_t << "<div class=\"ttdoc\">";
994 codify(desc);
995 *m_t << "</div>";
996 }
997
998 if (!defInfo.file.isEmpty())
999 {
1000 *m_t << "<div class=\"ttdef\"><b>" << theTranslator->trDefinition() << "</b> ";
1001 if (!defInfo.url.isEmpty())
1002 {
1003 *m_t << "<a href=\"";
1004 QCString fn = defInfo.url;
1006 *m_t << createHtmlUrl(m_relPath,defInfo.ref,true,
1007 fileName()==fn,fn,defInfo.anchor);
1008 *m_t << "\">";
1009 }
1010 *m_t << defInfo.file << ":" << defInfo.line;
1011 if (!defInfo.url.isEmpty())
1012 {
1013 *m_t << "</a>";
1014 }
1015 *m_t << "</div>";
1016 }
1017 if (!declInfo.file.isEmpty())
1018 {
1019 *m_t << "<div class=\"ttdecl\"><b>" << theTranslator->trDeclaration() << "</b> ";
1020 if (!declInfo.url.isEmpty())
1021 {
1022 *m_t << "<a href=\"";
1023 QCString fn = declInfo.url;
1025 *m_t << createHtmlUrl(m_relPath,declInfo.ref,true,
1026 fileName()==fn,fn,declInfo.anchor);
1027 *m_t << "\">";
1028 }
1029 *m_t << declInfo.file << ":" << declInfo.line;
1030 if (!declInfo.url.isEmpty())
1031 {
1032 *m_t << "</a>";
1033 }
1034 *m_t << "</div>";
1035 }
1036 *m_t << "</div>\n";
1037}
1038
1039
1041{
1042 //printf("startCodeLine open=%d\n",m_lineOpen);
1043 m_col=0;
1044 if (m_hide) return;
1045 if (!m_lineOpen)
1046 {
1047 *m_t << "<div class=\"line\">";
1048 m_lineOpen = TRUE;
1049 }
1050}
1051
1053{
1054 //printf("endCodeLine hide=%d open=%d\n",m_hide,m_lineOpen);
1055 if (m_hide) return;
1056 if (m_col == 0)
1057 {
1058 *m_t << " ";
1059 m_col++;
1060 }
1061 if (m_lineOpen)
1062 {
1063 *m_t << "</div>\n";
1064 m_lineOpen = FALSE;
1065 }
1066}
1067
1069{
1070 if (m_hide) return;
1071 *m_t << "<span class=\"" << s << "\">";
1072}
1073
1075{
1076 if (m_hide) return;
1077 *m_t << "</span>";
1078}
1079
1081{
1082 if (m_hide) return;
1083 *m_t << "<a id=\"" << anchor << "\" name=\"" << anchor << "\"></a>";
1084}
1085
1087{
1088 *m_t << "<div class=\"fragment\">";
1089}
1090
1092{
1093 //printf("endCodeFragment hide=%d open=%d\n",m_hide,m_lineOpen);
1094 bool wasHidden = m_hide;
1095 m_hide = false;
1096 //endCodeLine checks is there is still an open code line, if so closes it.
1097 endCodeLine();
1098 m_hide = wasHidden;
1099
1100 *m_t << "</div><!-- fragment -->";
1101}
1102
1103void HtmlCodeGenerator::startFold(int lineNr,const QCString &startMarker,const QCString &endMarker)
1104{
1105 //printf("startFold open=%d\n",m_lineOpen);
1106 if (m_lineOpen) // if we have a hidden comment in a code fold, we need to end the line
1107 {
1108 *m_t << "</div>\n";
1109 }
1110 const int maxLineNrStr = 10;
1111 char lineNumber[maxLineNrStr];
1112 qsnprintf(lineNumber,maxLineNrStr,"%05d",lineNr);
1113 *m_t << "<div class=\"foldopen\" id=\"foldopen" << lineNumber <<
1114 "\" data-start=\"" << startMarker <<
1115 "\" data-end=\"" << endMarker <<
1116 "\">\n";
1117 if (m_lineOpen) // if we have a hidden comment in a code fold, we need to restart the line
1118 {
1119 *m_t << "<div class=\"line\">";
1120 }
1121 m_hide=false;
1122}
1123
1125{
1126 //printf("_startOpenLine open=%d\n",m_lineOpen);
1127 *m_t << "<div class=\"line\">";
1128 bool wasHidden=m_hide;
1129 m_hide = false;
1130 m_lineOpen = true;
1132 m_lastLineInfo.fileName,
1133 m_lastLineInfo.anchor,
1134 m_lastLineInfo.line+1,
1135 m_lastLineInfo.writeAnchor);
1136 m_hide = wasHidden;
1137}
1138
1140{
1141 //printf("endFold open=%d\n",m_lineOpen);
1142 if (m_lineOpen) // if we have a hidden comment in a code fold, we need to end the line
1143 {
1144 *m_t << "</div>\n";
1145 }
1146 *m_t << "</div>\n";
1147 if (m_lineOpen)
1148 {
1150 }
1151}
1152
1153//--------------------------------------------------------------------------
1154
1156 : OutputGenerator(Config_getString(HTML_OUTPUT))
1157 , m_codeList(std::make_unique<OutputCodeList>())
1158{
1159 //printf("%p:HtmlGenerator()\n",(void*)this);
1161}
1162
1164{
1165 //printf("%p:HtmlGenerator(copy %p)\n",(void*)this,(void*)&og);
1166 m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList);
1168 m_codeGen->setTextStream(&m_t);
1171 m_relPath = og.m_relPath;
1174}
1175
1177{
1178 //printf("%p:HtmlGenerator(copy assign %p)\n",(void*)this,(void*)&og);
1179 if (this!=&og)
1180 {
1181 m_dir = og.m_dir;
1182 m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList);
1184 m_codeGen->setTextStream(&m_t);
1187 m_relPath = og.m_relPath;
1190 }
1191 return *this;
1192}
1193
1195
1200
1201static bool hasDateReplacement(const QCString &str)
1202{
1203 return (str.contains("$datetime",false) ||
1204 str.contains("$date",false) ||
1205 str.contains("$time",false) ||
1206 str.contains("$year",false)
1207 );
1208}
1209
1211{
1212 QCString dname = Config_getString(HTML_OUTPUT);
1213 Dir d(dname.str());
1214 if (!d.exists() && !d.mkdir(dname.str()))
1215 {
1216 term("Could not create output directory {}\n",dname);
1217 }
1218 //writeLogo(dname);
1219 if (!Config_getString(HTML_HEADER).isEmpty())
1220 {
1221 g_header_file=Config_getString(HTML_HEADER);
1224 //printf("g_header='%s'\n",qPrint(g_header));
1226 checkBlocks(result,Config_getString(HTML_HEADER),htmlMarkerInfo);
1227 }
1228 else
1229 {
1230 g_header_file="header.html";
1234 checkBlocks(result,"<default header.html>",htmlMarkerInfo);
1235 }
1236
1237 if (!Config_getString(HTML_FOOTER).isEmpty())
1238 {
1239 g_footer_file=Config_getString(HTML_FOOTER);
1242 //printf("g_footer='%s'\n",qPrint(g_footer));
1244 checkBlocks(result,Config_getString(HTML_FOOTER),htmlMarkerInfo);
1245 }
1246 else
1247 {
1248 g_footer_file = "footer.html";
1252 checkBlocks(result,"<default footer.html>",htmlMarkerInfo);
1253 }
1254
1255 if (Config_getBool(USE_MATHJAX))
1256 {
1257 if (!Config_getString(MATHJAX_CODEFILE).isEmpty())
1258 {
1259 g_mathjax_code=fileToString(Config_getString(MATHJAX_CODEFILE));
1260 //printf("g_mathjax_code='%s'\n",qPrint(g_mathjax_code));
1261 }
1263 //printf("converted g_latex_macro='%s'\n",qPrint(g_latex_macro));
1264 }
1265 createSubDirs(d);
1266
1268
1270
1271 {
1272 QCString tabsCss;
1273 if (Config_getBool(HTML_DYNAMIC_MENUS))
1274 {
1275 tabsCss = mgr.getAsString("tabs.css");
1276 }
1277 else // stylesheet for the 'old' static tabs
1278 {
1279 tabsCss = mgr.getAsString("fixed_tabs.css");
1280 }
1281
1282 std::ofstream f = Portable::openOutputStream(dname+"/tabs.css");
1283 if (f.is_open())
1284 {
1285 TextStream t(&f);
1286 t << replaceVariables(tabsCss);
1287 }
1288 }
1289
1290
1291 if (Config_getBool(INTERACTIVE_SVG))
1292 {
1293 mgr.copyResource("svg.min.js",dname);
1294 }
1295
1296 if (!Config_getBool(DISABLE_INDEX) && Config_getBool(HTML_DYNAMIC_MENUS))
1297 {
1298 mgr.copyResource("menu.js",dname);
1299 }
1300
1301 // copy navtree.css
1302 {
1303 std::ofstream f = Portable::openOutputStream(dname+"/navtree.css");
1304 if (f.is_open())
1305 {
1306 TextStream t(&f);
1307 t << getNavTreeCss();
1308 }
1309 }
1310
1311 if (Config_getBool(HTML_COPY_CLIPBOARD))
1312 {
1313 std::ofstream f = Portable::openOutputStream(dname+"/clipboard.js");
1314 if (f.is_open())
1315 {
1316 TextStream t(&f);
1317 t << substitute(mgr.getAsString("clipboard.js"),"$copy_to_clipboard_text",theTranslator->trCopyToClipboard());
1318 }
1319 }
1320
1321 bool hasCookie = Config_getBool(GENERATE_TREEVIEW) || Config_getBool(SEARCHENGINE) || Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE;
1322 if (hasCookie)
1323 {
1324 mgr.copyResource("cookie.js",dname);
1325 }
1326
1327 if (Config_getBool(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE)
1328 {
1329 std::ofstream f = Portable::openOutputStream(dname+"/darkmode_toggle.js");
1330 if (f.is_open())
1331 {
1332 TextStream t(&f);
1333 t << substitute(replaceColorMarkers(mgr.getAsString("darkmode_toggle.js")),
1334 "$PROJECTID",getProjectId());
1335 }
1336 }
1337
1338 if (Config_getBool(HTML_DYNAMIC_SECTIONS))
1339 {
1340 std::ofstream f = Portable::openOutputStream(dname+"/dynsections.js");
1341 if (f.is_open())
1342 {
1343 TextStream t(&f);
1344 t << replaceVariables(mgr.getAsString("dynsections.js"));
1345 if (Config_getBool(SOURCE_BROWSER) && Config_getBool(SOURCE_TOOLTIPS))
1346 {
1347 t << replaceVariables(mgr.getAsString("dynsections_tooltips.js"));
1348 }
1349 }
1350 }
1351 if (Config_getBool(HTML_CODE_FOLDING))
1352 {
1353 std::ofstream f = Portable::openOutputStream(dname+"/codefolding.js");
1354 if (f.is_open())
1355 {
1356 TextStream t(&f);
1357 t << replaceVariables(mgr.getAsString("codefolding.js"));
1358 }
1359 }
1360}
1361
1363{
1364 QCString dname = Config_getString(HTML_OUTPUT);
1365 Dir d(dname.str());
1366 clearSubDirs(d);
1367}
1368
1369/// Additional initialization after indices have been created
1371{
1372 Doxygen::indexList->addStyleSheetFile("tabs.css");
1373 QCString dname=Config_getString(HTML_OUTPUT);
1375 mgr.copyResource("doxygen.svg",dname);
1376 Doxygen::indexList->addImageFile("doxygen.svg");
1377}
1378
1380{
1381 //bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
1382 //writeImgData(dname,serverBasedSearch ? search_server_data : search_client_data);
1384
1385 QCString searchDirName = dname;
1386 std::ofstream f = Portable::openOutputStream(searchDirName+"/search.css");
1387 if (f.is_open())
1388 {
1389 TextStream t(&f);
1390 QCString searchCss;
1391 // the position of the search box depends on a number of settings.
1392 // Insert the right piece of CSS code depending on which options are selected
1393 if (Config_getBool(GENERATE_TREEVIEW) && Config_getBool(FULL_SIDEBAR))
1394 {
1395 searchCss = mgr.getAsString("search_sidebar.css"); // we have a full height side bar
1396 }
1397 else if (Config_getBool(DISABLE_INDEX))
1398 {
1399 if (Config_getBool(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE)
1400 {
1401 searchCss = mgr.getAsString("search_nomenu_toggle.css"); // we have no tabs but do have a darkmode button
1402 }
1403 else
1404 {
1405 searchCss = mgr.getAsString("search_nomenu.css"); // we have no tabs and no darkmode button
1406 }
1407 }
1408 else if (!Config_getBool(HTML_DYNAMIC_MENUS))
1409 {
1410 searchCss = mgr.getAsString("search_fixedtabs.css"); // we have tabs, but they are static
1411 }
1412 else
1413 {
1414 searchCss = mgr.getAsString("search.css"); // default case with a dynamic menu bar
1415 }
1416 // and then add the option independent part of the styling
1417 searchCss += mgr.getAsString("search_common.css");
1418 searchCss = substitute(searchCss,"$doxygenversion",getDoxygenVersion());
1419 t << replaceVariables(searchCss);
1420 Doxygen::indexList->addStyleSheetFile("search/search.css");
1421 }
1422}
1423
1425{
1426 t << "/* The standard CSS for doxygen " << getDoxygenVersion() << "*/\n\n";
1427 switch (Config_getEnum(HTML_COLORSTYLE))
1428 {
1429 case HTML_COLORSTYLE_t::LIGHT:
1430 case HTML_COLORSTYLE_t::DARK:
1431 /* variables will be resolved while writing to the CSS file */
1432 break;
1433 case HTML_COLORSTYLE_t::AUTO_LIGHT:
1434 case HTML_COLORSTYLE_t::TOGGLE:
1435 t << "html {\n";
1436 t << replaceColorMarkers(ResourceMgr::instance().getAsString("lightmode_settings.css"));
1437 t << "}\n\n";
1438 break;
1439 case HTML_COLORSTYLE_t::AUTO_DARK:
1440 t << "html {\n";
1441 t << replaceColorMarkers(ResourceMgr::instance().getAsString("darkmode_settings.css"));
1442 t << "}\n\n";
1443 break;
1444 }
1445 if (Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::AUTO_LIGHT)
1446 {
1447 t << "@media (prefers-color-scheme: dark) {\n";
1448 t << " html:not(.dark-mode) {\n";
1449 t << " color-scheme: dark;\n\n";
1450 t << replaceColorMarkers(ResourceMgr::instance().getAsString("darkmode_settings.css"));
1451 t << "}}\n";
1452 }
1453 else if (Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::AUTO_DARK)
1454 {
1455 t << "@media (prefers-color-scheme: light) {\n";
1456 t << " html:not(.light-mode) {\n";
1457 t << " color-scheme: light;\n\n";
1458 t << replaceColorMarkers(ResourceMgr::instance().getAsString("lightmode_settings.css"));
1459 t << "}}\n";
1460 }
1461 else if (Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE)
1462 {
1463 t << "html.dark-mode {\n";
1464 t << replaceColorMarkers(ResourceMgr::instance().getAsString("darkmode_settings.css"));
1465 t << "}\n\n";
1466 }
1467
1468 QCString cssStr = ResourceMgr::instance().getAsString("doxygen.css");
1469 bool hasFullSidebar = Config_getBool(FULL_SIDEBAR) && Config_getBool(GENERATE_TREEVIEW);
1470 if (hasFullSidebar)
1471 {
1472 cssStr+="\n"
1473 "#titlearea {\n"
1474 " border-bottom: none;\n"
1475 " background-color: var(--nav-background-color);\n"
1476 " border-right: 1px solid var(--nav-border-color);\n"
1477 "}\n";
1478 }
1479 t << replaceVariables(cssStr);
1480
1481 bool addTimestamp = Config_getEnum(TIMESTAMP)!=TIMESTAMP_t::NO;
1482 if (g_build_date || addTimestamp)
1483 {
1484 t << "\nhtml {\n";
1485
1486 if (addTimestamp)
1487 {
1488 QCString timeStampStr;
1489 switch (Config_getEnum(TIMESTAMP))
1490 {
1491 case TIMESTAMP_t::YES:
1492 case TIMESTAMP_t::DATETIME:
1493 timeStampStr = dateToString(DateTimeType::DateTime);
1494 break;
1495 case TIMESTAMP_t::DATE:
1496 timeStampStr = dateToString(DateTimeType::Date);
1497 break;
1498 default:
1499 break;
1500 }
1501 t << "--timestamp: '" << timeStampStr << "';\n";
1502 }
1503 if (g_build_date)
1504 {
1505 t << "--datetime: '" << dateToString(DateTimeType::DateTime) << "';\n";
1506 t << "--date: '" << dateToString(DateTimeType::Date) << "';\n";
1507 t << "--time: '" << dateToString(DateTimeType::Time) << "';\n";
1508 t << "--year: '" << yearToString() << "';\n";
1509 }
1510 t << "}\n";
1511
1512 if (addTimestamp)
1513 {
1514 t << "span.timestamp { content: ' '; }\n";
1515 t << "span.timestamp:before { content: var(--timestamp); }\n\n";
1516 }
1517 if (g_build_date)
1518 {
1519 t << "span.datetime { content: ' '; }\n";
1520 t << "span.datetime:before { content: var(--datetime); }\n\n";
1521 t << "span.date { content: ' '; }\n";
1522 t << "span.date:before { content: var(--date); }\n\n";
1523 t << "span.time { content: ' '; }\n";
1524 t << "span.time:before { content: var(--time); }\n\n";
1525 t << "span.year { content: ' '; }\n";
1526 t << "span.year:before { content: var(--year); }\n\n";
1527 }
1528 }
1529
1530 // For Webkit based the scrollbar styling cannot be overruled (bug in chromium?).
1531 // To allow the user to style the scrollbars differently we should only add it in case
1532 // the user did not specify any extra stylesheets.
1533 bool addScrollbarStyling = Config_getList(HTML_EXTRA_STYLESHEET).empty();
1534 if (addScrollbarStyling)
1535 {
1536 t << replaceVariables(ResourceMgr::instance().getAsString("scrollbar.css"));
1537 }
1538
1539}
1540
1546
1548{
1549 t << "<!-- HTML header for doxygen " << getDoxygenVersion() << "-->\n";
1550 t << ResourceMgr::instance().getAsString("header.html");
1551}
1552
1554{
1555 t << "<!-- HTML footer for doxygen " << getDoxygenVersion() << "-->\n";
1556 t << ResourceMgr::instance().getAsString("footer.html");
1557}
1558
1559static std::mutex g_indexLock;
1560
1561void HtmlGenerator::startFile(const QCString &name,bool isSource,const QCString &,
1562 const QCString &title,int /*id*/, int /*hierarchyLevel*/)
1563{
1564 //printf("HtmlGenerator::startFile(%s)\n",qPrint(name));
1566 QCString fileName = name;
1568 m_lastTitle=title;
1569
1571 m_codeGen->setFileName(fileName);
1572 m_codeGen->setRelativePath(m_relPath);
1573 {
1574 std::lock_guard<std::mutex> lock(g_indexLock);
1575 Doxygen::indexList->addIndexFile(fileName);
1576 }
1577
1580
1581 m_t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
1582 << getDoxygenVersion() << " -->\n";
1583 bool searchEngine = Config_getBool(SEARCHENGINE);
1584 if (searchEngine /*&& !generateTreeView*/)
1585 {
1586 m_t << "<script type=\"text/javascript\">\n";
1587 m_t << "let searchBox = new SearchBox(\"searchBox\", \""
1588 << m_relPath<< "search/\",'" << Doxygen::htmlFileExtension << "');\n";
1589 m_t << "</script>\n";
1590 }
1591 if (Config_getBool(HTML_CODE_FOLDING))
1592 {
1593 m_t << "<script type=\"text/javascript\">\n";
1594 m_t << "document.addEventListener('DOMContentLoaded', codefold.init);\n";
1595 m_t << "</script>\n";
1596 }
1598}
1599
1601{
1602 bool searchEngine = Config_getBool(SEARCHENGINE);
1603 bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
1604 if (searchEngine && !serverBasedSearch)
1605 {
1606 t << "<!-- window showing the filter options -->\n";
1607 t << "<div id=\"MSearchSelectWindow\"\n";
1608 t << " onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
1609 t << " onmouseout=\"return searchBox.OnSearchSelectHide()\"\n";
1610 t << " onkeydown=\"return searchBox.OnSearchSelectKey(event)\">\n";
1611 t << "</div>\n";
1612 t << "\n";
1613 t << "<!-- iframe showing the search results (closed by default) -->\n";
1614 t << "<div id=\"MSearchResultsWindow\">\n";
1615 t << "<div id=\"MSearchResults\">\n";
1616 t << "<div class=\"SRPage\">\n";
1617 t << "<div id=\"SRIndex\">\n";
1618 t << "<div id=\"SRResults\"></div>\n"; // here the results will be inserted
1619 t << "<div class=\"SRStatus\" id=\"Loading\">" << theTranslator->trLoading() << "</div>\n";
1620 t << "<div class=\"SRStatus\" id=\"Searching\">" << theTranslator->trSearching() << "</div>\n";
1621 t << "<div class=\"SRStatus\" id=\"NoMatches\">" << theTranslator->trNoMatches() << "</div>\n";
1622 t << "</div>\n"; // SRIndex
1623 t << "</div>\n"; // SRPage
1624 t << "</div>\n"; // MSearchResults
1625 t << "</div>\n"; // MSearchResultsWindow
1626 t << "\n";
1627 }
1628}
1629
1634
1635
1637{
1638 QCString result;
1639 switch (Config_getEnum(TIMESTAMP))
1640 {
1641 case TIMESTAMP_t::NO:
1642 result = theTranslator->trGeneratedBy();
1643 break;
1644 default:
1645 result = theTranslator->trGeneratedAt("<span class=\"timestamp\"></span>",
1646 convertToHtml(Config_getString(PROJECT_NAME)));
1647 break;
1648 }
1649 result += "&#160;\n<a href=\"https://www.doxygen.org/index.html\">\n"
1650 "<img class=\"footer\" src=\"";
1651 result += path;
1652 result += "doxygen.svg\" width=\"104\" height=\"31\" alt=\"doxygen\"/></a> ";
1653 result += getDoxygenVersion();
1654 result += " ";
1655 return result;
1656}
1657
1662
1664 const QCString &relPath,const QCString &navPath)
1665{
1666 t << substituteHtmlKeywords(g_footer_file,g_footer,convertToHtml(lastTitle),relPath,navPath);
1667}
1668
1670{
1672}
1673
1675{
1676 endPlainFile();
1677}
1678
1680{
1681 m_t << "<h3 class=\"version\">";
1682}
1683
1685{
1686 m_t << "</h3>";
1687}
1688
1690{
1691 //printf("writeStyleInfo(%d)\n",part);
1692 if (part==0)
1693 {
1694 if (Config_getString(HTML_STYLESHEET).isEmpty()) // write default style sheet
1695 {
1696 //printf("write doxygen.css\n");
1697 startPlainFile("doxygen.css");
1699 endPlainFile();
1700 Doxygen::indexList->addStyleSheetFile("doxygen.css");
1701 }
1702 else // write user defined style sheet
1703 {
1704 QCString cssName=Config_getString(HTML_STYLESHEET);
1705 if (!cssName.startsWith("http:") && !cssName.startsWith("https:"))
1706 {
1707 FileInfo cssfi(cssName.str());
1708 if (!cssfi.exists() || !cssfi.isFile() || !cssfi.isReadable())
1709 {
1710 err("style sheet {} does not exist or is not readable!\n", Config_getString(HTML_STYLESHEET));
1711 }
1712 else
1713 {
1714 // convert style sheet to string
1715 QCString fileStr = fileToString(cssName);
1716 // write the string into the output dir
1717 startPlainFile(cssfi.fileName());
1718 m_t << fileStr;
1719 endPlainFile();
1720 }
1721 Doxygen::indexList->addStyleSheetFile(cssfi.fileName());
1722 }
1723 }
1724 const StringVector &extraCssFiles = Config_getList(HTML_EXTRA_STYLESHEET);
1725 for (const auto &fileName : extraCssFiles)
1726 {
1727 if (!fileName.empty())
1728 {
1729 FileInfo fi(fileName);
1730 if (fi.exists())
1731 {
1732 Doxygen::indexList->addStyleSheetFile(fi.fileName());
1733 }
1734 }
1735 }
1736
1737 Doxygen::indexList->addStyleSheetFile("navtree.css");
1738
1739 if (Config_getBool(HTML_DYNAMIC_SECTIONS))
1740 {
1741 Doxygen::indexList->addStyleSheetFile("dynsections.js");
1742 }
1743 if (Config_getBool(HTML_CODE_FOLDING))
1744 {
1745 Doxygen::indexList->addStyleSheetFile("codefolding.js");
1746 }
1747
1748 if (Config_getEnum(HTML_COLORSTYLE)==HTML_COLORSTYLE_t::TOGGLE)
1749 {
1750 Doxygen::indexList->addStyleSheetFile("darkmode_toggle.js");
1751 }
1752
1753 if (Config_getBool(INTERACTIVE_SVG))
1754 {
1755 Doxygen::indexList->addStyleSheetFile("svg.min.js");
1756 }
1757
1758 if (!Config_getBool(DISABLE_INDEX) && Config_getBool(HTML_DYNAMIC_MENUS))
1759 {
1760 Doxygen::indexList->addStyleSheetFile("menu.js");
1761 Doxygen::indexList->addStyleSheetFile("menudata.js");
1762 }
1763 }
1764}
1765
1767 const QCString &anchor, const QCString &,
1768 const QCString &)
1769{
1770 m_t << "<a id=\"" << anchor << "\" name=\"" << anchor << "\"></a>";
1771}
1772
1774{
1775}
1776
1778{
1779}
1780
1782{
1783 if (!classDef.isEmpty())
1784 m_t << "\n<p class=\"" << classDef << "\">";
1785 else
1786 m_t << "\n<p>";
1787}
1788
1790{
1791 m_t << "</p>\n";
1792}
1793
1795{
1796 m_t << text;
1797}
1798
1800{
1801 m_t << "<li>";
1802}
1803
1805{
1806 m_t << "</li>\n";
1807}
1808
1810{
1811 //printf("HtmlGenerator::startIndexItem(%s,%s)\n",ref,f);
1812 if (!ref.isEmpty() || !f.isEmpty())
1813 {
1814 if (!ref.isEmpty())
1815 {
1816 m_t << "<a class=\"elRef\" ";
1818 }
1819 else
1820 {
1821 m_t << "<a class=\"el\" ";
1822 }
1823 m_t << "href=\"";
1824 m_t << externalRef(m_relPath,ref,TRUE);
1825 if (!f.isEmpty())
1826 {
1827 QCString fn=f;
1829 m_t << fn;
1830 }
1831 m_t << "\">";
1832 }
1833 else
1834 {
1835 m_t << "<b>";
1836 }
1837}
1838
1840{
1841 //printf("HtmlGenerator::endIndexItem(%s,%s,%s)\n",ref,f,name);
1842 if (!ref.isEmpty() || !f.isEmpty())
1843 {
1844 m_t << "</a>";
1845 }
1846 else
1847 {
1848 m_t << "</b>";
1849 }
1850}
1851
1853 const QCString &path,const QCString &name)
1854{
1855 m_t << "<li>";
1856 if (!path.isEmpty()) docify(path);
1857 QCString fn = f;
1859 m_t << "<a class=\"el\" href=\"" << fn << "\">";
1860 docify(name);
1861 m_t << "</a> ";
1862}
1863
1865 const QCString &anchor, const QCString &name)
1866{
1867 if (!ref.isEmpty())
1868 {
1869 m_t << "<a class=\"elRef\" ";
1871 }
1872 else
1873 {
1874 m_t << "<a class=\"el\" ";
1875 }
1876 m_t << "href=\"";
1877 QCString fn = f;
1879 m_t << createHtmlUrl(m_relPath,ref,true,
1880 fileName() == Config_getString(HTML_OUTPUT)+"/"+fn,
1881 fn,
1882 anchor);
1883 m_t << "\">";
1884 docify(name);
1885 m_t << "</a>";
1886}
1887
1889{
1890 m_t << "<a href=\"";
1891 QCString fn = f;
1893 m_t << createHtmlUrl(m_relPath,"",true,
1894 fileName() == Config_getString(HTML_OUTPUT)+"/"+fn,
1895 fn,
1896 anchor);
1897 m_t << "\">";
1898}
1899
1901{
1902 m_t << "</a>";
1903}
1904
1905void HtmlGenerator::startGroupHeader(const QCString &id,int extraIndentLevel)
1906{
1907 if (extraIndentLevel==2)
1908 {
1909 m_t << "<h4";
1910 }
1911 else if (extraIndentLevel==1)
1912 {
1913 m_t << "<h3";
1914 }
1915 else // extraIndentLevel==0
1916 {
1917 m_t << "<h2";
1918 }
1919 if (!id.isEmpty())
1920 {
1921 m_t <<" id=\"header-"+convertToId(id)+"\"";
1922 }
1923 m_t << " class=\"groupheader\">";
1924}
1925
1926void HtmlGenerator::endGroupHeader(int extraIndentLevel)
1927{
1928 if (extraIndentLevel==2)
1929 {
1930 m_t << "</h4>\n";
1931 }
1932 else if (extraIndentLevel==1)
1933 {
1934 m_t << "</h3>\n";
1935 }
1936 else
1937 {
1938 m_t << "</h2>\n";
1939 }
1940}
1941
1943{
1944 switch(type.level())
1945 {
1946 case SectionType::Page: m_t << "\n\n<h1 class=\"doxsection\">"; break;
1947 case SectionType::Section: m_t << "\n\n<h2 class=\"doxsection\">"; break;
1948 case SectionType::Subsection: m_t << "\n\n<h3 class=\"doxsection\">"; break;
1949 case SectionType::Subsubsection: m_t << "\n\n<h4 class=\"doxsection\">"; break;
1950 case SectionType::Paragraph: m_t << "\n\n<h5 class=\"doxsection\">"; break;
1951 case SectionType::Subparagraph: m_t << "\n\n<h6 class=\"doxsection\">"; break;
1952 case SectionType::Subsubparagraph: m_t << "\n\n<h6 class=\"doxsection\">"; break;
1953 default: ASSERT(0); break;
1954 }
1955 m_t << "<a id=\"" << lab << "\" name=\"" << lab << "\"></a>";
1956}
1957
1959{
1960 switch(type.level())
1961 {
1962 case SectionType::Page: m_t << "</h1>"; break;
1963 case SectionType::Section: m_t << "</h2>"; break;
1964 case SectionType::Subsection: m_t << "</h3>"; break;
1965 case SectionType::Subsubsection: m_t << "</h4>"; break;
1966 case SectionType::Paragraph: m_t << "</h5>"; break;
1967 case SectionType::Subparagraph: m_t << "</h6>"; break;
1968 case SectionType::Subsubparagraph: m_t << "</h6>"; break;
1969 default: ASSERT(0); break;
1970 }
1971}
1972
1974{
1975 docify_(str,FALSE);
1976}
1977
1978void HtmlGenerator::docify_(const QCString &str,bool inHtmlComment)
1979{
1980 if (!str.isEmpty())
1981 {
1982 const char *p=str.data();
1983 while (*p)
1984 {
1985 char c=*p++;
1986 switch(c)
1987 {
1988 case '<': m_t << "&lt;"; break;
1989 case '>': m_t << "&gt;"; break;
1990 case '&': m_t << "&amp;"; break;
1991 case '"': m_t << "&quot;"; break;
1992 case '-': if (inHtmlComment) m_t << "&#45;"; else m_t << "-"; break;
1993 case '\\':
1994 if (*p=='<')
1995 { m_t << "&lt;"; p++; }
1996 else if (*p=='>')
1997 { m_t << "&gt;"; p++; }
1998 else if (*p=='[')
1999 { m_t << "\\&zwj;["; p++; }
2000 else if (*p==']')
2001 { m_t << "\\&zwj;]"; p++; }
2002 else if (*p=='(')
2003 { m_t << "\\&zwj;("; p++; }
2004 else if (*p==')')
2005 { m_t << "\\&zwj;)"; p++; }
2006 else
2007 m_t << "\\";
2008 break;
2009 default: m_t << c;
2010 }
2011 }
2012 }
2013}
2014
2016{
2017 char cs[2];
2018 cs[0]=c;
2019 cs[1]=0;
2020 docify(cs);
2021}
2022
2023//--- helper function for dynamic sections -------------------------
2024
2026 const QCString &relPath,int sectionCount)
2027{
2028 //t << "<!-- startSectionHeader -->";
2029 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2030 if (dynamicSections)
2031 {
2032 t << "<div id=\"dynsection-" << sectionCount << "\" "
2033 "onclick=\"return dynsection.toggleVisibility(this)\" "
2034 "class=\"dynheader closed\" "
2035 "style=\"cursor:pointer;\">"
2036 "<span class=\"dynarrow\"><span class=\"arrowhead closed\"></span></span>";
2037 }
2038 else
2039 {
2040 t << "<div class=\"dynheader\">\n";
2041 }
2042}
2043
2045{
2046 //t << "<!-- endSectionHeader -->";
2047 t << "</div>\n";
2048}
2049
2050static void startSectionSummary(TextStream &t,int sectionCount)
2051{
2052 //t << "<!-- startSectionSummary -->";
2053 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2054 if (dynamicSections)
2055 {
2056 t << "<div id=\"dynsection-" << sectionCount << "-summary\" "
2057 "class=\"dynsummary\" "
2058 "style=\"display:block;\">\n";
2059 }
2060}
2061
2063{
2064 //t << "<!-- endSectionSummary -->";
2065 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2066 if (dynamicSections)
2067 {
2068 t << "</div>\n";
2069 }
2070}
2071
2072static void startSectionContent(TextStream &t,int sectionCount)
2073{
2074 //t << "<!-- startSectionContent -->";
2075 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2076 if (dynamicSections)
2077 {
2078 t << "<div id=\"dynsection-" << sectionCount << "-content\" "
2079 "class=\"dyncontent\" "
2080 "style=\"display:none;\">\n";
2081 }
2082 else
2083 {
2084 t << "<div class=\"dyncontent\">\n";
2085 }
2086}
2087
2089{
2090 //t << "<!-- endSectionContent -->";
2091 t << "</div>\n";
2092}
2093
2094//----------------------------
2095
2100
2102 const QCString &fileName,const QCString &name)
2103{
2108 TextStream tt;
2110 if (!tt.empty())
2111 {
2112 m_t << " <div class=\"center\">\n";
2113 m_t << " <img src=\"";
2114 m_t << m_relPath << fileName << ".png\" usemap=\"#" << convertToId(name);
2115 m_t << "_map\" alt=\"\"/>\n";
2116 m_t << " <map id=\"" << convertToId(name);
2117 m_t << "_map\" name=\"" << convertToId(name);
2118 m_t << "_map\">\n";
2119 m_t << tt.str();
2120 m_t << " </map>\n";
2121 m_t << "</div>";
2122 }
2123 else
2124 {
2125 m_t << " <div class=\"center\">\n";
2126 m_t << " <img src=\"";
2127 m_t << m_relPath << fileName << ".png\" alt=\"\"/>\n";
2128 m_t << " </div>";
2129 }
2132}
2133
2134
2136{
2137 DBG_HTML(m_t << "<!-- startMemberList -->\n")
2138}
2139
2141{
2142 DBG_HTML(m_t << "<!-- endMemberList -->\n")
2143}
2144
2145// anonymous type:
2146// 0 = single column right aligned
2147// 1 = double column left aligned
2148// 2 = single column left aligned
2150{
2151 DBG_HTML(m_t << "<!-- startMemberItem() -->\n")
2152 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2153 if (m_emptySection)
2154 {
2155 m_t << "<table class=\"memberdecls\">\n";
2157 }
2158 m_t << "<tr class=\"memitem:" << convertToId(anchor);
2159 if (!inheritId.isEmpty())
2160 {
2161 if (dynamicSections) m_t << " inherit";
2162 m_t << " " << inheritId;
2163 }
2164 m_t << "\"";
2165 if (!anchor.isEmpty())
2166 {
2167 m_t << " id=\"r_" << convertToId(anchor) << "\"";
2168 }
2169 m_t << ">";
2171}
2172
2174{
2176 {
2177 insertMemberAlign(false);
2178 }
2179 m_t << "</td></tr>\n";
2180}
2181
2185
2187{
2188 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2189 m_t << "</td></tr>\n";
2190 m_t << "<tr class=\"memitem:" << convertToId(anchor);
2191 if (!inheritId.isEmpty())
2192 {
2193 if (dynamicSections) m_t << " inherit";
2194 m_t << " " << inheritId;
2195 }
2196 m_t << " template\"><td class=\"memItemLeft\">";
2197}
2198
2200{
2201 m_t << "<div class=\"compoundTemplParams\">";
2202}
2203
2205{
2206 m_t << "</div>";
2207}
2208
2210{
2211 DBG_HTML(m_t << "<!-- insertMemberAlign -->\n")
2212 m_t << "&#160;</td><td class=\"memItemRight\">";
2213}
2214
2216{
2217 if (!initTag) m_t << "&#160;</td>";
2218 switch (type)
2219 {
2220 case MemberItemType::Normal: m_t << "<td class=\"memItemLeft\">"; break;
2221 case MemberItemType::AnonymousStart: m_t << "<td class=\"memItemLeft anon\">"; break;
2222 case MemberItemType::AnonymousEnd: m_t << "<td class=\"memItemLeft anonEnd\">"; break;
2223 case MemberItemType::Templated: m_t << "<td class=\"memTemplParams\" colspan=\"2\">"; break;
2224 }
2225}
2226
2227void HtmlGenerator::startMemberDescription(const QCString &anchor,const QCString &inheritId, bool typ)
2228{
2229 DBG_HTML(m_t << "<!-- startMemberDescription -->\n")
2230 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
2231 if (m_emptySection)
2232 {
2233 m_t << "<table class=\"memberdecls\">\n";
2235 }
2236 m_t << "<tr class=\"memdesc:" << anchor;
2237 if (!inheritId.isEmpty())
2238 {
2239 if (dynamicSections) m_t << " inherit";
2240 m_t << " " << inheritId;
2241 }
2242 m_t << "\">";
2243 m_t << "<td class=\"mdescLeft\">&#160;</td>";
2244 if (typ) m_t << "<td class=\"mdescLeft\">&#160;</td>";
2245 m_t << "<td class=\"mdescRight\">";
2246}
2247
2249{
2250 DBG_HTML(m_t << "<!-- endMemberDescription -->\n")
2251 m_t << "<br /></td></tr>\n";
2252}
2253
2255{
2256 DBG_HTML(m_t << "<!-- startMemberSections -->\n")
2257 m_emptySection=TRUE; // we postpone writing <table> until we actually
2258 // write a row to prevent empty tables, which
2259 // are not valid XHTML!
2260}
2261
2263{
2264 DBG_HTML(m_t << "<!-- endMemberSections -->\n")
2265 if (!m_emptySection)
2266 {
2267 m_t << "</table>\n";
2268 }
2269}
2270
2271void HtmlGenerator::startMemberHeader(const QCString &anchor, int typ)
2272{
2273 DBG_HTML(m_t << "<!-- startMemberHeader -->\n")
2274 if (!m_emptySection)
2275 {
2276 m_t << "</table>";
2278 }
2279 if (m_emptySection)
2280 {
2281 m_t << "<table class=\"memberdecls\">\n";
2283 }
2284 m_t << "<tr class=\"heading\"><td colspan=\"" << typ << "\"><h2";
2285 if (!anchor.isEmpty())
2286 {
2287 m_t << " id=\"header-" << anchor << "\"";
2288 }
2289 m_t << " class=\"groupheader\">";
2290 if (!anchor.isEmpty())
2291 {
2292 m_t << "<a id=\"" << anchor << "\" name=\"" << anchor << "\"></a>\n";
2293 }
2294}
2295
2297{
2298 DBG_HTML(m_t << "<!-- endMemberHeader -->\n")
2299 m_t << "</h2></td></tr>\n";
2300}
2301
2303{
2304 DBG_HTML(m_t << "<!-- startMemberSubtitle -->\n")
2305 if (m_emptySection)
2306 {
2307 m_t << "<table class=\"memberdecls\">\n";
2309 }
2310 m_t << "<tr><td class=\"ititle\" colspan=\"2\">";
2311}
2312
2314{
2315 DBG_HTML(m_t << "<!-- endMemberSubtitle -->\n")
2316 m_t << "</td></tr>\n";
2317}
2318
2320{
2321 m_t << "<table>\n";
2322}
2323
2325{
2326 m_t << "</table>\n";
2327}
2328
2330{
2331 //m_t << " <tr><td class=\"indexkey\">";
2332}
2333
2335{
2336 //m_t << "</td>";
2337}
2338
2340{
2341 //m_t << "<td class=\"indexvalue\">";
2342}
2343
2345{
2346 //m_t << "</td></tr>\n";
2347}
2348
2350{
2351 DBG_HTML(m_t << "<!-- startMemberDocList -->\n";)
2352}
2353
2355{
2356 DBG_HTML(m_t << "<!-- endMemberDocList -->\n";)
2357}
2358
2359void HtmlGenerator::startMemberDoc( const QCString &/* clName */, const QCString &/* memName */,
2360 const QCString &anchor, const QCString &title,
2361 int memCount, int memTotal, bool /* showInline */)
2362{
2363 DBG_HTML(m_t << "<!-- startMemberDoc -->\n";)
2364 m_t << "\n<h2 class=\"memtitle\">"
2365 << "<span class=\"permalink\"><a href=\"#" << anchor << "\">&#9670;&#160;</a></span>";
2366 docify(title);
2367 if (memTotal>1)
2368 {
2369 m_t << " <span class=\"overload\">[" << memCount << "/" << memTotal <<"]</span>";
2370 }
2371 m_t << "</h2>\n";
2372 m_t << "\n<div class=\"memitem\">\n";
2373 m_t << "<div class=\"memproto\">\n";
2374}
2375
2377{
2378 DBG_HTML(m_t << "<!-- startMemberDocPrefixItem -->\n";)
2379 m_t << "<div class=\"memtemplate\">\n";
2380}
2381
2383{
2384 DBG_HTML(m_t << "<!-- endMemberDocPrefixItem -->\n";)
2385 m_t << "</div>\n";
2386}
2387
2389{
2390 DBG_HTML(m_t << "<!-- startMemberDocName -->\n";)
2391
2392 m_t << " <table class=\"memname\">\n";
2393
2394 m_t << " <tr>\n";
2395 m_t << " <td class=\"memname\">";
2396}
2397
2399{
2400 DBG_HTML(m_t << "<!-- endMemberDocName -->\n";)
2401 m_t << "</td>\n";
2402}
2403
2405{
2406 DBG_HTML(m_t << "<!-- startParameterList -->\n";)
2407 m_t << " <td>";
2408 if (openBracket) m_t << "(";
2409 m_t << "</td>\n";
2410}
2411
2413{
2414 if (first)
2415 {
2416 DBG_HTML(m_t << "<!-- startFirstParameterType -->\n";)
2417 m_t << " <td class=\"paramtype\">";
2418 }
2419 else
2420 {
2421 DBG_HTML(m_t << "<!-- startParameterType -->\n";)
2422 m_t << " <tr>\n";
2423 m_t << " <td class=\"paramkey\">" << key << "</td>\n";
2424 m_t << " <td></td>\n";
2425 m_t << " <td class=\"paramtype\">";
2426 }
2427}
2428
2430{
2431 DBG_HTML(m_t << "<!-- endParameterType -->\n";)
2432 m_t << "</td>";
2433}
2434
2435void HtmlGenerator::startParameterName(bool /*oneArgOnly*/)
2436{
2437 DBG_HTML(m_t << "<!-- startParameterName -->\n";)
2438 m_t << " <td class=\"paramname\"><span class=\"paramname\"><em>";
2439}
2440
2442{
2443 DBG_HTML(m_t << "<!-- endParameterName -->\n";)
2444 m_t << "</em></span>";
2445}
2446
2448{
2449 DBG_HTML(m_t << "<!-- startParameterExtra -->\n";)
2450}
2451
2452void HtmlGenerator::endParameterExtra(bool last,bool emptyList, bool closeBracket)
2453{
2454 DBG_HTML(m_t << "<!-- endParameterExtra -->\n";)
2455 if (last)
2456 {
2457 if (emptyList)
2458 {
2459 if (closeBracket) m_t << "</td><td>)";
2460 m_t << "</td>\n";
2461 m_t << " <td>";
2462 }
2463 else
2464 {
2465 m_t << "&#160;";
2466 if (closeBracket) m_t << ")";
2467 }
2468 }
2469 else
2470 {
2471 m_t << "</td>\n";
2472 m_t << " </tr>\n";
2473 }
2474}
2475
2477{
2478 m_t << "<span class=\"paramdefsep\">";
2479 docify(s);
2480 m_t << "</span><span class=\"paramdefval\">";
2481}
2482
2484{
2485 m_t << "</span>";
2486}
2487
2489{
2490 DBG_HTML(m_t << "<!-- endParameterList -->\n";)
2491 m_t << "</td>\n";
2492 m_t << " </tr>\n";
2493}
2494
2495void HtmlGenerator::exceptionEntry(const QCString &prefix,bool closeBracket)
2496{
2497 DBG_HTML(m_t << "<!-- exceptionEntry -->\n";)
2498 if (!closeBracket)
2499 {
2500 m_t << "</td>\n";
2501 m_t << " </tr>\n";
2502 m_t << " <tr>\n";
2503 m_t << " <td align=\"right\">";
2504 }
2505 // colspan 2 so it gets both parameter type and parameter name columns
2506 if (!prefix.isEmpty())
2507 m_t << prefix << "</td><td>(</td><td colspan=\"2\">";
2508 else if (closeBracket)
2509 m_t << "&#160;)</td><td></td><td></td><td>";
2510 else
2511 m_t << "</td><td></td><td colspan=\"2\">";
2512}
2513
2515{
2516 DBG_HTML(m_t << "<!-- endMemberDoc -->\n";)
2517 if (!hasArgs)
2518 {
2519 m_t << " </tr>\n";
2520 }
2521 m_t << " </table>\n";
2522 // m_t << "</div>\n";
2523}
2524
2529
2531{
2532 bool generateLegend = Config_getBool(GENERATE_LEGEND);
2533 bool umlLook = Config_getBool(UML_LOOK);
2538
2540 if (generateLegend && !umlLook)
2541 {
2542 QCString url = m_relPath+"graph_legend"+Doxygen::htmlFileExtension;
2543 m_t << "<center><span class=\"legend\">[";
2544 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2545 m_t << "<a ";
2546 if (generateTreeView) m_t << "target=\"top\" ";
2547 m_t << "href=\"";
2548 if (!url.isEmpty()) m_t << url;
2549 m_t << "\">";
2550 m_t << theTranslator->trLegend();
2551 m_t << "</a>";
2552 m_t << "]</span></center>";
2553 }
2554
2557}
2558
2563
2576
2581
2594
2599
2612
2617
2630
2635
2637{
2638 m_t << "<tr id=\"" << id << "\" class=\"groupHeader\"><td colspan=\"2\"><div class=\"groupHeader\">";
2639}
2640
2642{
2643 m_t << "</div></td></tr>\n";
2644}
2645
2647{
2648 m_t << "<tr><td colspan=\"2\" class=\"ititle\"><div class=\"groupText\">";
2649}
2650
2652{
2653 m_t << "</div></td></tr>\n";
2654}
2655
2659
2661{
2662}
2663
2665{
2666 DBG_HTML(m_t << "<!-- startIndent -->\n";)
2667
2668 m_t << "<div class=\"memdoc\">\n";
2669}
2670
2672{
2673 DBG_HTML(m_t << "<!-- endIndent -->\n";)
2674 m_t << "\n</div>\n" << "</div>\n";
2675}
2676
2678{
2679}
2680
2682{
2683 for (int i=0; i<n; i++)
2684 {
2685 m_t << "&#160;";
2686 }
2687}
2688
2689void HtmlGenerator::startDescTable(const QCString &title,const bool hasInits)
2690{
2691 m_t << "<table class=\"fieldtable\">\n"
2692 << "<tr><th colspan=\"" << (hasInits?3:2) << "\">" << title << "</th></tr>";
2693}
2695{
2696 m_t << "</table>\n";
2697}
2698
2700{
2701 m_t << "<tr>";
2702}
2703
2705{
2706 m_t << "</tr>\n";
2707}
2708
2710{
2711 m_t << "<td class=\"fieldname\">";
2712}
2713
2715{
2716 m_t << "&#160;</td>";
2717}
2718
2720{
2721 m_t << "<td class=\"fieldinit\">";
2722}
2723
2725{
2726 m_t << "&#160;</td>";
2727}
2728
2730{
2731 m_t << "<td class=\"fielddoc\">";
2732}
2733
2735{
2736 m_t << "</td>";
2737}
2738
2740{
2741 m_t << "<dl class=\"section examples\"><dt>";
2742 docify(theTranslator->trExamples());
2743 m_t << "</dt>";
2744}
2745
2747{
2748 m_t << "</dl>\n";
2749}
2750
2751void HtmlGenerator::writeDoc(const IDocNodeAST *ast,const Definition *ctx,const MemberDef *,int id,int sectionLevel)
2752{
2753 const DocNodeAST *astImpl = dynamic_cast<const DocNodeAST*>(ast);
2754 if (astImpl && sectionLevel<=m_tocState.maxLevel)
2755 {
2756 m_codeList->setId(id);
2757 HtmlDocVisitor visitor(m_t,*m_codeList,ctx,fileName());
2758 std::visit(visitor,astImpl->root);
2759 }
2760}
2761
2762//---------------- helpers for index generation -----------------------------
2763
2764static void startQuickIndexList(TextStream &t,bool topLevel=TRUE)
2765{
2766 if (!Config_getBool(DISABLE_INDEX))
2767 {
2768 if (topLevel)
2769 {
2770 t << " <div id=\"navrow1\" class=\"tabs\">\n";
2771 }
2772 else
2773 {
2774 t << " <div id=\"navrow2\" class=\"tabs2\">\n";
2775 }
2776 t << " <ul class=\"tablist\">\n";
2777 }
2778 else
2779 {
2780 t << "<ul>";
2781 }
2782}
2783
2785{
2786 if (!Config_getBool(DISABLE_INDEX))
2787 {
2788 t << " </ul>\n";
2789 t << " </div>\n";
2790 }
2791 else
2792 {
2793 t << "</ul>\n";
2794 }
2795}
2796
2798 bool hl,bool /*compact*/,
2799 const QCString &relPath)
2800{
2801 t << " <li";
2802 if (hl)
2803 {
2804 t << " class=\"current\"";
2805 }
2806 t << ">";
2807 if (!l.isEmpty()) t << "<a href=\"" << correctURL(l,relPath) << "\">";
2808 t << "<span>";
2809}
2810
2811static void endQuickIndexItem(TextStream &t,const QCString &l)
2812{
2813 t << "</span>";
2814 if (!l.isEmpty()) t << "</a>";
2815 t << "</li>\n";
2816}
2817
2819{
2820 const auto &index = Index::instance();
2821 bool showNamespaces = Config_getBool(SHOW_NAMESPACES);
2822 bool showFiles = Config_getBool(SHOW_FILES);
2823 switch (kind)
2824 {
2825 case LayoutNavEntry::MainPage: return TRUE;
2826 case LayoutNavEntry::User: return TRUE;
2827 case LayoutNavEntry::UserGroup: return TRUE;
2828 case LayoutNavEntry::Pages: return index.numIndexedPages()>0;
2829 case LayoutNavEntry::Topics: return index.numDocumentedGroups()>0;
2830 case LayoutNavEntry::Modules: return index.numDocumentedModules()>0;
2831 case LayoutNavEntry::ModuleList: return index.numDocumentedModules()>0;
2832 case LayoutNavEntry::ModuleMembers: return index.numDocumentedModuleMembers(ModuleMemberHighlight::All)>0;
2833 case LayoutNavEntry::Namespaces: return showNamespaces && index.numDocumentedNamespaces()>0;
2834 case LayoutNavEntry::NamespaceList: return showNamespaces && index.numDocumentedNamespaces()>0;
2835 case LayoutNavEntry::NamespaceMembers: return showNamespaces && index.numDocumentedNamespaceMembers(NamespaceMemberHighlight::All)>0;
2836 case LayoutNavEntry::Concepts: return index.numDocumentedConcepts()>0;
2837 case LayoutNavEntry::Classes: return index.numAnnotatedClasses()>0;
2838 case LayoutNavEntry::ClassList: return index.numAnnotatedClasses()>0;
2839 case LayoutNavEntry::ClassIndex: return index.numAnnotatedClasses()>0;
2840 case LayoutNavEntry::ClassHierarchy: return index.numHierarchyClasses()>0;
2841 case LayoutNavEntry::ClassMembers: return index.numDocumentedClassMembers(ClassMemberHighlight::All)>0;
2842 case LayoutNavEntry::Files: return showFiles && index.numDocumentedFiles()>0;
2843 case LayoutNavEntry::FileList: return showFiles && index.numDocumentedFiles()>0;
2844 case LayoutNavEntry::FileGlobals: return showFiles && index.numDocumentedFileMembers(FileMemberHighlight::All)>0;
2845 case LayoutNavEntry::Examples: return !Doxygen::exampleLinkedMap->empty();
2846 case LayoutNavEntry::Interfaces: return index.numAnnotatedInterfaces()>0;
2847 case LayoutNavEntry::InterfaceList: return index.numAnnotatedInterfaces()>0;
2848 case LayoutNavEntry::InterfaceIndex: return index.numAnnotatedInterfaces()>0;
2849 case LayoutNavEntry::InterfaceHierarchy: return index.numHierarchyInterfaces()>0;
2850 case LayoutNavEntry::Structs: return index.numAnnotatedStructs()>0;
2851 case LayoutNavEntry::StructList: return index.numAnnotatedStructs()>0;
2852 case LayoutNavEntry::StructIndex: return index.numAnnotatedStructs()>0;
2853 case LayoutNavEntry::Exceptions: return index.numAnnotatedExceptions()>0;
2854 case LayoutNavEntry::ExceptionList: return index.numAnnotatedExceptions()>0;
2855 case LayoutNavEntry::ExceptionIndex: return index.numAnnotatedExceptions()>0;
2856 case LayoutNavEntry::ExceptionHierarchy: return index.numHierarchyExceptions()>0;
2857 case LayoutNavEntry::None: // should never happen, means not properly initialized
2858 assert(kind != LayoutNavEntry::None);
2859 return FALSE;
2860 }
2861 return FALSE;
2862}
2863
2864static void renderQuickLinksAsTree(TextStream &t,const QCString &relPath,LayoutNavEntry *root)
2865
2866{
2867 int count=0;
2868 for (const auto &entry : root->children())
2869 {
2870 if (entry->visible() && quickLinkVisible(entry->kind())) count++;
2871 }
2872 if (count>0) // at least one item is visible
2873 {
2875 for (const auto &entry : root->children())
2876 {
2877 if (entry->visible() && quickLinkVisible(entry->kind()))
2878 {
2879 QCString url = entry->url();
2880 t << "<li><a href=\"" << relPath << url << "\"><span>";
2881 t << fixSpaces(entry->title());
2882 t << "</span></a>\n";
2883 // recursive into child list
2884 renderQuickLinksAsTree(t,relPath,entry.get());
2885 t << "</li>";
2886 }
2887 }
2889 }
2890}
2891
2892
2893static void renderQuickLinksAsTabs(TextStream &t,const QCString &relPath,
2895 bool highlightParent,bool highlightSearch)
2896{
2897 if (hlEntry->parent()) // first draw the tabs for the parent of hlEntry
2898 {
2899 renderQuickLinksAsTabs(t,relPath,hlEntry->parent(),kind,highlightParent,highlightSearch);
2900 }
2901 if (hlEntry->parent() && !hlEntry->parent()->children().empty()) // draw tabs for row containing hlEntry
2902 {
2903 bool topLevel = hlEntry->parent()->parent()==nullptr;
2904 int count=0;
2905 for (const auto &entry : hlEntry->parent()->children())
2906 {
2907 if (entry->visible() && quickLinkVisible(entry->kind())) count++;
2908 }
2909 if (count>0) // at least one item is visible
2910 {
2911 startQuickIndexList(t,topLevel);
2912 for (const auto &entry : hlEntry->parent()->children())
2913 {
2914 if (entry->visible() && quickLinkVisible(entry->kind()))
2915 {
2916 QCString url = entry->url();
2917 startQuickIndexItem(t,url,
2918 entry.get()==hlEntry &&
2919 (!entry->children().empty() ||
2920 (entry->kind()==kind && !highlightParent)
2921 ),
2922 TRUE,relPath);
2923 t << fixSpaces(entry->title());
2924 endQuickIndexItem(t,url);
2925 }
2926 }
2927 if (hlEntry->parent()==LayoutDocManager::instance().rootNavEntry()) // first row is special as it contains the search box
2928 {
2929 bool searchEngine = Config_getBool(SEARCHENGINE);
2930 bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
2931 bool disableIndex = Config_getBool(DISABLE_INDEX);
2932 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2933 bool fullSidebar = Config_getBool(FULL_SIDEBAR);
2934 // case where DISABLE_INDEX=NO & GENERATE_TREEVIEW=YES & FULL_SIDEBAR=YES has search box in the side panel
2935 if (searchEngine)
2936 {
2937 t << " <li>\n";
2938 if (disableIndex || !generateTreeView || !fullSidebar)
2939 {
2940 if (!serverBasedSearch) // pure client side search
2941 {
2942 writeClientSearchBox(t,relPath);
2943 t << " </li>\n";
2944 }
2945 else // server based search
2946 {
2947 writeServerSearchBox(t,relPath,highlightSearch);
2948 if (!highlightSearch)
2949 {
2950 t << " </li>\n";
2951 }
2952 }
2953 }
2954 else
2955 {
2956 t << " </li>\n";
2957 }
2958 }
2959 if (!highlightSearch || Config_getBool(FULL_SIDEBAR))
2960 // on the search page the index will be ended by the page itself if the search box is part of the navigation bar
2961 {
2963 }
2964 }
2965 else // normal case for other rows than first one
2966 {
2968 }
2969 }
2970 }
2971}
2972
2974 HighlightedItem hli,
2975 const QCString &file,
2976 const QCString &relPath,
2977 bool extraTabs)
2978{
2979 bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
2980 bool searchEngine = Config_getBool(SEARCHENGINE);
2981 bool externalSearch = Config_getBool(EXTERNAL_SEARCH);
2982 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2983 bool fullSidebar = Config_getBool(FULL_SIDEBAR);
2984 bool disableIndex = Config_getBool(DISABLE_INDEX);
2985 bool dynamicMenus = Config_getBool(HTML_DYNAMIC_MENUS);
2987 LayoutNavEntry::Kind kind = LayoutNavEntry::None;
2988 LayoutNavEntry::Kind altKind = LayoutNavEntry::None; // fall back for the old layout file
2989 bool highlightParent=false;
2990 switch (hli) // map HLI enums to LayoutNavEntry::Kind enums
2991 {
2992 case HighlightedItem::Main: kind = LayoutNavEntry::MainPage; break;
2993 case HighlightedItem::Topics: kind = LayoutNavEntry::Topics; break;
2994 case HighlightedItem::Modules: kind = LayoutNavEntry::ModuleList; altKind = LayoutNavEntry::Modules; break;
2995 case HighlightedItem::Namespaces: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces; break;
2996 case HighlightedItem::ClassHierarchy: kind = LayoutNavEntry::ClassHierarchy; break;
2997 case HighlightedItem::InterfaceHierarchy: kind = LayoutNavEntry::InterfaceHierarchy; break;
2998 case HighlightedItem::ExceptionHierarchy: kind = LayoutNavEntry::ExceptionHierarchy; break;
2999 case HighlightedItem::Classes: kind = LayoutNavEntry::ClassIndex; altKind = LayoutNavEntry::Classes; break;
3000 case HighlightedItem::Concepts: kind = LayoutNavEntry::Concepts; break;
3001 case HighlightedItem::Interfaces: kind = LayoutNavEntry::InterfaceIndex; altKind = LayoutNavEntry::Interfaces; break;
3002 case HighlightedItem::Structs: kind = LayoutNavEntry::StructIndex; altKind = LayoutNavEntry::Structs; break;
3003 case HighlightedItem::Exceptions: kind = LayoutNavEntry::ExceptionIndex; altKind = LayoutNavEntry::Exceptions; break;
3004 case HighlightedItem::AnnotatedClasses: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; break;
3005 case HighlightedItem::AnnotatedInterfaces: kind = LayoutNavEntry::InterfaceList; altKind = LayoutNavEntry::Interfaces; break;
3006 case HighlightedItem::AnnotatedStructs: kind = LayoutNavEntry::StructList; altKind = LayoutNavEntry::Structs; break;
3007 case HighlightedItem::AnnotatedExceptions: kind = LayoutNavEntry::ExceptionList; altKind = LayoutNavEntry::Exceptions; break;
3008 case HighlightedItem::Files: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files; break;
3009 case HighlightedItem::NamespaceMembers: kind = LayoutNavEntry::NamespaceMembers; break;
3010 case HighlightedItem::ModuleMembers: kind = LayoutNavEntry::ModuleMembers; break;
3011 case HighlightedItem::Functions: kind = LayoutNavEntry::ClassMembers; break;
3012 case HighlightedItem::Globals: kind = LayoutNavEntry::FileGlobals; break;
3013 case HighlightedItem::Pages: kind = LayoutNavEntry::Pages; break;
3014 case HighlightedItem::Examples: kind = LayoutNavEntry::Examples; break;
3015 case HighlightedItem::UserGroup: kind = LayoutNavEntry::UserGroup; break;
3016 case HighlightedItem::ClassVisible: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes;
3017 highlightParent = true; break;
3018 case HighlightedItem::ConceptVisible: kind = LayoutNavEntry::Concepts;
3019 highlightParent = true; break;
3020 case HighlightedItem::ModuleVisible: kind = LayoutNavEntry::ModuleList; altKind = LayoutNavEntry::Modules;
3021 highlightParent = true; break;
3022 case HighlightedItem::InterfaceVisible: kind = LayoutNavEntry::InterfaceList; altKind = LayoutNavEntry::Interfaces;
3023 highlightParent = true; break;
3024 case HighlightedItem::StructVisible: kind = LayoutNavEntry::StructList; altKind = LayoutNavEntry::Structs;
3025 highlightParent = true; break;
3026 case HighlightedItem::ExceptionVisible: kind = LayoutNavEntry::ExceptionList; altKind = LayoutNavEntry::Exceptions;
3027 highlightParent = true; break;
3028 case HighlightedItem::NamespaceVisible: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces;
3029 highlightParent = true; break;
3030 case HighlightedItem::FileVisible: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files;
3031 highlightParent = true; break;
3032 case HighlightedItem::None: break;
3033 case HighlightedItem::Search: break;
3034 }
3035
3036 if (!disableIndex && dynamicMenus)
3037 {
3038 QCString searchPage;
3039 if (externalSearch)
3040 {
3041 searchPage = "search" + Doxygen::htmlFileExtension;
3042 }
3043 else
3044 {
3045 searchPage = "search.php";
3046 }
3047 t << "<script type=\"text/javascript\" src=\"" << relPath << "menudata.js\"></script>\n";
3048 t << "<script type=\"text/javascript\" src=\"" << relPath << "menu.js\"></script>\n";
3049 t << "<script type=\"text/javascript\">\n";
3050 t << "document.addEventListener('DOMContentLoaded', () => {\n";
3051 t << " initMenu('" << relPath << "'," << (generateTreeView?"true":"false") << ");\n";
3052 if (searchEngine)
3053 {
3054 if (!serverBasedSearch)
3055 {
3056 if (!disableIndex && dynamicMenus && !fullSidebar)
3057 {
3058 t << " init_search();\n";
3059 }
3060 }
3061 else
3062 {
3063 t << " if (document.querySelector('.searchresults')) { searchBox.DOMSearchField().focus(); }\n";
3064 }
3065 }
3066 t << "});\n";
3067 t << "</script>\n";
3068 t << "<div id=\"main-nav-mobile\">\n";
3069 if (searchEngine && !fullSidebar)
3070 {
3071 t << "<div class=\"sm sm-dox\"><input id=\"main-menu-state\" type=\"checkbox\"/>\n";
3072 t << "<label class=\"main-menu-btn\" for=\"main-menu-state\">\n";
3073 t << "<span class=\"main-menu-btn-icon\"></span> Toggle main menu visibility</label>\n";
3074 t << "<span id=\"searchBoxPos1\" style=\"position:absolute;right:8px;top:8px;height:36px;\">";
3075 t << "</span>\n";
3076 t << "</div>\n";
3077 }
3078 t << "</div><!-- main-nav-mobile -->\n";
3079 t << "<div id=\"main-nav\">\n";
3080 t << " <ul class=\"sm sm-dox\" id=\"main-menu\">\n";
3081 t << " <li id=\"searchBoxPos2\" style=\"float:right\">\n";
3082 if (searchEngine && !(generateTreeView && fullSidebar))
3083 {
3084 t << getSearchBox(serverBasedSearch,relPath,false);
3085 }
3086 t << " </li>\n";
3087 t << " </ul>\n";
3088 t << "</div><!-- main-nav -->\n";
3089 }
3090 else if (!disableIndex) // && !Config_getBool(HTML_DYNAMIC_MENUS)
3091 {
3092 // find highlighted index item
3093 LayoutNavEntry *hlEntry = root->find(kind,kind==LayoutNavEntry::UserGroup ? file : QCString());
3094 if (!hlEntry && altKind!=LayoutNavEntry::None) { hlEntry=root->find(altKind); kind=altKind; }
3095 if (!hlEntry) // highlighted item not found in the index! -> just show the level 1 index...
3096 {
3097 highlightParent=TRUE;
3098 hlEntry = root->children().front().get();
3099 if (hlEntry==nullptr)
3100 {
3101 return; // argl, empty index!
3102 }
3103 }
3104 if (kind==LayoutNavEntry::UserGroup)
3105 {
3106 LayoutNavEntry *e = hlEntry->children().front().get();
3107 if (e)
3108 {
3109 hlEntry = e;
3110 }
3111 }
3112 t << "<div id=\"main-nav\">\n";
3113 renderQuickLinksAsTabs(t,relPath,hlEntry,kind,highlightParent,hli==HighlightedItem::Search);
3114 if (!extraTabs)
3115 {
3116 t << "</div><!-- main-nav -->\n";
3117 }
3118 }
3119 else if (!generateTreeView)
3120 {
3121 renderQuickLinksAsTree(t,relPath,root);
3122 }
3123 if (generateTreeView && !disableIndex && fullSidebar && !extraTabs)
3124 {
3125 t << "<div id=\"container\"><div id=\"doc-content\">\n";
3126 }
3127}
3128
3130{
3131 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
3132 m_t << "</div><!-- top -->\n";
3133 if (!generateTreeView)
3134 {
3135 m_t << "<div id=\"doc-content\">\n";
3136 }
3137}
3138
3139QCString HtmlGenerator::writeSplitBarAsString(const QCString &name,const QCString &relpath,const QCString &allMembersFile)
3140{
3141 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
3142 QCString result;
3143 // write split bar
3144 if (generateTreeView)
3145 {
3146 QCString fn = name;
3148 if (!Config_getBool(FULL_SIDEBAR))
3149 {
3150 result += QCString(
3151 "<div id=\"side-nav\" class=\"ui-resizable side-nav-resizable\">\n");
3152 }
3153 result+=
3154 " <div id=\"nav-tree\">\n"
3155 " <div id=\"nav-tree-contents\">\n"
3156 " <div id=\"nav-sync\" class=\"sync\"></div>\n"
3157 " </div>\n"
3158 " </div>\n"
3159 " <div id=\"splitbar\" style=\"-moz-user-select:none;\" \n"
3160 " class=\"ui-resizable-handle\">\n"
3161 " </div>\n"
3162 "</div>\n"
3163 "<script type=\"text/javascript\">\n"
3164 "document.addEventListener('DOMContentLoaded',() => { initNavTree('" + fn + "','" + relpath + "','" + allMembersFile + "'); });\n"
3165 "</script>\n";
3166 if (Config_getBool(DISABLE_INDEX) || !Config_getBool(FULL_SIDEBAR))
3167 {
3168 result+="<div id=\"container\">\n<div id=\"doc-content\">\n";
3169 }
3170 }
3171 return result;
3172}
3173
3174void HtmlGenerator::writeSplitBar(const QCString &name,const QCString &allMembersFile)
3175{
3176 m_t << writeSplitBarAsString(name,m_relPath,allMembersFile);
3177}
3178
3180{
3181 m_t << substitute(s,"$relpath^",m_relPath);
3182}
3183
3185{
3186 m_t << "<div class=\"contents\">\n";
3187}
3188
3190{
3191 m_t << "</div><!-- contents -->\n";
3192}
3193
3194void HtmlGenerator::startPageDoc(const QCString &/* pageTitle */)
3195{
3196 m_t << "<div>";
3197}
3198
3200{
3201 m_t << "</div><!-- PageDoc -->\n";
3202}
3203
3204void HtmlGenerator::writeQuickLinks(HighlightedItem hli,const QCString &file,bool extraTabs)
3205{
3206 writeDefaultQuickLinks(m_t,hli,file,m_relPath,extraTabs);
3207}
3208
3209// PHP based search script
3211{
3212 bool disableIndex = Config_getBool(DISABLE_INDEX);
3213 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
3214 bool fullSidebar = Config_getBool(FULL_SIDEBAR);
3215 bool quickLinksAfterSplitbar = !disableIndex && generateTreeView && fullSidebar;
3216 QCString projectName = Config_getString(PROJECT_NAME);
3217 QCString htmlOutput = Config_getString(HTML_OUTPUT);
3218
3219 // OPENSEARCH_PROVIDER {
3220 QCString configFileName = htmlOutput+"/search_config.php";
3221 std::ofstream f = Portable::openOutputStream(configFileName);
3222 if (f.is_open())
3223 {
3224 TextStream t(&f);
3225 t << "<?php\n\n";
3226 t << "$config = array(\n";
3227 t << " 'PROJECT_NAME' => \"" << convertToHtml(projectName) << "\",\n";
3228 t << " 'GENERATE_TREEVIEW' => " << (generateTreeView?"true":"false") << ",\n";
3229 t << " 'DISABLE_INDEX' => " << (disableIndex?"true":"false") << ",\n";
3230 t << " 'FULL_SIDEBAR' => " << (fullSidebar?"true":"false") << ",\n";
3231 t << ");\n\n";
3232 t << "$translator = array(\n";
3233 t << " 'search_results_title' => \"" << theTranslator->trSearchResultsTitle() << "\",\n";
3234 t << " 'search_results' => array(\n";
3235 t << " 0 => \"" << theTranslator->trSearchResults(0) << "\",\n";
3236 t << " 1 => \"" << theTranslator->trSearchResults(1) << "\",\n";
3237 t << " 2 => \"" << substitute(theTranslator->trSearchResults(2), "$", "\\$") << "\",\n";
3238 t << " ),\n";
3239 t << " 'search_matches' => \"" << theTranslator->trSearchMatches() << "\",\n";
3240 t << " 'search' => \"" << theTranslator->trSearch() << "\",\n";
3241 t << " 'logo' => \"" << substitute(substitute(writeLogoAsString(""), "\"","\\\""), "\n","\\n") << "\",\n";
3242 t << ");\n\n";
3243 t << "?>\n";
3244 }
3245 f.close();
3246
3247 ResourceMgr::instance().copyResource("search_functions.php",htmlOutput);
3248 ResourceMgr::instance().copyResource("search_opensearch.php",htmlOutput);
3249 // OPENSEARCH_PROVIDER }
3250
3251 QCString fileName = htmlOutput+"/search.php";
3253 if (f.is_open())
3254 {
3255 TextStream t(&f);
3257
3258 t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
3259 << getDoxygenVersion() << " -->\n";
3260 t << "<script type=\"text/javascript\">\n";
3261 t << "let searchBox = new SearchBox(\"searchBox\", \""
3262 << "search/\",'" << Doxygen::htmlFileExtension << "');\n";
3263 t << "</script>\n";
3264
3265 if (!disableIndex && !quickLinksAfterSplitbar)
3266 {
3268 }
3269 if (generateTreeView)
3270 {
3271 t << "</div><!-- top -->\n";
3272 }
3273 t << writeSplitBarAsString("search.php",QCString(),QCString());
3274 if (quickLinksAfterSplitbar)
3275 {
3277 }
3278 t << "<!-- generated -->\n";
3279
3280 t << "<?php\n";
3281 t << "require_once \"search_functions.php\";\n";
3282 t << "main();\n";
3283 t << "?>\n";
3284
3285 // Write empty navigation path, to make footer connect properly
3286 if (generateTreeView)
3287 {
3288 t << "</div><!-- doc-content -->\n";
3289 t << "</div><!-- container -->\n";
3290 }
3291
3292 writePageFooter(t,"Search","","");
3293 }
3294 f.close();
3295
3296 QCString scriptName = htmlOutput+"/search/search.js";
3297 f = Portable::openOutputStream(scriptName);
3298 if (f.is_open())
3299 {
3300 TextStream t(&f);
3301 t << ResourceMgr::instance().getAsString("extsearch.js");
3302 }
3303 else
3304 {
3305 err("Failed to open file '{}' for writing...\n",scriptName);
3306 }
3307}
3308
3310{
3311 bool disableIndex = Config_getBool(DISABLE_INDEX);
3312 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
3313 bool fullSidebar = Config_getBool(FULL_SIDEBAR);
3314 bool quickLinksAfterSplitbar = !disableIndex && generateTreeView && fullSidebar;
3315 QCString dname = Config_getString(HTML_OUTPUT);
3317 std::ofstream f = Portable::openOutputStream(fileName);
3318 if (f.is_open())
3319 {
3320 TextStream t(&f);
3322
3323 t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
3324 << getDoxygenVersion() << " -->\n";
3325 t << "<script type=\"text/javascript\">\n";
3326 t << "let searchBox = new SearchBox(\"searchBox\", \""
3327 << "search/\",'" << Doxygen::htmlFileExtension << "');\n";
3328 t << "</script>\n";
3329
3330 if (!disableIndex && !quickLinksAfterSplitbar)
3331 {
3333 }
3334 if (generateTreeView)
3335 {
3336 t << "</div><!-- top -->\n";
3337 }
3338 t << writeSplitBarAsString("search.php",QCString(),QCString());
3339 if (quickLinksAfterSplitbar)
3340 {
3342 }
3343
3344 t << "<div class=\"header\">\n";
3345 t << " <div class=\"headertitle\">\n";
3346 t << " <div class=\"title\">" << theTranslator->trSearchResultsTitle() << "</div>\n";
3347 t << " </div>\n";
3348 t << "</div>\n";
3349 t << "<div class=\"contents\">\n";
3350
3351 t << "<div id=\"searchresults\"></div>\n";
3352 t << "</div>\n";
3353
3354 if (generateTreeView)
3355 {
3356 t << "</div><!-- doc-content -->\n";
3357 t << "</div><!-- container -->\n";
3358 }
3359
3360 writePageFooter(t,"Search","","");
3361
3362 }
3363 f.close();
3364
3365 QCString scriptName = dname+"/search/search.js";
3366 f = Portable::openOutputStream(scriptName);
3367 if (f.is_open())
3368 {
3369 TextStream t(&f);
3370 t << "const searchResultsText=["
3371 << "\"" << theTranslator->trSearchResults(0) << "\","
3372 << "\"" << theTranslator->trSearchResults(1) << "\","
3373 << "\"" << theTranslator->trSearchResults(2) << "\"];\n";
3374 t << "const serverUrl=\"" << Config_getString(SEARCHENGINE_URL) << "\";\n";
3375 t << "const tagMap = {\n";
3376 bool first=TRUE;
3377 // add search mappings
3378 const StringVector &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS);
3379 for (const auto &ml : extraSearchMappings)
3380 {
3381 QCString mapLine(ml);
3382 int eqPos = mapLine.find('=');
3383 if (eqPos!=-1) // tag command contains a destination
3384 {
3385 QCString tagName = mapLine.left(eqPos).stripWhiteSpace();
3386 QCString destName = mapLine.right(mapLine.length()-eqPos-1).stripWhiteSpace();
3387 if (!tagName.isEmpty())
3388 {
3389 if (!first) t << ",\n";
3390 t << " \"" << tagName << "\": \"" << destName << "\"";
3391 first=FALSE;
3392 }
3393 }
3394 }
3395 if (!first) t << "\n";
3396 t << "};\n\n";
3397 t << ResourceMgr::instance().getAsString("extsearch.js");
3398 t << "\n";
3399 t << "document.addEventListener('DOMContentLoaded',() => {\n";
3400 t << " const query = trim(getURLParameter('query'));\n";
3401 t << " if (query) {\n";
3402 t << " searchFor(query,0,20);\n";
3403 t << " } else {\n";
3404 t << " const results = document.getElementById('results');\n";
3405 t << " results.innerHtml = '<p>" << theTranslator->trSearchResults(0) << "</p>';\n";
3406 t << " }\n";
3407 t << "});\n";
3408 }
3409 else
3410 {
3411 err("Failed to open file '{}' for writing...\n",scriptName);
3412 }
3413}
3414
3416{
3417 m_t << "<div class=\"typeconstraint\">\n";
3418 m_t << "<dl><dt><b>" << header << "</b></dt><dd>\n";
3419 m_t << "<table border=\"0\" cellspacing=\"2\" cellpadding=\"0\">\n";
3420}
3421
3423{
3424 m_t << "<tr><td valign=\"top\"><em>";
3425}
3426
3428{
3429 m_t << "</em></td>";
3430}
3431
3433{
3434 m_t << "<td>&#160;:</td><td valign=\"top\"><em>";
3435}
3436
3438{
3439 m_t << "</em></td>";
3440}
3441
3443{
3444 m_t << "<td>&#160;";
3445}
3446
3448{
3449 m_t << "</td></tr>\n";
3450}
3451
3453{
3454 m_t << "</table>\n";
3455 m_t << "</dd>\n";
3456 m_t << "</dl>\n";
3457 m_t << "</div>\n";
3458}
3459
3461{
3462 if (!style.isEmpty())
3463 {
3464 m_t << "<br class=\"" << style << "\" />\n";
3465 }
3466 else
3467 {
3468 m_t << "<br />\n";
3469 }
3470}
3471
3473{
3474 m_t << "<div class=\"header\">\n";
3475}
3476
3478{
3479 m_t << " <div class=\"headertitle\">";
3480 startTitle();
3481}
3482
3484{
3485 endTitle();
3486 m_t << "</div>\n";
3487}
3488
3490{
3491 m_t << "</div><!--header-->\n";
3492}
3493
3495{
3496 if (m_emptySection)
3497 {
3498 m_t << "<table class=\"memberdecls\">\n";
3500 }
3501 m_t << "<tr><td colspan=\"2\"><h3>";
3502}
3503
3505{
3506 m_t << "</h3></td></tr>\n";
3507}
3508
3510{
3511 DBG_HTML(m_t << "<!-- startMemberDocSimple -->\n";)
3512 m_t << "<table class=\"fieldtable\">\n";
3513 m_t << "<tr><th colspan=\"" << (isEnum?"2":"3") << "\">";
3514 m_t << (isEnum? theTranslator->trEnumerationValues() :
3515 theTranslator->trCompoundMembers()) << "</th></tr>\n";
3516}
3517
3519{
3520 DBG_HTML(m_t << "<!-- endMemberDocSimple -->\n";)
3521 m_t << "</table>\n";
3522}
3523
3525{
3526 DBG_HTML(m_t << "<!-- startInlineMemberType -->\n";)
3527 m_t << "<tr><td class=\"fieldtype\">\n";
3528}
3529
3531{
3532 DBG_HTML(m_t << "<!-- endInlineMemberType -->\n";)
3533 m_t << "</td>\n";
3534}
3535
3537{
3538 DBG_HTML(m_t << "<!-- startInlineMemberName -->\n";)
3539 m_t << "<td class=\"fieldname\">\n";
3540}
3541
3543{
3544 DBG_HTML(m_t << "<!-- endInlineMemberName -->\n";)
3545 m_t << "</td>\n";
3546}
3547
3549{
3550 DBG_HTML(m_t << "<!-- startInlineMemberDoc -->\n";)
3551 m_t << "<td class=\"fielddoc\">\n";
3552}
3553
3555{
3556 DBG_HTML(m_t << "<!-- endInlineMemberDoc -->\n";)
3557 m_t << "</td></tr>\n";
3558}
3559
3561{
3562 DBG_HTML(m_t << "<!-- startEmbeddedDoc -->\n";)
3563 m_t << "<div class=\"embeddoc\" style=\"margin-left:" << indent << "ch;\">";
3564}
3565
3567{
3568 DBG_HTML(m_t << "<!-- endEmbeddedDoc -->\n";)
3569 m_t << "</div>";
3570}
3571
3573{
3574 DBG_HTML(m_t << "<!-- startLabels -->\n";)
3575 m_t << "<span class=\"mlabels\">";
3576}
3577
3578void HtmlGenerator::writeLabel(const QCString &label,bool /*isLast*/)
3579{
3580 DBG_HTML(m_t << "<!-- writeLabel(" << label << ") -->\n";)
3581
3582 auto convertLabelToClass = [](const std::string &lab) {
3583 QCString input = convertUTF8ToLower(lab);
3584 QCString result;
3585 size_t l=input.length();
3586 result.reserve(l);
3587
3588 // Create valid class selector, see 10.2 here https://www.w3.org/TR/selectors-3/#w3cselgrammar
3589 // ident [-]?{nmstart}{nmchar}*
3590 // nmstart [_a-z]|{nonascii}
3591 // nonascii [^\0-\177]
3592 // nmchar [_a-z0-9-]|{nonascii}
3593
3594 bool nmstart=false;
3595 for (size_t i=0; i<l; i++)
3596 {
3597 char c = input.at(i);
3598 if (c<0 || (c>='a' && c<='z') || c=='_') // nmstart pattern
3599 {
3600 nmstart=true;
3601 result+=c;
3602 }
3603 else if (nmstart && (c<0 || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='_')) // nmchar pattern
3604 {
3605 result+=c;
3606 }
3607 else if (nmstart && (c==' ' || c=='-')) // show whitespace as -
3608 {
3609 result+='-';
3610 }
3611 }
3612 return result;
3613 };
3614
3615 m_t << "<span class=\"mlabel " << convertLabelToClass(label.stripWhiteSpace().str()) << "\">" << label << "</span>";
3616}
3617
3619{
3620 DBG_HTML(m_t << "<!-- endLabels -->\n";)
3621 m_t << "</span>";
3622}
3623
3625 const QCString &id, const QCString &ref,
3626 const QCString &file, const QCString &anchor,
3627 const QCString &title, const QCString &name)
3628{
3629 DBG_HTML(m_t << "<!-- writeInheritedSectionTitle -->\n";)
3630 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
3631 QCString a = anchor;
3632 if (!a.isEmpty()) a.prepend("#");
3633 QCString classLink = QCString("<a class=\"el\" ");
3634 if (!ref.isEmpty())
3635 {
3636 classLink+= externalLinkTarget();
3637 classLink += " href=\"";
3638 classLink+= externalRef(m_relPath,ref,TRUE);
3639 }
3640 else
3641 {
3642 classLink += "href=\"";
3643 classLink+=m_relPath;
3644 }
3645 QCString fn = file;
3647 classLink=classLink+fn+a;
3648 classLink+=QCString("\">")+convertToHtml(name,FALSE)+"</a>";
3649 m_t << "<tr class=\"inherit_header " << id << "\">";
3650 if (dynamicSections)
3651 {
3652 m_t << "<td colspan=\"2\" onclick=\"javascript:dynsection.toggleInherit('" << id << "')\">";
3653 m_t << "<span class=\"dynarrow\"><span class=\"arrowhead closed\"></span></span>";
3654 }
3655 else
3656 {
3657 m_t << "<td colspan=\"2\">";
3658 }
3659 m_t << theTranslator->trInheritedFrom(convertToHtml(title,FALSE),classLink)
3660 << "</td></tr>\n";
3661}
3662
3663void HtmlGenerator::writeSummaryLink(const QCString &file,const QCString &anchor,const QCString &title,bool first)
3664{
3665 if (first)
3666 {
3667 m_t << " <div class=\"summary\">\n";
3668 }
3669 else
3670 {
3671 m_t << " &#124;\n";
3672 }
3673 m_t << "<a href=\"";
3674 if (!file.isEmpty())
3675 {
3676 QCString fn = file;
3678 m_t << m_relPath << fn;
3679 }
3680 else if (!anchor.isEmpty())
3681 {
3682 m_t << "#";
3683 m_t << anchor;
3684 }
3685 m_t << "\">";
3686 m_t << title;
3687 m_t << "</a>";
3688}
3689
3691{
3692 m_t << "<div id=\"page-nav\" class=\"page-nav-panel\">\n";
3693 m_t << "<div id=\"page-nav-resize-handle\"></div>\n";
3694 m_t << "<div id=\"page-nav-tree\">\n";
3695 m_t << "<div id=\"page-nav-contents\">\n";
3696 m_t << "</div><!-- page-nav-contents -->\n";
3697 m_t << "</div><!-- page-nav-tree -->\n";
3698 m_t << "</div><!-- page-nav -->\n";
3699}
3700
3701void HtmlGenerator::endMemberDeclaration(const QCString &anchor,const QCString &inheritId)
3702{
3703}
3704
3706{
3708 return replaceVariables(mgr.getAsString("navtree.css"));
3709}
3710
3712{
3713 m_tocState.level=0;
3714 m_tocState.indent=0;
3715 m_tocState.maxLevel=level;
3716 m_tocState.inLi = BoolVector(level+1,false);
3717 m_t << "<div class=\"toc\">";
3718 m_t << "<h3>" << theTranslator->trRTFTableOfContents() << "</h3>\n";
3719}
3720
3722{
3723 if (m_tocState.level > m_tocState.maxLevel) m_tocState.level = m_tocState.maxLevel;
3724 while (m_tocState.level>0)
3725 {
3726 m_tocState.decIndent(m_t,"</li>");
3727 m_tocState.decIndent(m_t,"</ul>");
3728 m_tocState.level--;
3729 }
3730 m_t << "</div>\n";
3731}
3732
3734{
3735 SectionType type = si->type();
3736 if (type.isSection())
3737 {
3738 //printf(" level=%d title=%s maxLevel=%d\n",level,qPrint(si->title()),maxLevel);
3739 int nextLevel = type.level();
3740 if (nextLevel>m_tocState.level)
3741 {
3742 for (int l=m_tocState.level;l<nextLevel;l++)
3743 {
3744 if (l < m_tocState.maxLevel)
3745 {
3746 m_tocState.incIndent(m_t,"<ul>");
3747 char cs[2] = { static_cast<char>('0'+l+1), 0 };
3748 const char *empty = (l!=nextLevel-1) ? " empty" : "";
3749 m_tocState.incIndent(m_t,"<li class=\"level" + QCString(cs) + empty + "\">");
3750 }
3751 }
3752 }
3753 else if (nextLevel<m_tocState.level)
3754 {
3755 for (int l=m_tocState.level;l>nextLevel;l--)
3756 {
3757 if (l <= m_tocState.maxLevel) m_tocState.decIndent(m_t,"</li>");
3758 m_tocState.inLi[l] = false;
3759 if (l <= m_tocState.maxLevel) m_tocState.decIndent(m_t,"</ul>");
3760 }
3761 }
3762 if (nextLevel <= m_tocState.maxLevel)
3763 {
3764 if (m_tocState.inLi[nextLevel] || m_tocState.level>nextLevel)
3765 {
3766 m_tocState.decIndent(m_t,"</li>");
3767 char cs[2] = { static_cast<char>('0'+nextLevel), 0 };
3768 m_tocState.incIndent(m_t,"<li class=\"level" + QCString(cs) + "\">");
3769 }
3770 QCString label = si->label();
3771 m_tocState.writeIndent(m_t);
3772 m_t << "<a href=\"#"+label+"\">";
3773 }
3774 }
3775}
3776
3778{
3779 SectionType type = si->type();
3780 int nextLevel = type.level();
3781 if (type.isSection() && nextLevel<=m_tocState.maxLevel)
3782 {
3783 m_t << "</a>\n";
3784 m_tocState.inLi[nextLevel]=true;
3785 m_tocState.level = nextLevel;
3786 }
3787}
3788
constexpr auto prefix
Definition anchor.cpp:44
Class representing a built-in class diagram.
Definition diagram.h:31
void writeImage(TextStream &t, const QCString &path, const QCString &relPath, const QCString &file, bool generateMap=true) const
Definition diagram.cpp:1361
The common base class of all entity definitions found in the sources.
Definition definition.h:77
Class representing a directory in the file system.
Definition dir.h:75
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:295
bool exists() const
Definition dir.cpp:257
Class representing the abstract syntax tree of a documentation block.
Definition docnode.h:1472
DocNodeVariant root
Definition docnode.h:1497
Representation of an call graph.
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
Representation of a class inheritance or dependency graph.
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool TBRank=TRUE, bool imageMap=TRUE, int graphId=-1)
Representation of an directory dependency graph.
Definition dotdirdeps.h:26
QCString writeGraph(TextStream &out, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1, bool linkRelations=TRUE)
Represents a graphical class hierarchy.
void writeGraph(TextStream &t, const QCString &path, const QCString &fileName)
Representation of a group collaboration graph.
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
Representation of an include dependency graph.
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
static PageLinkedMap * exampleLinkedMap
Definition doxygen.h:98
static IndexList * indexList
Definition doxygen.h:132
static QCString htmlFileExtension
Definition doxygen.h:122
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
bool exists() const
Definition fileinfo.cpp:30
std::string fileName() const
Definition fileinfo.cpp:118
bool isReadable() const
Definition fileinfo.cpp:44
bool isFile() const
Definition fileinfo.cpp:63
std::string absFilePath() const
Definition fileinfo.cpp:101
Generator for HTML code fragments.
Definition htmlgen.h:26
void codify(const QCString &text) override
Definition htmlgen.cpp:777
bool m_stripCodeComments
Definition htmlgen.h:77
void startSpecialComment() override
Definition htmlgen.cpp:867
void endCodeLine() override
Definition htmlgen.cpp:1052
void startFontClass(const QCString &s) override
Definition htmlgen.cpp:1068
void writeCodeAnchor(const QCString &anchor) override
Definition htmlgen.cpp:1080
QCString fileName()
Definition htmlgen.h:33
size_t m_stripIndentAmount
Definition htmlgen.h:91
QCString m_relPath
Definition htmlgen.h:74
void writeCodeLink(CodeSymbolType type, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name, const QCString &tooltip) override
Definition htmlgen.cpp:916
void startFold(int, const QCString &, const QCString &) override
Definition htmlgen.cpp:1103
void writeLineNumber(const QCString &, const QCString &, const QCString &, int, bool) override
Definition htmlgen.cpp:884
void startCodeLine(int) override
Definition htmlgen.cpp:1040
void endFold() override
Definition htmlgen.cpp:1139
void _writeCodeLink(const QCString &className, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name, const QCString &tooltip)
Definition htmlgen.cpp:932
void setRelativePath(const QCString &path)
Definition htmlgen.cpp:772
void setStripIndentAmount(size_t amount) override
Definition htmlgen.cpp:879
void endSpecialComment() override
Definition htmlgen.cpp:873
HtmlCodeGenerator(TextStream *t, const QCString &relPath)
Definition htmlgen.cpp:766
void writeTooltip(const QCString &id, const DocLinkInfo &docInfo, const QCString &decl, const QCString &desc, const SourceLinkInfo &defInfo, const SourceLinkInfo &declInfo) override
Definition htmlgen.cpp:960
void endFontClass() override
Definition htmlgen.cpp:1074
void startCodeFragment(const QCString &style) override
Definition htmlgen.cpp:1086
TextStream * m_t
Definition htmlgen.h:72
LineInfo m_lastLineInfo
Definition htmlgen.h:90
void endCodeFragment(const QCString &) override
Definition htmlgen.cpp:1091
void stripCodeComments(bool b) override
Definition htmlgen.cpp:862
OutputType type() const override
Definition htmlgen.h:35
Concrete visitor implementation for HTML output.
void startClassDiagram() override
Definition htmlgen.cpp:2096
void writeLogo() override
Definition htmlgen.cpp:1658
void endFile() override
Definition htmlgen.cpp:1674
void endParameterExtra(bool last, bool emptyList, bool closeBracket) override
Definition htmlgen.cpp:2452
static void init()
Definition htmlgen.cpp:1210
void startTocEntry(const SectionInfo *si) override
Definition htmlgen.cpp:3733
void startInlineMemberName() override
Definition htmlgen.cpp:3536
void endDescTableInit() override
Definition htmlgen.cpp:2724
void startTitle()
Definition htmlgen.h:340
void startTextLink(const QCString &file, const QCString &anchor) override
Definition htmlgen.cpp:1888
void startInlineMemberType() override
Definition htmlgen.cpp:3524
void endDescTable() override
Definition htmlgen.cpp:2694
void startParameterDefVal(const char *sep) override
Definition htmlgen.cpp:2476
void startIndexKey() override
Definition htmlgen.cpp:2329
void lineBreak(const QCString &style) override
Definition htmlgen.cpp:3460
void startParameterName(bool) override
Definition htmlgen.cpp:2435
void startMemberItem(const QCString &anchor, MemberItemType, const QCString &inheritId) override
Definition htmlgen.cpp:2149
static void writeSearchPage()
Definition htmlgen.cpp:3210
void startInclDepGraph() override
Definition htmlgen.cpp:2559
void insertMemberAlignLeft(MemberItemType, bool) override
Definition htmlgen.cpp:2215
void writeQuickLinks(HighlightedItem hli, const QCString &file, bool extraTabs) override
Definition htmlgen.cpp:3204
void startMemberSubtitle() override
Definition htmlgen.cpp:2302
HtmlGenerator & operator=(const HtmlGenerator &)
Definition htmlgen.cpp:1176
void writeFooter(const QCString &navPath) override
Definition htmlgen.cpp:1669
int m_sectionCount
Definition htmlgen.h:348
void startMemberDocName(bool) override
Definition htmlgen.cpp:2388
void endParameterType() override
Definition htmlgen.cpp:2429
void startLabels() override
Definition htmlgen.cpp:3572
void startCallGraph() override
Definition htmlgen.cpp:2595
TocState m_tocState
Definition htmlgen.h:364
void endMemberList() override
Definition htmlgen.cpp:2140
static QCString getNavTreeCss()
Definition htmlgen.cpp:3705
void startParagraph(const QCString &classDef) override
Definition htmlgen.cpp:1781
void endIndexList() override
Definition htmlgen.cpp:2324
void writeSearchInfo() override
Definition htmlgen.cpp:1630
void startContents() override
Definition htmlgen.cpp:3184
void startMemberDoc(const QCString &clName, const QCString &memName, const QCString &anchor, const QCString &title, int memCount, int memTotal, bool showInline) override
Definition htmlgen.cpp:2359
void startDescTableRow() override
Definition htmlgen.cpp:2699
void startDoxyAnchor(const QCString &fName, const QCString &manName, const QCString &anchor, const QCString &name, const QCString &args) override
Definition htmlgen.cpp:1766
void startDirDepGraph() override
Definition htmlgen.cpp:2613
void startCompoundTemplateParams() override
Definition htmlgen.cpp:2199
void startConstraintParam() override
Definition htmlgen.cpp:3422
void startEmbeddedDoc(int) override
Definition htmlgen.cpp:3560
void endGroupHeader(int) override
Definition htmlgen.cpp:1926
QCString m_lastFile
Definition htmlgen.h:346
void writeNavigationPath(const QCString &s) override
Definition htmlgen.cpp:3179
void writeObjectLink(const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name) override
Definition htmlgen.cpp:1864
void startMemberDescription(const QCString &anchor, const QCString &inheritId, bool typ) override
Definition htmlgen.cpp:2227
void writeChar(char c) override
Definition htmlgen.cpp:2015
void endConstraintList() override
Definition htmlgen.cpp:3452
void endParameterList() override
Definition htmlgen.cpp:2488
void startMemberGroupHeader(const QCString &, bool) override
Definition htmlgen.cpp:2636
void startDotGraph() override
Definition htmlgen.cpp:2525
void startFile(const QCString &name, bool isSource, const QCString &manName, const QCString &title, int id, int hierarchyLevel) override
Definition htmlgen.cpp:1561
void endIndent() override
Definition htmlgen.cpp:2671
void endParameterName() override
Definition htmlgen.cpp:2441
void endPageDoc() override
Definition htmlgen.cpp:3199
void startMemberDocList() override
Definition htmlgen.cpp:2349
static QCString writeLogoAsString(const QCString &path)
Definition htmlgen.cpp:1636
void endDescTableRow() override
Definition htmlgen.cpp:2704
void startParameterType(bool first, const QCString &key) override
Definition htmlgen.cpp:2412
void startDescTableInit() override
Definition htmlgen.cpp:2719
void startLocalToc(int level) override
Definition htmlgen.cpp:3711
void startMemberList() override
Definition htmlgen.cpp:2135
void endQuickIndices() override
Definition htmlgen.cpp:3129
void startHeaderSection() override
Definition htmlgen.cpp:3472
void startDescTableTitle() override
Definition htmlgen.cpp:2709
void endDirDepGraph(DotDirDeps &g) override
Definition htmlgen.cpp:2618
void startIndexList() override
Definition htmlgen.cpp:2319
void endParameterDefVal() override
Definition htmlgen.cpp:2483
void endMemberGroup(bool) override
Definition htmlgen.cpp:2660
void endInlineHeader() override
Definition htmlgen.cpp:3504
void endEmbeddedDoc() override
Definition htmlgen.cpp:3566
static void writeFooterFile(TextStream &t)
Definition htmlgen.cpp:1553
void endMemberDescription() override
Definition htmlgen.cpp:2248
void startGroupCollaboration() override
Definition htmlgen.cpp:2577
void endClassDiagram(const ClassDiagram &, const QCString &, const QCString &) override
Definition htmlgen.cpp:2101
void startConstraintList(const QCString &) override
Definition htmlgen.cpp:3415
void startDescTable(const QCString &title, const bool hasInits) override
Definition htmlgen.cpp:2689
void endConstraintDocs() override
Definition htmlgen.cpp:3447
void writeNonBreakableSpace(int) override
Definition htmlgen.cpp:2681
void endMemberGroupHeader(bool) override
Definition htmlgen.cpp:2641
void writePageOutline() override
Definition htmlgen.cpp:3690
void startInlineMemberDoc() override
Definition htmlgen.cpp:3548
void exceptionEntry(const QCString &, bool) override
Definition htmlgen.cpp:2495
static void writeTabData()
Additional initialization after indices have been created.
Definition htmlgen.cpp:1370
void endExamples() override
Definition htmlgen.cpp:2746
void endIndexKey() override
Definition htmlgen.cpp:2334
void writeString(const QCString &text) override
Definition htmlgen.cpp:1794
void endMemberDocName() override
Definition htmlgen.cpp:2398
void endContents() override
Definition htmlgen.cpp:3189
void endInlineMemberType() override
Definition htmlgen.cpp:3530
void startMemberGroupDocs() override
Definition htmlgen.cpp:2646
void startMemberDocSimple(bool) override
Definition htmlgen.cpp:3509
void startIndexItem(const QCString &ref, const QCString &file) override
Definition htmlgen.cpp:1809
OutputType type() const override
Definition htmlgen.h:121
void endHeaderSection() override
Definition htmlgen.cpp:3489
void startIndent() override
Definition htmlgen.cpp:2664
void writeStyleInfo(int part) override
Definition htmlgen.cpp:1689
void addIndexItem(const QCString &, const QCString &) override
Definition htmlgen.cpp:2677
void docify_(const QCString &text, bool inHtmlComment)
Definition htmlgen.cpp:1978
void endMemberGroupDocs() override
Definition htmlgen.cpp:2651
void cleanup() override
Definition htmlgen.cpp:1362
void endDotGraph(DotClassGraph &g) override
Definition htmlgen.cpp:2530
void endMemberHeader() override
Definition htmlgen.cpp:2296
void endTextLink() override
Definition htmlgen.cpp:1900
void writeLabel(const QCString &l, bool isLast) override
Definition htmlgen.cpp:3578
void startMemberSections() override
Definition htmlgen.cpp:2254
static void writeSearchData(const QCString &dir)
Definition htmlgen.cpp:1379
void endMemberSections() override
Definition htmlgen.cpp:2262
void endMemberDocList() override
Definition htmlgen.cpp:2354
void endCompoundTemplateParams() override
Definition htmlgen.cpp:2204
static void writeExternalSearchPage()
Definition htmlgen.cpp:3309
void endDescTableData() override
Definition htmlgen.cpp:2734
void startDescTableData() override
Definition htmlgen.cpp:2729
void writeStartAnnoItem(const QCString &type, const QCString &file, const QCString &path, const QCString &name) override
Definition htmlgen.cpp:1852
static void writePageFooter(TextStream &t, const QCString &, const QCString &, const QCString &)
Definition htmlgen.cpp:1663
void endParagraph() override
Definition htmlgen.cpp:1789
void insertMemberAlign(bool) override
Definition htmlgen.cpp:2209
static void writeStyleSheetFile(TextStream &t)
Definition htmlgen.cpp:1541
void endDoxyAnchor(const QCString &fName, const QCString &anchor) override
Definition htmlgen.cpp:1773
void startMemberTemplateParams() override
Definition htmlgen.cpp:2182
void endLabels() override
Definition htmlgen.cpp:3618
void startPageDoc(const QCString &pageTitle) override
Definition htmlgen.cpp:3194
void endMemberDeclaration(const QCString &anchor, const QCString &inheritId) override
Definition htmlgen.cpp:3701
HtmlCodeGenerator * m_codeGen
Definition htmlgen.h:351
void startIndexValue(bool) override
Definition htmlgen.cpp:2339
void endGroupCollaboration(DotGroupCollaboration &g) override
Definition htmlgen.cpp:2582
QCString m_relPath
Definition htmlgen.h:347
static void writeSearchInfoStatic(TextStream &t, const QCString &relPath)
Definition htmlgen.cpp:1600
void endLocalToc() override
Definition htmlgen.cpp:3721
std::unique_ptr< OutputCodeList > m_codeList
Definition htmlgen.h:350
static void writeHeaderFile(TextStream &t, const QCString &cssname)
Definition htmlgen.cpp:1547
void startConstraintType() override
Definition htmlgen.cpp:3432
void endConstraintParam() override
Definition htmlgen.cpp:3427
static QCString writeSplitBarAsString(const QCString &name, const QCString &relpath, const QCString &allMembersFile)
Definition htmlgen.cpp:3139
void startTitleHead(const QCString &) override
Definition htmlgen.cpp:3477
void endIndexValue(const QCString &, bool) override
Definition htmlgen.cpp:2344
void addCodeGen(OutputCodeList &list) override
Definition htmlgen.cpp:1196
void startConstraintDocs() override
Definition htmlgen.cpp:3442
void endMemberTemplateParams(const QCString &anchor, const QCString &inheritId) override
Definition htmlgen.cpp:2186
void endPlainFile() override
Definition htmlgen.h:334
void startIndexListItem() override
Definition htmlgen.cpp:1799
void endProjectNumber() override
Definition htmlgen.cpp:1684
void writeDoc(const IDocNodeAST *node, const Definition *, const MemberDef *, int id, int sectionLevel) override
Definition htmlgen.cpp:2751
void writeSummaryLink(const QCString &file, const QCString &anchor, const QCString &title, bool first) override
Definition htmlgen.cpp:3663
void endMemberDocPrefixItem() override
Definition htmlgen.cpp:2382
void endDescTableTitle() override
Definition htmlgen.cpp:2714
void addLabel(const QCString &, const QCString &) override
Definition htmlgen.cpp:1777
void startGroupHeader(const QCString &, int) override
Definition htmlgen.cpp:1905
void endInclDepGraph(DotInclDepGraph &g) override
Definition htmlgen.cpp:2564
void startParameterExtra() override
Definition htmlgen.cpp:2447
void startProjectNumber() override
Definition htmlgen.cpp:1679
void writeGraphicalHierarchy(DotGfxHierarchyTable &g) override
Definition htmlgen.cpp:2631
void startExamples() override
Definition htmlgen.cpp:2739
void docify(const QCString &text) override
Definition htmlgen.cpp:1973
bool m_emptySection
Definition htmlgen.h:349
void endInlineMemberDoc() override
Definition htmlgen.cpp:3554
void writeSplitBar(const QCString &name, const QCString &allMembersFile) override
Definition htmlgen.cpp:3174
void endCallGraph(DotCallGraph &g) override
Definition htmlgen.cpp:2600
void endConstraintType() override
Definition htmlgen.cpp:3437
void endMemberSubtitle() override
Definition htmlgen.cpp:2313
void endTitle()
Definition htmlgen.h:341
void startMemberDocPrefixItem() override
Definition htmlgen.cpp:2376
void startSection(const QCString &, const QCString &, SectionType) override
Definition htmlgen.cpp:1942
void endTocEntry(const SectionInfo *si) override
Definition htmlgen.cpp:3777
void endMemberItem(MemberItemType) override
Definition htmlgen.cpp:2173
void startMemberGroup() override
Definition htmlgen.cpp:2656
void endMemberDoc(bool) override
Definition htmlgen.cpp:2514
void endIndexItem(const QCString &ref, const QCString &file) override
Definition htmlgen.cpp:1839
void startMemberHeader(const QCString &, int) override
Definition htmlgen.cpp:2271
void endTitleHead(const QCString &, const QCString &) override
Definition htmlgen.cpp:3483
void endSection(const QCString &, SectionType) override
Definition htmlgen.cpp:1958
void startInlineHeader() override
Definition htmlgen.cpp:3494
void endInlineMemberName() override
Definition htmlgen.cpp:3542
void endMemberDocSimple(bool) override
Definition htmlgen.cpp:3518
void writeInheritedSectionTitle(const QCString &id, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &title, const QCString &name) override
Definition htmlgen.cpp:3624
void endIndexListItem() override
Definition htmlgen.cpp:1804
void startParameterList(bool) override
Definition htmlgen.cpp:2404
QCString m_lastTitle
Definition htmlgen.h:345
void startPlainFile(const QCString &name) override
Definition htmlgen.h:333
opaque representation of the abstract syntax tree (AST)
Definition docparser.h:50
static Index & instance()
Definition index.cpp:108
static LayoutDocManager & instance()
Returns a reference to this singleton.
Definition layout.cpp:1437
LayoutNavEntry * rootNavEntry() const
returns the (invisible) root of the navigation tree.
Definition layout.cpp:1448
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
Class representing a list of different code generators.
Definition outputlist.h:165
void add(OutputCodeIntfPtr &&p)
Definition outputlist.h:195
Abstract interface for output generators.
Definition outputgen.h:127
QCString dir() const
Definition outputgen.cpp:52
QCString m_dir
Definition outputgen.h:117
TextStream m_t
Definition outputgen.h:116
QCString fileName() const
Definition outputgen.cpp:57
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString & prepend(const char *s)
Definition qcstring.h:422
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool startsWith(const char *s) const
Definition qcstring.h:507
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
QCString lower() const
Definition qcstring.h:249
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
const std::string & str() const
Definition qcstring.h:552
QCString right(size_t len) const
Definition qcstring.h:234
void reserve(size_t size)
Reserve space for size bytes without changing the string contents.
Definition qcstring.h:185
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
QCString left(size_t len) const
Definition qcstring.h:229
int contains(char c, bool cs=TRUE) const
Definition qcstring.cpp:148
Singleton for managing resources compiled into an executable.
Definition resourcemgr.h:37
static ResourceMgr & instance()
Returns the one and only instance of this class.
bool copyResource(const QCString &name, const QCString &targetDir) const
Copies a registered resource to a given target directory.
QCString getAsString(const QCString &name) const
Gets the resource data as a C string.
class that provide information about a section.
Definition section.h:58
QCString label() const
Definition section.h:69
SectionType type() const
Definition section.h:71
static constexpr int Section
Definition section.h:33
static constexpr int Subsection
Definition section.h:34
static constexpr int Subsubsection
Definition section.h:35
static constexpr int Page
Definition section.h:31
static constexpr int Paragraph
Definition section.h:36
static constexpr int Subsubparagraph
Definition section.h:38
static constexpr int Subparagraph
Definition section.h:37
Text streaming class that buffers data.
Definition textstream.h:36
bool empty() const
Returns true iff the buffer is empty.
Definition textstream.h:240
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:216
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2362
#define Config_getInt(name)
Definition config.h:34
#define Config_getList(name)
Definition config.h:38
#define Config_getEnumAsString(name)
Definition config.h:36
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
#define Config_getEnum(name)
Definition config.h:35
std::vector< std::string > StringVector
Definition containers.h:33
std::unordered_map< std::string, std::string > StringUnorderedMap
Definition containers.h:28
std::vector< bool > BoolVector
Definition containers.h:36
QCString dateToString(DateTimeType includeTime)
Returns the current date, when includeTime is set also the time is provided.
Definition datetime.cpp:62
QCString yearToString()
Returns the current year as a string.
Definition datetime.cpp:75
static constexpr auto hex
static bool g_build_date
Definition htmlgen.cpp:69
#define DBG_HTML(x)
Definition htmlgen.cpp:61
static QCString replaceVariables(const QCString &input)
Definition htmlgen.cpp:713
static void fillColorStyleMap(const QCString &definitions, StringUnorderedMap &map)
Definition htmlgen.cpp:678
static QCString g_header
Definition htmlgen.cpp:63
static void startSectionContent(TextStream &t, int sectionCount)
Definition htmlgen.cpp:2072
static QCString g_header_file
Definition htmlgen.cpp:64
static void endQuickIndexList(TextStream &t)
Definition htmlgen.cpp:2784
static QCString g_mathjax_code
Definition htmlgen.cpp:67
static void writeServerSearchBox(TextStream &t, const QCString &relPath, bool highlightSearch)
Definition htmlgen.cpp:98
static void startQuickIndexList(TextStream &t, bool topLevel=TRUE)
Definition htmlgen.cpp:2764
static void startSectionSummary(TextStream &t, int sectionCount)
Definition htmlgen.cpp:2050
static void startQuickIndexItem(TextStream &t, const QCString &l, bool hl, bool, const QCString &relPath)
Definition htmlgen.cpp:2797
static void renderQuickLinksAsTabs(TextStream &t, const QCString &relPath, LayoutNavEntry *hlEntry, LayoutNavEntry::Kind kind, bool highlightParent, bool highlightSearch)
Definition htmlgen.cpp:2893
static QCString g_footer
Definition htmlgen.cpp:66
static const SelectionMarkerInfo htmlMarkerInfo
Definition htmlgen.cpp:72
static QCString getConvertLatexMacro()
Convert a set of LaTeX commands \‍(re)newcommand to a form readable by MathJax LaTeX syntax:
Definition htmlgen.cpp:149
static void writeDefaultQuickLinks(TextStream &t, HighlightedItem hli, const QCString &file, const QCString &relPath, bool extraTabs)
Definition htmlgen.cpp:2973
static QCString g_footer_file
Definition htmlgen.cpp:65
static void endSectionContent(TextStream &t)
Definition htmlgen.cpp:2088
static bool hasDateReplacement(const QCString &str)
Definition htmlgen.cpp:1201
static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch)
Definition htmlgen.cpp:300
static QCString g_latex_macro
Definition htmlgen.cpp:68
static void fillColorStyleMaps()
Definition htmlgen.cpp:699
static void endQuickIndexItem(TextStream &t, const QCString &l)
Definition htmlgen.cpp:2811
static StringUnorderedMap g_lightMap
Definition htmlgen.cpp:675
static void startSectionHeader(TextStream &t, const QCString &relPath, int sectionCount)
Definition htmlgen.cpp:2025
static void writeDefaultStyleSheet(TextStream &t)
Definition htmlgen.cpp:1424
static void renderQuickLinksAsTree(TextStream &t, const QCString &relPath, LayoutNavEntry *root)
Definition htmlgen.cpp:2864
static bool quickLinkVisible(LayoutNavEntry::Kind kind)
Definition htmlgen.cpp:2818
static std::mutex g_indexLock
Definition htmlgen.cpp:1559
static StringUnorderedMap g_darkMap
Definition htmlgen.cpp:676
static void endSectionHeader(TextStream &t)
Definition htmlgen.cpp:2044
static void writeClientSearchBox(TextStream &t, const QCString &relPath)
Definition htmlgen.cpp:76
static void endSectionSummary(TextStream &t)
Definition htmlgen.cpp:2062
static QCString substituteHtmlKeywords(const QCString &file, const QCString &str, const QCString &title, const QCString &relPath, const QCString &navPath=QCString(), bool isSource=false)
Definition htmlgen.cpp:314
HighlightedItem
Definition index.h:59
@ AnnotatedExceptions
Definition index.h:76
@ InterfaceVisible
Definition index.h:89
@ InterfaceHierarchy
Definition index.h:66
@ AnnotatedInterfaces
Definition index.h:74
@ NamespaceMembers
Definition index.h:78
@ AnnotatedClasses
Definition index.h:73
@ AnnotatedStructs
Definition index.h:75
@ ExceptionVisible
Definition index.h:91
@ NamespaceVisible
Definition index.h:92
@ ExceptionHierarchy
Definition index.h:67
Translator * theTranslator
Definition language.cpp:71
#define warn(file, line, fmt,...)
Definition message.h:97
#define err(fmt,...)
Definition message.h:127
#define term(fmt,...)
Definition message.h:137
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:648
OutputCodeDefer< HtmlCodeGenerator > HtmlCodeGeneratorDefer
Definition outputlist.h:102
Portable versions of functions that are platform dependent.
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:571
#define qsnprintf
Definition qcstring.h:49
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
Web server based search engine.
Some helper functions for std::string.
bool literal_at(const char *data, const char(&str)[N])
returns TRUE iff data points to a substring that matches string literal str
Definition stringutil.h:98
Base class for the layout of a navigation item at the top of the HTML pages.
Definition layout.h:156
const LayoutNavEntryList & children() const
Definition layout.h:219
LayoutNavEntry * parent() const
Definition layout.h:212
LayoutNavEntry * find(LayoutNavEntry::Kind k, const QCString &file=QCString()) const
Definition layout.cpp:133
Kind
Definition layout.h:193
constexpr const char * codeSymbolType2Str(CodeSymbolType type) noexcept
Definition types.h:515
CodeSymbolType
Definition types.h:481
std::string convertUTF8ToLower(const std::string &input)
Converts the input string into a lower case version, also taking into account non-ASCII characters th...
Definition utf8.cpp:187
const char * writeUTF8Char(TextStream &t, const char *s)
Writes the UTF8 character pointed to by s to stream t and returns a pointer to the next character.
Definition utf8.cpp:197
Various UTF8 related helper functions.
QCString externalRef(const QCString &relPath, const QCString &ref, bool href)
Definition util.cpp:5776
size_t updateColumnCount(const char *s, size_t col)
Definition util.cpp:6903
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:3967
void checkBlocks(const QCString &s, const QCString fileName, const SelectionMarkerInfo &markerInfo)
Definition util.cpp:6545
QCString correctURL(const QCString &url, const QCString &relPath)
Corrects URL url according to the relative path relPath.
Definition util.cpp:5948
QCString stripPath(const QCString &s)
Definition util.cpp:4952
QCString removeEmptyLines(const QCString &s)
Definition util.cpp:6609
QCString selectBlocks(const QCString &s, const SelectionBlockList &blockList, const SelectionMarkerInfo &markerInfo)
remove disabled blocks and all block markers from s and return the result as a string
Definition util.cpp:6432
QCString substituteKeywords(const QCString &file, const QCString &s, const KeywordSubstitutionList &keywords)
Definition util.cpp:3058
QCString relativePathToRoot(const QCString &name)
Definition util.cpp:3583
void clearSubDirs(const Dir &d)
Definition util.cpp:3671
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition util.cpp:1494
QCString filterTitle(const QCString &title)
Definition util.cpp:5633
void createSubDirs(const Dir &d)
Definition util.cpp:3644
QCString getProjectId()
Definition util.cpp:6834
QCString externalLinkTarget(const bool parent)
Definition util.cpp:5728
QCString replaceColorMarkers(const QCString &str)
Replaces any markers of the form ##AA in input string str by new markers of the form #AABBCC,...
Definition util.cpp:5829
QCString convertToId(const QCString &s)
Definition util.cpp:3876
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:4925
QCString createHtmlUrl(const QCString &relPath, const QCString &ref, bool href, bool isLocalFile, const QCString &targetFileName, const QCString &anchor)
Definition util.cpp:5739
A bunch of utility functions.
QCString fixSpaces(const QCString &s)
Definition util.h:522