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