Doxygen
Loading...
Searching...
No Matches
ftvhelp.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * ftvhelp.cpp,v 1.0 2000/09/06 16:09:00
3 *
4 * Copyright (C) 1997-2015 by Dimitri van Heesch.
5 *
6 * Permission to use, copy, modify, and distribute this software and its
7 * documentation under the terms of the GNU General Public License is hereby
8 * granted. No representations are made about the suitability of this software
9 * for any purpose. It is provided "as is" without express or implied warranty.
10 * See the GNU General Public License for more details.
11 *
12 * Documents produced by Doxygen are derivative works derived from the
13 * input used in their production; they are not affected by this license.
14 *
15 * Original version contributed by Kenney Wong <kwong@ea.com>
16 * Modified by Dimitri van Heesch
17 *
18 * Folder Tree View for offline help on browsers that do not support HTML Help.
19 */
20
21// own header
22#include "ftvhelp.h"
23
24// standard includes
25#include <memory>
26#include <variant>
27#include <vector>
28
29// other includes
30#include "classdef.h"
31#include "config.h"
32#include "docparser.h"
33#include "doxygen.h"
34#include "filedef.h"
35#include "htmldocvisitor.h"
36#include "language.h"
37#include "layout.h"
38#include "message.h"
39#include "outputlist.h"
40#include "pagedef.h"
41#include "portable.h"
42#include "resourcemgr.h"
43#include "threadpool.h"
44#include "util.h"
45
46static int folderId=1;
47
48
49struct FTVNode;
50using FTVNodePtr = std::shared_ptr<FTVNode>;
51using FTVNodeWeakPtr = std::weak_ptr<FTVNode>;
52using FTVNodes = std::vector<FTVNodePtr>;
53
54struct FTVNode
55{
56 FTVNode(bool dir,const DString &r,const DString &f,const DString &a,
57 const DString &n,bool sepIndex,bool navIndex,const Definition *df,
58 const DString &nameAsHtml_)
59 : isLast(true), isDir(dir), ref(r), file(f), anchor(a), name(n), nameAsHtml(nameAsHtml_),
60 separateIndex(sepIndex), addToNavIndex(navIndex), def(df) {}
61 int computeTreeDepth(int level) const;
62 int numNodesAtLevel(int level,int maxLevel) const;
63 bool isLast;
64 bool isDir;
70 int index = 0;
76};
77
78int FTVNode::computeTreeDepth(int level) const
79{
80 int maxDepth=level;
81 for (const auto &n : children)
82 {
83 if (!n->children.empty())
84 {
85 int d = n->computeTreeDepth(level+1);
86 if (d>maxDepth) maxDepth=d;
87 }
88 }
89 return maxDepth;
90}
91
92int FTVNode::numNodesAtLevel(int level,int maxLevel) const
93{
94 int num=0;
95 if (level<maxLevel)
96 {
97 num++; // this node
98 for (const auto &n : children)
99 {
100 num+=n->numNodesAtLevel(level+1,maxLevel);
101 }
102 }
103 return num;
104}
105
106//----------------------------------------------------------------------------
107
109{
110 Private(bool TLI) : topLevelIndex(TLI) { indentNodes.resize(1); }
111 std::vector<FTVNodes> indentNodes;
112 int indent = 0;
114
115 void generateTree(TextStream &t,const FTVNodes &nl,int level,int maxLevel,int &index);
116 void generateLink(TextStream &t,const FTVNodePtr &n);
117};
118
119/*! Constructs an ftv help object.
120 * The object has to be \link initialize() initialized\endlink before it can
121 * be used.
122 */
123FTVHelp::FTVHelp(bool TLI) : p(std::make_unique<Private>(TLI)) {}
124FTVHelp::~FTVHelp() = default;
125
126/*! This will create a folder tree view table of contents file (tree.js).
127 * \sa finalize()
128 */
130{
131}
132
133/*! Finalizes the FTV help. This will finish and close the
134 * contents file (index.js).
135 * \sa initialize()
136 */
138{
140}
141
142/*! Increase the level of the contents hierarchy.
143 * This will start a new sublist in contents file.
144 * \sa decContentsDepth()
145 */
147{
148 //printf("%p: incContentsDepth() indent=%d\n",this,p->indent);
149 p->indent++;
150 p->indentNodes.resize(p->indent+1);
151}
152
153/*! Decrease the level of the contents hierarchy.
154 * This will end the current sublist.
155 * \sa incContentsDepth()
156 */
158{
159 //printf("%p: decContentsDepth() indent=%d\n",this,p->indent);
160 ASSERT(p->indent>0);
161 if (p->indent>0)
162 {
163 p->indent--;
164 auto &nl = p->indentNodes[p->indent];
165 if (!nl.empty())
166 {
167 auto &parent = nl.back();
168 auto &children = p->indentNodes[p->indent+1];
169 for (const auto &child : children)
170 {
171 parent->children.push_back(child);
172 }
173 children.clear();
174 }
175 }
176}
177
178/*! Add a list item to the contents file.
179 * \param isDir true if the item is a directory, false if it is a text
180 * \param name the name of the item.
181 * \param nameAsHtml the name of the item in HTML format.
182 * \param ref the URL of to the item.
183 * \param file the file containing the definition of the item
184 * \param anchor the anchor within the file.
185 * \param separateIndex put the entries in a separate index file
186 * \param addToNavIndex add this entry to the quick navigation index
187 * \param def Definition corresponding to this entry
188 */
190 const DString &name,
191 const DString &ref,
192 const DString &file,
193 const DString &anchor,
194 bool separateIndex,
195 bool addToNavIndex,
196 const Definition *def,
197 const DString &nameAsHtml
198 )
199{
200 //printf("%p: p->indent=%d addContentsItem(isDir=%d,name=%s,ref=%s,file=%s,anchor=%s,nameAsHtml=%s)\n",(void*)this,p->indent,isDir,qPrint(name),qPrint(ref),qPrint(file),qPrint(anchor),qPrint(nameAsHtml));
201 auto &nl = p->indentNodes[p->indent];
202 if (!nl.empty())
203 {
204 nl.back()->isLast=false;
205 }
206 auto newNode = std::make_shared<FTVNode>(isDir,ref,file,anchor,name,separateIndex,addToNavIndex,def,nameAsHtml);
207 nl.push_back(newNode);
208 newNode->index = static_cast<int>(nl.size()-1);
209 if (p->indent>0)
210 {
211 auto &pnl = p->indentNodes[p->indent-1];
212 if (!pnl.empty())
213 {
214 newNode->parent = pnl.back();
215 }
216 }
217}
218
219static DString node2URL(const FTVNodePtr &n,bool overruleFile=false,bool srcLink=false)
220{
221 DString url = n->file;
222 if (!url.empty() && url.at(0)=='!') // relative URL
223 {
224 // remove leading !
225 url = url.mid(1);
226 }
227 else if (!url.empty() && url.at(0)=='^') // absolute URL
228 {
229 // skip, keep ^ in the output
230 }
231 else // local file (with optional anchor)
232 {
233 if (overruleFile && n->def && n->def->definitionType()==Definition::TypeFile)
234 {
235 const FileDef *fd = toFileDef(n->def);
236 if (srcLink)
237 {
238 url = fd->getSourceFileBase();
239 }
240 else
241 {
242 url = fd->getOutputFileBase();
243 }
244 }
246 if (!n->anchor.empty()) url+="#"+n->anchor;
247 }
248 return url;
249}
250
251static DString generateIndentLabel(const FTVNodePtr &n,int level)
252{
253 DString result;
254 auto parent = n->parent.lock();
255 if (parent)
256 {
257 result=generateIndentLabel(parent,level+1);
258 }
259 result+=DString().setNum(n->index)+"_";
260 return result;
261}
262
263static void generateIndent(TextStream &t, const FTVNodePtr &n,bool opened)
264{
265 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
266 int indent=0;
267 auto parent = n->parent.lock();
268 while (parent) { indent++; parent=parent->parent.lock(); }
269 if (n->isDir && dynamicSections)
270 {
271 const char *ARROW_DOWN = "<span class=\"arrowhead opened\"></span>";
272 const char *ARROW_RIGHT = "<span class=\"arrowhead closed\"></span>";
273 DString dir = opened ? ARROW_DOWN : ARROW_RIGHT;
274 for(int i=0;i<indent;i++) t << "<span class=\"spacer\">&#160;</span>";
275 t << "<span id=\"arr_" << generateIndentLabel(n,0) << "\" class=\"arrow\">" << dir
276 << "</span>";
277 }
278 else
279 {
280 for(int i=0;i<=indent;i++) t << "<span class=\"spacer\">&#160;</span>";
281 }
282}
283
285{
286 //printf("FTVHelp::generateLink(ref=%s,file=%s,anchor=%s\n",
287 // qPrint(n->ref),qPrint(n->file),qPrint(n->anchor));
288 bool setTarget = false;
289 bool nameAsHtml = !n->nameAsHtml.empty();
290 DString text = nameAsHtml ? n->nameAsHtml : convertToHtml(n->name);
291 if (n->file.empty()) // no link
292 {
293 t << "<b>" << text << "</b>";
294 }
295 else // link into other frame
296 {
297 if (!n->ref.empty()) // link to entity imported via tag file
298 {
299 t << "<a class=\"elRef\" ";
300 DString result = externalLinkTarget();
301 if (result != "") setTarget = true;
302 t << result;
303 }
304 else // local link
305 {
306 t << "<a class=\"el\" ";
307 }
308 t << "href=\"";
309 t << externalRef("",n->ref);
310 t << node2URL(n);
311 if (!setTarget)
312 {
313 if (topLevelIndex)
314 t << "\" target=\"basefrm\">";
315 else
316 t << "\" target=\"_self\">";
317 }
318 else
319 {
320 t << "\">";
321 }
322 t << text;
323 t << "</a>";
324 if (!n->ref.empty())
325 {
326 t << "&#160;[external]";
327 }
328 }
329}
330
331static void generateBriefDoc(TextStream &t,const Definition *def)
332{
333 DString brief = def->briefDescription(true);
334 //printf("*** %p: generateBriefDoc(%s)='%s'\n",def,qPrint(def->name()),qPrint(brief));
335 if (!brief.empty())
336 {
337 auto parser { createDocParser() };
338 auto ast { validatingParseDoc(*parser.get(),
339 def->briefFile(),
340 def->briefLine(),
341 def,
342 nullptr,
343 brief,
344 DocOptions()
345 .setSingleLine(true)
346 .setLinkFromIndex(true))
347 };
348 const DocNodeAST *astImpl = dynamic_cast<const DocNodeAST*>(ast.get());
349 if (astImpl)
350 {
352 OutputCodeList htmlList;
353 htmlList.add<HtmlCodeGenerator>(&t,relPath);
354 HtmlDocVisitor visitor(t,htmlList,def);
355 std::visit(visitor,astImpl->root);
356 }
357 }
358}
359
360static char compoundIcon(const ClassDef *cd)
361{
362 char icon='C';
363 if (cd->getLanguage() == SrcLangExt::Slice)
364 {
366 {
367 icon='I';
368 }
369 else if (cd->compoundType()==ClassDef::Struct)
370 {
371 icon='S';
372 }
373 else if (cd->compoundType()==ClassDef::Exception)
374 {
375 icon='E';
376 }
377 }
378 return icon;
379}
380
381void FTVHelp::Private::generateTree(TextStream &t, const FTVNodes &nl,int level,int maxLevel,int &index)
382{
383 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
384 for (const auto &n : nl)
385 {
386 t << "<tr id=\"row_" << generateIndentLabel(n,0) << "\"";
387 t << " class=\"";
388 if ((index&1)==0) // even row
389 t << "even";
390 else
391 t << "odd";
392 if (level>=maxLevel && dynamicSections) // item invisible by default
393 t << " hidden";
394 else // item visible by default
395 index++;
396 t << "\"";
397 t << "><td class=\"entry\">";
398 bool nodeOpened = level+1<maxLevel;
399 generateIndent(t,n,nodeOpened);
400 if (n->isDir)
401 {
402 if (n->def && n->def->definitionType()==Definition::TypeGroup)
403 {
404 // no icon
405 }
406 else if (n->def && n->def->definitionType()==Definition::TypePage)
407 {
408 // no icon
409 }
410 else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
411 {
412 if ((n->def->getLanguage() == SrcLangExt::Slice) || (n->def->getLanguage() == SrcLangExt::Fortran))
413 {
414 t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
415 }
416 else if ((n->def->getLanguage() == SrcLangExt::Java) || (n->def->getLanguage() == SrcLangExt::VHDL))
417 {
418 t << "<span class=\"icona\"><span class=\"icon\">P</span></span>";
419 }
420 else
421 {
422 t << "<span class=\"icona\"><span class=\"icon\">N</span></span>";
423 }
424 }
425 else if (n->def && n->def->definitionType()==Definition::TypeModule)
426 {
427 t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
428 }
429 else if (n->def && n->def->definitionType()==Definition::TypeClass)
430 {
431 char icon=compoundIcon(toClassDef(n->def));
432 t << "<span class=\"icona\"><span class=\"icon\">" << icon << "</span></span>";
433 }
434 else if (dynamicSections)
435 {
436 t << "<span id=\"img_" << generateIndentLabel(n,0) << "\" class=\"iconfolder\">"
437 << "<div class=\"folder-icon"
438 << (nodeOpened ? " open" : "")
439 << "\"></div></span>";
440 }
441 generateLink(t,n);
442 t << "</td><td class=\"desc\">";
443 if (n->def)
444 {
445 generateBriefDoc(t,n->def);
446 }
447 t << "</td></tr>\n";
448 folderId++;
449 generateTree(t,n->children,level+1,maxLevel,index);
450 }
451 else // leaf node
452 {
453 const FileDef *srcRef=nullptr;
454 if (n->def && n->def->definitionType()==Definition::TypeFile &&
455 (toFileDef(n->def))->generateSourceFile())
456 {
457 srcRef = toFileDef(n->def);
458 }
459 if (srcRef)
460 {
461 DString fn=srcRef->getSourceFileBase();
463 t << "<a href=\"" << fn << "\">";
464 }
465 if (n->def && n->def->definitionType()==Definition::TypeGroup)
466 {
467 // no icon
468 }
469 else if (n->def && n->def->definitionType()==Definition::TypePage)
470 {
471 // no icon
472 }
473 else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
474 {
475 if ((n->def->getLanguage() == SrcLangExt::Slice) || (n->def->getLanguage() == SrcLangExt::Fortran))
476 {
477 t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
478 }
479 else if ((n->def->getLanguage() == SrcLangExt::Java) || (n->def->getLanguage() == SrcLangExt::VHDL))
480 {
481 t << "<span class=\"icona\"><span class=\"icon\">P</span></span>";
482 }
483 else
484 {
485 t << "<span class=\"icona\"><span class=\"icon\">N</span></span>";
486 }
487 }
488 else if (n->def && n->def->definitionType()==Definition::TypeModule)
489 {
490 t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
491 }
492 else if (n->def && n->def->definitionType()==Definition::TypeClass)
493 {
494 char icon=compoundIcon(toClassDef(n->def));
495 t << "<span class=\"icona\"><span class=\"icon\">" << icon << "</span></span>";
496 }
497 else if (n->def && n->def->definitionType()==Definition::TypeConcept)
498 {
499 t << "<span class=\"icona\"><span class=\"icon\">R</span></span>";
500 }
501 else if (n->def && n->def->definitionType()==Definition::TypeDir)
502 {
503 t << "<span class=\"iconfolder\"><div class=\"folder-icon\"></div></span>";
504 }
505 else
506 {
507 t << "<span class=\"icondoc\"><div class=\"doc-icon\"></div></span>";
508 }
509 if (srcRef)
510 {
511 t << "</a>";
512 }
513 generateLink(t,n);
514 t << "</td><td class=\"desc\">";
515 if (n->def)
516 {
517 generateBriefDoc(t,n->def);
518 }
519 t << "</td></tr>\n";
520 }
521 }
522}
523
524//-----------------------------------------------------------
525
527{
528 NavIndexEntry(const DString &u,const DString &p) : url(u), path(p) {}
531};
532
533class NavIndexEntryList final : public std::vector<NavIndexEntry>
534{
535};
536
537static DString pathToNode(const FTVNodePtr &leaf,const FTVNodePtr &n)
538{
539 DString result;
540 auto parent = n->parent.lock();
541 if (parent)
542 {
543 result+=pathToNode(leaf,parent);
544 }
545 result+=DString().setNum(n->index);
546 if (leaf!=n) result+=",";
547 return result;
548}
549
550static bool dupOfParent(const FTVNodePtr &n)
551{
552 auto parent = n->parent.lock();
553 if (!parent) return false;
554 if (n->file==parent->file) return true;
555 return false;
556}
557
558static void generateJSLink(TextStream &t,const FTVNodePtr &n)
559{
560 bool nameAsHtml = !n->nameAsHtml.empty();
561 DString link = nameAsHtml ? convertToJSString(n->nameAsHtml,true) : convertToJSString(n->name);
562 if (Config_getBool(HIDE_SCOPE_NAMES)) link=stripScope(link);
563 link = substitute(link,"\n","");
564 if (n->file.empty()) // no link
565 {
566 t << "\"" << link << "\", null, ";
567 }
568 else // link into other page
569 {
570 t << "\"" << link << "\", \"";
571 t << externalRef("",n->ref);
572 t << node2URL(n);
573 t << "\", ";
574 }
575}
576
577static DString convertFileId2Var(const DString &fileId)
578{
579 DString varId = fileId;
580 size_t i=varId.rfind('/');
581 if (i!=DString::npos) varId = varId.mid(i+1);
582 if (isdigit(varId[0])) varId.prepend("_");
583
584 return substitute(varId,"-","_");
585}
586
587
589{
590 JSTreeFile(const DString &fi,const FTVNodePtr &n) : fileId(fi), node(n) {}
593};
594
595using JSTreeFiles = std::vector<JSTreeFile>;
596
597static void collectJSTreeFiles(const FTVNodes &nl,JSTreeFiles &files)
598{
599 DString htmlOutput = Config_getString(HTML_OUTPUT);
600 for (const auto &n : nl)
601 {
602 if (n->separateIndex) // add new file if there are children
603 {
604 if (!n->children.empty())
605 {
606 DString fileId = n->file;
607 files.emplace_back(fileId,n);
608 collectJSTreeFiles(n->children,files);
609 }
610 }
611 else // traverse without adding a new file
612 {
613 collectJSTreeFiles(n->children,files);
614 }
615 }
616}
617
618static std::mutex g_navIndexMutex;
619
621 const FTVNodes &nl,int level,bool &first)
622{
623 DString htmlOutput = Config_getString(HTML_OUTPUT);
624 DString indentStr;
625 indentStr.fill(' ',level*2);
626
627 bool found=false;
628 for (const auto &n : nl)
629 {
630 // terminate previous entry
631 if (!first) t << ",\n";
632 first=false;
633
634 // start entry
635 if (!found)
636 {
637 t << "[\n";
638 }
639 found=true;
640
641 if (n->addToNavIndex) // add entry to the navigation index
642 {
643 std::lock_guard lock(g_navIndexMutex);
644 if (n->def && n->def->definitionType()==Definition::TypeFile)
645 {
646 const FileDef *fd = toFileDef(n->def);
647 bool src = false;
648 bool doc = fd->visibleInIndex(src);
649 if (doc)
650 {
651 navIndex.emplace_back(node2URL(n,true,false),pathToNode(n,n));
652 }
653 if (src)
654 {
655 navIndex.emplace_back(node2URL(n,true,true),pathToNode(n,n));
656 }
657 }
658 else
659 {
660 navIndex.emplace_back(node2URL(n),pathToNode(n,n));
661 }
662 }
663
664 if (n->separateIndex) // store items in a separate file for dynamic loading
665 {
666 t << indentStr << " [ ";
667 generateJSLink(t,n);
668 if (!n->children.empty()) // write children to separate file for dynamic loading
669 {
670 DString fileId = n->file;
671 if (!n->anchor.empty())
672 {
673 fileId+="_"+n->anchor;
674 }
675 if (dupOfParent(n))
676 {
677 fileId+="_dup";
678 }
679 t << "\"" << fileId << "\" ]";
680 }
681 else // no children
682 {
683 t << "null ]";
684 }
685 }
686 else // show items in this file
687 {
688 bool firstChild=true;
689 t << indentStr << " [ ";
690 generateJSLink(t,n);
691 bool emptySection = !generateJSTree(navIndex,t,n->children,level+1,firstChild);
692 if (emptySection)
693 t << "null ]";
694 else
695 t << "\n" << indentStr << " ] ]";
696 }
697 }
698 return found;
699}
700
701static void generateJSTreeFiles(NavIndexEntryList &navIndex,TextStream &t,const FTVNodes &nodeList)
702{
703 DString htmlOutput = Config_getString(HTML_OUTPUT);
704
705 auto getVarName = [](const FTVNodePtr n)
706 {
707 DString fileId = n->file;
708 if (!n->anchor.empty()) fileId+="_"+n->anchor;
709 if (dupOfParent(n)) fileId+="_dup";
710 return fileId;
711 };
712
713 auto generateJSFile = [&](const JSTreeFile &tf)
714 {
715 DString fileId = getVarName(tf.node);
716 DString fileName = htmlOutput+"/"+fileId+".js";
717 std::ofstream ff = Portable::openOutputStream(fileName);
718 if (ff.is_open())
719 {
720 bool firstChild = true;
721 TextStream tt(&ff);
722 tt << "var " << convertFileId2Var(fileId) << " =\n";
723 generateJSTree(navIndex,tt,tf.node->children,1,firstChild);
724 tt << "\n];";
725 }
726 };
727
728 JSTreeFiles jsTreeFiles;
729 collectJSTreeFiles(nodeList,jsTreeFiles);
730
731 std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
732 if (numThreads>1) // multi threaded version
733 {
734 ThreadPool threadPool(numThreads);
735 std::vector< std::future<void> > results;
736 for (const auto &tf : jsTreeFiles)
737 {
738 results.emplace_back(threadPool.queue([&](){ generateJSFile(tf); }));
739 }
740 // wait for the results
741 for (auto &f : results) f.get();
742 }
743 else // single threaded version
744 {
745 for (const auto &tf : jsTreeFiles)
746 {
747 generateJSFile(tf);
748 }
749 }
750}
751
752static void generateJSNavTree(const FTVNodes &nodeList)
753{
754 DString htmlOutput = Config_getString(HTML_OUTPUT);
755 std::ofstream f = Portable::openOutputStream(htmlOutput+"/navtreedata.js");
756 NavIndexEntryList navIndex;
757 if (f.is_open())
758 {
759 TextStream t(&f);
760 //TextStream tidx(&fidx);
761 //tidx << "var NAVTREEINDEX =\n";
762 //tidx << "{\n";
764 t << "var NAVTREE =\n";
765 t << "[\n";
766 t << " [ ";
767 DString projName = Config_getString(PROJECT_NAME);
768 if (projName.empty())
769 {
770 if (mainPageHasTitle()) // Use title of main page as root
771 {
772 t << "\"" << convertToJSString(Doxygen::mainPage->title()) << "\", ";
773 }
774 else // Use default section title as root
775 {
776 LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::MainPage);
777 t << "\"" << convertToJSString(lne->title()) << "\", ";
778 }
779 }
780 else // use PROJECT_NAME as root tree element
781 {
782 t << "\"" << convertToJSString(projName) << "\", ";
783 }
784 t << "\"index" << Doxygen::htmlFileExtension << "\", ";
785
786 // add special entry for index page
787 navIndex.emplace_back("index"+Doxygen::htmlFileExtension,"");
788 // related page index is written as a child of index.html, so add this as well
789 navIndex.emplace_back("pages"+Doxygen::htmlFileExtension,"");
790
791 bool first=true;
792 generateJSTree(navIndex,t,nodeList,1,first);
793 generateJSTreeFiles(navIndex,t,nodeList);
794
795 if (first)
796 t << "]\n";
797 else
798 t << "\n ] ]\n";
799 t << "];\n\n";
800
801 // write the navigation index (and sub-indices)
802 std::stable_sort(navIndex.begin(),navIndex.end(),[](const auto &n1,const auto &n2)
803 { return !n1.url.empty() && (n2.url.empty() || (n1.url<n2.url)); });
804
805 int subIndex=0;
806 int elemCount=0;
807 const int maxElemCount=250;
808 std::ofstream tsidx = Portable::openOutputStream(htmlOutput+"/navtreeindex0.js");
809 if (tsidx.is_open())
810 {
811 t << "var NAVTREEINDEX =\n";
812 t << "[\n";
813 tsidx << "var NAVTREEINDEX" << subIndex << " =\n";
814 tsidx << "{\n";
815 first=true;
816 auto it = navIndex.begin();
817 while (it!=navIndex.end())
818 {
819 const NavIndexEntry &e = *it;
820 if (elemCount==0)
821 {
822 if (!first)
823 {
824 t << ",\n";
825 }
826 else
827 {
828 first=false;
829 }
830 t << "\"" << e.url << "\"";
831 }
832 tsidx << "\"" << e.url << "\":[" << e.path << "]";
833 ++it;
834 if (it!=navIndex.end() && elemCount<maxElemCount-1) tsidx << ","; // not last entry
835 tsidx << "\n";
836
837 elemCount++;
838 if (it!=navIndex.end() && elemCount>=maxElemCount) // switch to new sub-index
839 {
840 tsidx << "};\n";
841 elemCount=0;
842 tsidx.close();
843 subIndex++;
844 DString fileName = htmlOutput+"/navtreeindex"+DString().setNum(subIndex)+".js";
845 tsidx = Portable::openOutputStream(fileName);
846 if (!tsidx.is_open()) break;
847 tsidx << "var NAVTREEINDEX" << subIndex << " =\n";
848 tsidx << "{\n";
849 }
850 }
851 tsidx << "};\n";
852 t << "\n];\n";
853 }
854 t << "\nconst SYNCONMSG = '" << theTranslator->trPanelSynchronisationTooltip(false) << "';";
855 t << "\nconst SYNCOFFMSG = '" << theTranslator->trPanelSynchronisationTooltip(true) << "';";
856 t << "\nconst LISTOFALLMEMBERS = '" << theTranslator->trListOfAllMembers() << "';";
857 }
858
859 auto &mgr = ResourceMgr::instance();
860 {
861 std::ofstream fn = Portable::openOutputStream(htmlOutput+"/navtree.js");
862 if (fn.is_open())
863 {
864 TextStream t(&fn);
865 t << substitute(
866 substitute(mgr.getAsString("navtree.js"),
867 "$TREEVIEW_WIDTH", DString().setNum(Config_getInt(TREEVIEW_WIDTH))),
868 "$PROJECTID",getProjectId());
869 }
870 }
871}
872
873//-----------------------------------------------------------
874
875// new style scripts
877{
878 DString htmlOutput = Config_getString(HTML_OUTPUT);
879
880 // generate navtree.js & navtreeindex.js
881 generateJSNavTree(p->indentNodes[0]);
882}
883
884// write tree inside page
886{
887 bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
888 int preferredNumEntries = Config_getInt(HTML_INDEX_NUM_ENTRIES);
889 t << "<div class=\"directory\">\n";
890 int d=1, depth=1;
891 for (const auto &n : p->indentNodes[0])
892 {
893 if (!n->children.empty())
894 {
895 d = n->computeTreeDepth(2);
896 if (d>depth) depth=d;
897 }
898 }
899 int preferredDepth = depth;
900 // write level selector
901 if (depth>1)
902 {
903 if (dynamicSections)
904 {
905 t << "<div class=\"levels\">[";
907 t << " ";
908 for (int i=1;i<=depth;i++)
909 {
910 t << "<span class=\"dyn-level-" << i << "\">" << i << "</span>";
911 }
912 t << "]</div>";
913 }
914
915 if (preferredNumEntries>0)
916 {
917 preferredDepth=1;
918 for (int i=1;i<=depth;i++)
919 {
920 int num=0;
921 for (const auto &n : p->indentNodes[0])
922 {
923 num+=n->numNodesAtLevel(0,i);
924 }
925 if (num<=preferredNumEntries)
926 {
927 preferredDepth=i;
928 }
929 else
930 {
931 break;
932 }
933 }
934 }
935 }
936 //printf("preferred depth=%d\n",preferredDepth);
937
938 if (!p->indentNodes[0].empty())
939 {
940 t << "<table class=\"directory\">\n";
941 int index=0;
942 p->generateTree(t,p->indentNodes[0],0,preferredDepth,index);
943 t << "</table>\n";
944 }
945
946 t << "</div><!-- directory -->\n";
947}
948
949// write old style index.html and tree.html
A abstract class representing of a compound symbol.
Definition classdef.h:100
@ Interface
Definition classdef.h:108
@ Exception
Definition classdef.h:111
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e. class/struct/union/...
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
DString & setNum(short n)
Definition dstring.h:552
size_t rfind(char c, size_t pos=npos) const
Definition dstring.h:244
DString fill(char c, size_t len)
Fills a string with a predefined character.
Definition dstring.h:278
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
char & at(size_t i)
Returns a reference to the character at index i.
Definition dstring.h:686
DString & prepend(const char *s)
Definition dstring.h:515
The common base class of all entity definitions found in the sources.
Definition definition.h:77
virtual DString briefDescription(bool abbreviate=false) const =0
virtual DString briefFile() const =0
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual int briefLine() const =0
virtual DString getSourceFileBase() const =0
virtual DString getOutputFileBase() const =0
Class representing the abstract syntax tree of a documentation block.
Definition docnode.h:1471
DocNodeVariant root
Definition docnode.h:1496
static std::unique_ptr< PageDef > mainPage
Definition doxygen.h:93
static DString htmlFileExtension
Definition doxygen.h:115
std::unique_ptr< Private > p
Definition ftvhelp.h:69
void generateTreeView()
Definition ftvhelp.cpp:950
void decContentsDepth()
Definition ftvhelp.cpp:157
void finalize()
Definition ftvhelp.cpp:137
void initialize()
Definition ftvhelp.cpp:129
FTVHelp(bool LTI)
Definition ftvhelp.cpp:123
void incContentsDepth()
Definition ftvhelp.cpp:146
void addContentsItem(bool isDir, const DString &name, const DString &ref, const DString &file, const DString &anchor, bool separateIndex, bool addToNavIndex, const Definition *def, const DString &nameAsHtml=DString())
Definition ftvhelp.cpp:189
void generateTreeViewScripts()
Definition ftvhelp.cpp:876
void generateTreeViewInline(TextStream &t)
Definition ftvhelp.cpp:885
A model of a file symbol.
Definition filedef.h:97
virtual bool visibleInIndex(bool &genSourceFile) const =0
Returns true if this file is visible in the index.
Generator for HTML code fragments.
Definition htmlgen.h:23
Concrete visitor implementation for HTML output.
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
Definition ftvhelp.cpp:534
Class representing a list of different code generators.
Definition outputlist.h:162
void add(OutputCodeIntfPtr &&p)
Definition outputlist.h:192
static ResourceMgr & instance()
Returns the one and only instance of this class.
Text streaming class that buffers data.
Definition textstream.h:36
Class managing a pool of worker threads.
Definition threadpool.h:48
auto queue(F &&f, Args &&... args) -> std::future< decltype(f(args...))>
Queue the callable function f for the threads to execute.
Definition threadpool.h:77
virtual DString trDetailLevel()=0
virtual DString trPanelSynchronisationTooltip(bool enable)=0
virtual DString trListOfAllMembers()=0
ClassDef * toClassDef(Definition *d)
#define Config_getInt(name)
Definition config.h:34
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
constexpr DocNodeVariant * parent(DocNodeVariant *n)
returns the parent node of a given node n or nullptr if the node has no parent.
Definition docnode.h:1335
IDocParserPtr createDocParser()
factory function to create a parser
Definition docparser.cpp:59
IDocNodeASTPtr validatingParseDoc(IDocParser &parserIntf, const DString &fileName, int startLine, const Definition *ctx, const MemberDef *md, const DString &input, const DocOptions &options)
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:485
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1973
static DString node2URL(const FTVNodePtr &n, bool overruleFile=false, bool srcLink=false)
Definition ftvhelp.cpp:219
static DString pathToNode(const FTVNodePtr &leaf, const FTVNodePtr &n)
Definition ftvhelp.cpp:537
static bool dupOfParent(const FTVNodePtr &n)
Definition ftvhelp.cpp:550
static bool generateJSTree(NavIndexEntryList &navIndex, TextStream &t, const FTVNodes &nl, int level, bool &first)
Definition ftvhelp.cpp:620
static int folderId
Definition ftvhelp.cpp:46
static void generateJSLink(TextStream &t, const FTVNodePtr &n)
Definition ftvhelp.cpp:558
static DString convertFileId2Var(const DString &fileId)
Definition ftvhelp.cpp:577
static void generateBriefDoc(TextStream &t, const Definition *def)
Definition ftvhelp.cpp:331
static void collectJSTreeFiles(const FTVNodes &nl, JSTreeFiles &files)
Definition ftvhelp.cpp:597
static char compoundIcon(const ClassDef *cd)
Definition ftvhelp.cpp:360
static std::mutex g_navIndexMutex
Definition ftvhelp.cpp:618
std::vector< FTVNodePtr > FTVNodes
Definition ftvhelp.cpp:52
std::weak_ptr< FTVNode > FTVNodeWeakPtr
Definition ftvhelp.cpp:51
static void generateIndent(TextStream &t, const FTVNodePtr &n, bool opened)
Definition ftvhelp.cpp:263
static DString generateIndentLabel(const FTVNodePtr &n, int level)
Definition ftvhelp.cpp:251
std::shared_ptr< FTVNode > FTVNodePtr
Definition ftvhelp.cpp:50
static void generateJSTreeFiles(NavIndexEntryList &navIndex, TextStream &t, const FTVNodes &nodeList)
Definition ftvhelp.cpp:701
std::vector< JSTreeFile > JSTreeFiles
Definition ftvhelp.cpp:595
static void generateJSNavTree(const FTVNodes &nodeList)
Definition ftvhelp.cpp:752
constexpr auto JAVASCRIPT_LICENSE_TEXT
Definition ftvhelp.h:72
Translator * theTranslator
Definition language.cpp:76
#define ASSERT(x)
Definition message.h:142
std::ofstream openOutputStream(const DString &name, bool append=false)
Definition portable.cpp:681
Definition dstring.h:913
Portable versions of functions that are platform dependent.
Helper class to pass options when calling OutputList::generateDoc().
Definition docoptions.h:24
void generateTree(TextStream &t, const FTVNodes &nl, int level, int maxLevel, int &index)
Definition ftvhelp.cpp:381
void generateLink(TextStream &t, const FTVNodePtr &n)
Definition ftvhelp.cpp:284
std::vector< FTVNodes > indentNodes
Definition ftvhelp.cpp:111
Private(bool TLI)
Definition ftvhelp.cpp:110
DString name
Definition ftvhelp.cpp:68
bool separateIndex
Definition ftvhelp.cpp:73
bool isLast
Definition ftvhelp.cpp:63
DString nameAsHtml
Definition ftvhelp.cpp:69
const Definition * def
Definition ftvhelp.cpp:75
bool addToNavIndex
Definition ftvhelp.cpp:74
FTVNodeWeakPtr parent
Definition ftvhelp.cpp:72
FTVNodes children
Definition ftvhelp.cpp:71
int numNodesAtLevel(int level, int maxLevel) const
Definition ftvhelp.cpp:92
FTVNode(bool dir, const DString &r, const DString &f, const DString &a, const DString &n, bool sepIndex, bool navIndex, const Definition *df, const DString &nameAsHtml_)
Definition ftvhelp.cpp:56
DString file
Definition ftvhelp.cpp:66
int computeTreeDepth(int level) const
Definition ftvhelp.cpp:78
bool isDir
Definition ftvhelp.cpp:64
int index
Definition ftvhelp.cpp:70
DString ref
Definition ftvhelp.cpp:65
DString anchor
Definition ftvhelp.cpp:67
JSTreeFile(const DString &fi, const FTVNodePtr &n)
Definition ftvhelp.cpp:590
DString fileId
Definition ftvhelp.cpp:591
FTVNodePtr node
Definition ftvhelp.cpp:592
Base class for the layout of a navigation item at the top of the HTML pages.
Definition layout.h:155
LayoutNavEntry * find(LayoutNavEntry::Kind k, const DString &file=DString()) const
Definition layout.cpp:135
DString title() const
Definition layout.h:215
Definition ftvhelp.cpp:527
DString path
Definition ftvhelp.cpp:530
DString url
Definition ftvhelp.cpp:529
NavIndexEntry(const DString &u, const DString &p)
Definition ftvhelp.cpp:528
bool mainPageHasTitle()
Definition util.cpp:4959
DString getProjectId()
Definition util.cpp:5270
DString externalLinkTarget(const bool parent)
Definition util.cpp:4491
DString convertToJSString(const DString &s, bool keepEntities, bool singleQuotes)
Definition util.cpp:3351
DString stripScope(const DString &name)
Definition util.cpp:3109
DString convertToHtml(const DString &s, bool keepEntities)
Definition util.cpp:3291
void addHtmlExtensionIfMissing(DString &fName)
Definition util.cpp:3931
DString relativePathToRoot(const DString &name)
Definition util.cpp:2912
DString externalRef(const DString &relPath, const DString &ref)
Definition util.cpp:4538
A bunch of utility functions.