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