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