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