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