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