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