Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / ftvhelp.cpp
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 <qlist.h>
24 #include <qdict.h>
25 #include <qfileinfo.h>
26
27 #include "ftvhelp.h"
28 #include "config.h"
29 #include "message.h"
30 #include "doxygen.h"
31 #include "language.h"
32 #include "htmlgen.h"
33 #include "layout.h"
34 #include "pagedef.h"
35 #include "docparser.h"
36 #include "htmldocvisitor.h"
37 #include "filedef.h"
38 #include "classdef.h"
39 #include "util.h"
40 #include "resourcemgr.h"
41
42 #define MAX_INDENT 1024
43
44 static int folderId=1;
45
46 struct FTVNode
47 {
48   FTVNode(bool dir,const char *r,const char *f,const char *a,
49           const char *n,bool sepIndex,bool navIndex,Definition *df)
50     : isLast(TRUE), isDir(dir),ref(r),file(f),anchor(a),name(n), index(0),
51       parent(0), separateIndex(sepIndex), addToNavIndex(navIndex),
52       def(df) { children.setAutoDelete(TRUE); }
53   int computeTreeDepth(int level) const;
54   int numNodesAtLevel(int level,int maxLevel) const;
55   bool isLast;
56   bool isDir;
57   QCString ref;
58   QCString file;
59   QCString anchor;
60   QCString name;
61   int index;
62   QList<FTVNode> children;
63   FTVNode *parent;
64   bool separateIndex;
65   bool addToNavIndex;
66   Definition *def;
67 };
68
69 int FTVNode::computeTreeDepth(int level) const
70 {
71   int maxDepth=level;
72   QListIterator<FTVNode> li(children);
73   FTVNode *n;
74   for (;(n=li.current());++li)
75   {
76     if (n->children.count()>0)
77     {
78       int d = n->computeTreeDepth(level+1);
79       if (d>maxDepth) maxDepth=d;
80     }
81   }
82   return maxDepth;
83 }
84
85 int FTVNode::numNodesAtLevel(int level,int maxLevel) const
86 {
87   int num=0;
88   if (level<maxLevel)
89   {
90     num++; // this node
91     QListIterator<FTVNode> li(children);
92     FTVNode *n;
93     for (;(n=li.current());++li)
94     {
95       num+=n->numNodesAtLevel(level+1,maxLevel);
96     }
97   }
98   return num;
99 }
100
101 //----------------------------------------------------------------------------
102
103 /*! Constructs an ftv help object.
104  *  The object has to be \link initialize() initialized\endlink before it can
105  *  be used.
106  */
107 FTVHelp::FTVHelp(bool TLI)
108 {
109   /* initial depth */
110   m_indentNodes = new QList<FTVNode>[MAX_INDENT];
111   m_indentNodes[0].setAutoDelete(TRUE);
112   m_indent=0;
113   m_topLevelIndex = TLI;
114 }
115
116 /*! Destroys the ftv help object. */
117 FTVHelp::~FTVHelp()
118 {
119   delete[] m_indentNodes;
120 }
121
122 /*! This will create a folder tree view table of contents file (tree.js).
123  *  \sa finalize()
124  */
125 void FTVHelp::initialize()
126 {
127 }
128
129 /*! Finalizes the FTV help. This will finish and close the
130  *  contents file (index.js).
131  *  \sa initialize()
132  */
133 void FTVHelp::finalize()
134 {
135   generateTreeView();
136 }
137
138 /*! Increase the level of the contents hierarchy.
139  *  This will start a new sublist in contents file.
140  *  \sa decContentsDepth()
141  */
142 void FTVHelp::incContentsDepth()
143 {
144   //printf("incContentsDepth() indent=%d\n",m_indent);
145   m_indent++;
146   ASSERT(m_indent<MAX_INDENT);
147 }
148
149 /*! Decrease the level of the contents hierarchy.
150  *  This will end the current sublist.
151  *  \sa incContentsDepth()
152  */
153 void FTVHelp::decContentsDepth()
154 {
155   //printf("decContentsDepth() indent=%d\n",m_indent);
156   ASSERT(m_indent>0);
157   if (m_indent>0)
158   {
159     m_indent--;
160     QList<FTVNode> *nl = &m_indentNodes[m_indent];
161     FTVNode *parent = nl->getLast();
162     if (parent)
163     {
164       QList<FTVNode> *children = &m_indentNodes[m_indent+1];
165       while (!children->isEmpty())
166       {
167         parent->children.append(children->take(0));
168       }
169     }
170   }
171 }
172
173 /*! Add a list item to the contents file.
174  *  \param isDir TRUE if the item is a directory, FALSE if it is a text
175  *  \param name the name of the item.
176  *  \param ref  the URL of to the item.
177  *  \param file the file containing the definition of the item
178  *  \param anchor the anchor within the file.
179  *  \param separateIndex put the entries in a separate index file
180  *  \param addToNavIndex add this entry to the quick navigation index
181  *  \param def Definition corresponding to this entry
182  */
183 void FTVHelp::addContentsItem(bool isDir,
184                               const char *name,
185                               const char *ref,
186                               const char *file,
187                               const char *anchor,
188                               bool separateIndex,
189                               bool addToNavIndex,
190                               Definition *def
191                               )
192 {
193   //printf("%p: m_indent=%d addContentsItem(%s,%s,%s,%s)\n",this,m_indent,name,ref,file,anchor);
194   QList<FTVNode> *nl = &m_indentNodes[m_indent];
195   FTVNode *newNode = new FTVNode(isDir,ref,file,anchor,name,separateIndex,addToNavIndex,def);
196   if (!nl->isEmpty())
197   {
198     nl->getLast()->isLast=FALSE;
199   }
200   nl->append(newNode);
201   newNode->index = nl->count()-1;
202   if (m_indent>0)
203   {
204     QList<FTVNode> *pnl = &m_indentNodes[m_indent-1];
205     newNode->parent = pnl->getLast();
206   }
207
208 }
209
210 static QCString node2URL(FTVNode *n,bool overruleFile=FALSE,bool srcLink=FALSE)
211 {
212   QCString url = n->file;
213   if (!url.isEmpty() && url.at(0)=='!')  // relative URL
214   {
215     // remove leading !
216     url = url.mid(1);
217   }
218   else if (!url.isEmpty() && url.at(0)=='^') // absolute URL
219   {
220     // skip, keep ^ in the output
221   }
222   else // local file (with optional anchor)
223   {
224     if (overruleFile && n->def && n->def->definitionType()==Definition::TypeFile)
225     {
226       FileDef *fd = (FileDef*)n->def;
227       if (srcLink)
228       {
229         url = fd->getSourceFileBase();
230       }
231       else
232       {
233         url = fd->getOutputFileBase();
234       }
235     }
236     url+=Doxygen::htmlFileExtension;
237     if (!n->anchor.isEmpty()) url+="#"+n->anchor;
238   }
239   return url;
240 }
241
242 QCString FTVHelp::generateIndentLabel(FTVNode *n,int level)
243 {
244   QCString result;
245   if (n->parent)
246   {
247     result=generateIndentLabel(n->parent,level+1);
248   }
249   result+=QCString().setNum(n->index)+"_";
250   return result;
251 }
252
253 void FTVHelp::generateIndent(FTextStream &t, FTVNode *n,bool opened)
254 {
255   int indent=0;
256   FTVNode *p = n->parent;
257   while (p) { indent++; p=p->parent; }
258   if (n->isDir)
259   {
260     QCString dir = opened ? "&#9660;" : "&#9658;";
261     t << "<span style=\"width:" << (indent*16) << "px;display:inline-block;\">&#160;</span>"
262       << "<span id=\"arr_" << generateIndentLabel(n,0) << "\" class=\"arrow\" ";
263     t << "onclick=\"toggleFolder('" << generateIndentLabel(n,0) << "')\"";
264     t << ">" << dir
265       << "</span>";
266   }
267   else
268   {
269     t << "<span style=\"width:" << ((indent+1)*16) << "px;display:inline-block;\">&#160;</span>";
270   }
271 }
272
273 void FTVHelp::generateLink(FTextStream &t,FTVNode *n)
274 {
275   //printf("FTVHelp::generateLink(ref=%s,file=%s,anchor=%s\n",
276   //    n->ref.data(),n->file.data(),n->anchor.data());
277   bool setTarget = FALSE;
278   if (n->file.isEmpty()) // no link
279   {
280     t << "<b>" << convertToHtml(n->name) << "</b>";
281   }
282   else // link into other frame
283   {
284     if (!n->ref.isEmpty()) // link to entity imported via tag file
285     {
286       t << "<a class=\"elRef\" ";
287       QCString result = externalLinkTarget();
288       if (result != "") setTarget = TRUE;
289       t << result << externalRef("",n->ref,FALSE);
290     }
291     else // local link
292     {
293       t << "<a class=\"el\" ";
294     }
295     t << "href=\"";
296     t << externalRef("",n->ref,TRUE);
297     t << node2URL(n);
298     if (!setTarget)
299     {
300       if (m_topLevelIndex)
301         t << "\" target=\"basefrm\">";
302       else
303         t << "\" target=\"_self\">";
304     }
305     else
306     {
307       t << "\">";
308     }
309     t << convertToHtml(n->name);
310     t << "</a>";
311     if (!n->ref.isEmpty())
312     {
313       t << "&#160;[external]";
314     }
315   }
316 }
317
318 static void generateBriefDoc(FTextStream &t,Definition *def)
319 {
320   QCString brief = def->briefDescription(TRUE);
321   //printf("*** %p: generateBriefDoc(%s)='%s'\n",def,def->name().data(),brief.data());
322   if (!brief.isEmpty())
323   {
324     DocNode *root = validatingParseDoc(def->briefFile(),def->briefLine(),
325         def,0,brief,FALSE,FALSE,0,TRUE,TRUE);
326     QCString relPath = relativePathToRoot(def->getOutputFileBase());
327     HtmlCodeGenerator htmlGen(t,relPath);
328     HtmlDocVisitor *visitor = new HtmlDocVisitor(t,htmlGen,def);
329     root->accept(visitor);
330     delete visitor;
331     delete root;
332   }
333 }
334
335 static char compoundIcon(ClassDef *cd)
336 {
337   char icon='C';
338   if (cd->getLanguage() == SrcLangExt_Slice)
339   {
340     if (cd->compoundType()==ClassDef::Interface)
341     {
342       icon='I';
343     }
344     else if (cd->compoundType()==ClassDef::Struct)
345     {
346       icon='S';
347     }
348     else if (cd->compoundType()==ClassDef::Exception)
349     {
350       icon='E';
351     }
352   }
353   return icon;
354 }
355
356 void FTVHelp::generateTree(FTextStream &t, const QList<FTVNode> &nl,int level,int maxLevel,int &index)
357 {
358   QListIterator<FTVNode> nli(nl);
359   FTVNode *n;
360   for (nli.toFirst();(n=nli.current());++nli)
361   {
362     t << "<tr id=\"row_" << generateIndentLabel(n,0) << "\"";
363     if ((index&1)==0) // even row
364       t << " class=\"even\"";
365     if (level>=maxLevel) // item invisible by default
366       t << " style=\"display:none;\"";
367     else // item visible by default
368       index++;
369     t << "><td class=\"entry\">";
370     bool nodeOpened = level+1<maxLevel;
371     generateIndent(t,n,nodeOpened);
372     if (n->isDir)
373     {
374       if (n->def && n->def->definitionType()==Definition::TypeGroup)
375       {
376         // no icon
377       }
378       else if (n->def && n->def->definitionType()==Definition::TypePage)
379       {
380         // no icon
381       }
382       else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
383       {
384         if (n->def->getLanguage() == SrcLangExt_Slice)
385         {
386           t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
387         }
388         else
389         {
390           t << "<span class=\"icona\"><span class=\"icon\">N</span></span>";
391         }
392       }
393       else if (n->def && n->def->definitionType()==Definition::TypeClass)
394       {
395         char icon=compoundIcon(dynamic_cast<ClassDef*>(n->def));
396         t << "<span class=\"icona\"><span class=\"icon\">" << icon << "</span></span>";
397       }
398       else
399       {
400         t << "<span id=\"img_" << generateIndentLabel(n,0)
401           << "\" class=\"iconf"
402           << (nodeOpened?"open":"closed")
403           << "\" onclick=\"toggleFolder('" << generateIndentLabel(n,0)
404           << "')\">&#160;</span>";
405       }
406       generateLink(t,n);
407       t << "</td><td class=\"desc\">";
408       if (n->def)
409       {
410         generateBriefDoc(t,n->def);
411       }
412       t << "</td></tr>" << endl;
413       folderId++;
414       generateTree(t,n->children,level+1,maxLevel,index);
415     }
416     else // leaf node
417     {
418       FileDef *srcRef=0;
419       if (n->def && n->def->definitionType()==Definition::TypeFile &&
420           ((FileDef*)n->def)->generateSourceFile())
421       {
422         srcRef = (FileDef*)n->def;
423       }
424       if (srcRef)
425       {
426         t << "<a href=\"" << srcRef->getSourceFileBase()
427           << Doxygen::htmlFileExtension
428           << "\">";
429       }
430       if (n->def && n->def->definitionType()==Definition::TypeGroup)
431       {
432         // no icon
433       }
434       else if (n->def && n->def->definitionType()==Definition::TypePage)
435       {
436         // no icon
437       }
438       else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
439       {
440         if (n->def->getLanguage() == SrcLangExt_Slice)
441         {
442           t << "<span class=\"icona\"><span class=\"icon\">M</span></span>";
443         }
444         else
445         {
446           t << "<span class=\"icona\"><span class=\"icon\">N</span></span>";
447         }
448       }
449       else if (n->def && n->def->definitionType()==Definition::TypeClass)
450       {
451         char icon=compoundIcon(dynamic_cast<ClassDef*>(n->def));
452         t << "<span class=\"icona\"><span class=\"icon\">" << icon << "</span></span>";
453       }
454       else
455       {
456         t << "<span class=\"icondoc\"></span>";
457       }
458       if (srcRef)
459       {
460         t << "</a>";
461       }
462       generateLink(t,n);
463       t << "</td><td class=\"desc\">";
464       if (n->def)
465       {
466         generateBriefDoc(t,n->def);
467       }
468       t << "</td></tr>" << endl;
469     }
470   }
471 }
472
473 //-----------------------------------------------------------
474
475 struct NavIndexEntry
476 {
477   NavIndexEntry(const QCString &u,const QCString &p) : url(u), path(p) {}
478   QCString url;
479   QCString path;
480 };
481
482 class NavIndexEntryList : public QList<NavIndexEntry>
483 {
484   public:
485     NavIndexEntryList() : QList<NavIndexEntry>() { setAutoDelete(TRUE); }
486    ~NavIndexEntryList() {}
487   private:
488     int compareValues(const NavIndexEntry *item1,const NavIndexEntry *item2) const
489     {
490       // sort list based on url
491       return qstrcmp(item1->url,item2->url);
492     }
493 };
494
495 static QCString pathToNode(FTVNode *leaf,FTVNode *n)
496 {
497   QCString result;
498   if (n->parent)
499   {
500     result+=pathToNode(leaf,n->parent);
501   }
502   result+=QCString().setNum(n->index);
503   if (leaf!=n) result+=",";
504   return result;
505 }
506
507 static bool dupOfParent(const FTVNode *n)
508 {
509   if (n->parent==0) return FALSE;
510   if (n->file==n->parent->file) return TRUE;
511   return FALSE;
512 }
513
514 static void generateJSLink(FTextStream &t,FTVNode *n)
515 {
516   if (n->file.isEmpty()) // no link
517   {
518     t << "\"" << convertToJSString(n->name) << "\", null, ";
519   }
520   else // link into other page
521   {
522     t << "\"" << convertToJSString(n->name) << "\", \"";
523     t << externalRef("",n->ref,TRUE);
524     t << node2URL(n);
525     t << "\", ";
526   }
527 }
528
529 static QCString convertFileId2Var(const QCString &fileId)
530 {
531   QCString varId = fileId;
532   int i=varId.findRev('/');
533   if (i>=0) varId = varId.mid(i+1);
534   return substitute(varId,"-","_");
535 }
536
537 static bool generateJSTree(NavIndexEntryList &navIndex,FTextStream &t,
538                            const QList<FTVNode> &nl,int level,bool &first)
539 {
540   static QCString htmlOutput = Config_getString(HTML_OUTPUT);
541   QCString indentStr;
542   indentStr.fill(' ',level*2);
543   bool found=FALSE;
544   QListIterator<FTVNode> nli(nl);
545   FTVNode *n;
546   for (nli.toFirst();(n=nli.current());++nli)
547   {
548     // terminate previous entry
549     if (!first) t << "," << endl;
550     first=FALSE;
551
552     // start entry
553     if (!found)
554     {
555       t << "[" << endl;
556     }
557     found=TRUE;
558
559     if (n->addToNavIndex) // add entry to the navigation index
560     {
561       if (n->def && n->def->definitionType()==Definition::TypeFile)
562       {
563         FileDef *fd = (FileDef*)n->def;
564         bool doc,src;
565         doc = fileVisibleInIndex(fd,src);
566         if (doc)
567         {
568           navIndex.append(new NavIndexEntry(node2URL(n,TRUE,FALSE),pathToNode(n,n)));
569         }
570         if (src)
571         {
572           navIndex.append(new NavIndexEntry(node2URL(n,TRUE,TRUE),pathToNode(n,n)));
573         }
574       }
575       else
576       {
577         navIndex.append(new NavIndexEntry(node2URL(n),pathToNode(n,n)));
578       }
579     }
580
581     if (n->separateIndex) // store items in a separate file for dynamic loading
582     {
583       bool firstChild=TRUE;
584       t << indentStr << "  [ ";
585       generateJSLink(t,n);
586       if (n->children.count()>0) // write children to separate file for dynamic loading
587       {
588         QCString fileId = n->file;
589         if (n->anchor)
590         {
591           fileId+="_"+n->anchor;
592         }
593         if (dupOfParent(n))
594         {
595           fileId+="_dup";
596         }
597         QFile f(htmlOutput+"/"+fileId+".js");
598         if (f.open(IO_WriteOnly))
599         {
600           FTextStream tt(&f);
601           tt << "var " << convertFileId2Var(fileId) << " =" << endl;
602           generateJSTree(navIndex,tt,n->children,1,firstChild);
603           tt << endl << "];";
604         }
605         t << "\"" << fileId << "\" ]";
606       }
607       else // no children
608       {
609         t << "null ]";
610       }
611     }
612     else // show items in this file
613     {
614       bool firstChild=TRUE;
615       t << indentStr << "  [ ";
616       generateJSLink(t,n);
617       bool emptySection = !generateJSTree(navIndex,t,n->children,level+1,firstChild);
618       if (emptySection)
619         t << "null ]";
620       else
621         t << endl << indentStr << "  ] ]";
622     }
623   }
624   return found;
625 }
626
627 static void generateJSNavTree(const QList<FTVNode> &nodeList)
628 {
629   QCString htmlOutput = Config_getString(HTML_OUTPUT);
630   QFile f(htmlOutput+"/navtreedata.js");
631   NavIndexEntryList navIndex;
632   if (f.open(IO_WriteOnly) /*&& fidx.open(IO_WriteOnly)*/)
633   {
634     //FTextStream tidx(&fidx);
635     //tidx << "var NAVTREEINDEX =" << endl;
636     //tidx << "{" << endl;
637     FTextStream t(&f);
638                 t << "/*\n@ @licstart  The following is the entire license notice for the\n"
639                         "JavaScript code in this file.\n\nCopyright (C) 1997-2017 by Dimitri van Heesch\n\n"
640                         "This program is free software; you can redistribute it and/or modify\n"
641                         "it under the terms of the GNU General Public License as published by\n"
642                         "the Free Software Foundation; either version 2 of the License, or\n"
643                         "(at your option) any later version.\n\n"
644                         "This program is distributed in the hope that it will be useful,\n"
645                         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
646                         " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
647                         " GNU General Public License for more details.\n\n"
648                         "You should have received a copy of the GNU General Public License along\n"
649                         "with this program; if not, write to the Free Software Foundation, Inc.,\n"
650                         "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n"
651                         "@licend  The above is the entire license notice\n"
652                         "for the JavaScript code in this file\n"
653                         "*/\n";
654     t << "var NAVTREE =" << endl;
655     t << "[" << endl;
656     t << "  [ ";
657     QCString &projName = Config_getString(PROJECT_NAME);
658     if (projName.isEmpty())
659     {
660       if (Doxygen::mainPage && !Doxygen::mainPage->title().isEmpty()) // Use title of main page as root
661       {
662         t << "\"" << convertToJSString(Doxygen::mainPage->title()) << "\", ";
663       }
664       else // Use default section title as root
665       {
666         LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::MainPage);
667         t << "\"" << convertToJSString(lne->title()) << "\", ";
668       }
669     }
670     else // use PROJECT_NAME as root tree element
671     {
672       t << "\"" << convertToJSString(projName) << "\", ";
673     }
674     t << "\"index" << Doxygen::htmlFileExtension << "\", ";
675
676     // add special entry for index page
677     navIndex.append(new NavIndexEntry("index"+Doxygen::htmlFileExtension,""));
678     // related page index is written as a child of index.html, so add this as well
679     navIndex.append(new NavIndexEntry("pages"+Doxygen::htmlFileExtension,""));
680
681     bool first=TRUE;
682     generateJSTree(navIndex,t,nodeList,1,first);
683
684     if (first)
685       t << "]" << endl;
686     else
687       t << endl << "  ] ]" << endl;
688     t << "];" << endl << endl;
689
690     // write the navigation index (and sub-indices)
691     navIndex.sort();
692     int subIndex=0;
693     int elemCount=0;
694     const int maxElemCount=250;
695     //QFile fidx(htmlOutput+"/navtreeindex.js");
696     QFile fsidx(htmlOutput+"/navtreeindex0.js");
697     if (/*fidx.open(IO_WriteOnly) &&*/ fsidx.open(IO_WriteOnly))
698     {
699       //FTextStream tidx(&fidx);
700       FTextStream tsidx(&fsidx);
701       t << "var NAVTREEINDEX =" << endl;
702       t << "[" << endl;
703       tsidx << "var NAVTREEINDEX" << subIndex << " =" << endl;
704       tsidx << "{" << endl;
705       QListIterator<NavIndexEntry> li(navIndex);
706       NavIndexEntry *e;
707       bool first=TRUE;
708       for (li.toFirst();(e=li.current());) // for each entry
709       {
710         if (elemCount==0)
711         {
712           if (!first)
713           {
714             t << "," << endl;
715           }
716           else
717           {
718             first=FALSE;
719           }
720           t << "\"" << e->url << "\"";
721         }
722         tsidx << "\"" << e->url << "\":[" << e->path << "]";
723         ++li;
724         if (li.current() && elemCount<maxElemCount-1) tsidx << ","; // not last entry
725         tsidx << endl;
726
727         elemCount++;
728         if (li.current() && elemCount>=maxElemCount) // switch to new sub-index
729         {
730           tsidx << "};" << endl;
731           elemCount=0;
732           fsidx.close();
733           subIndex++;
734           fsidx.setName(htmlOutput+"/navtreeindex"+QCString().setNum(subIndex)+".js");
735           if (!fsidx.open(IO_WriteOnly)) break;
736           tsidx.setDevice(&fsidx);
737           tsidx << "var NAVTREEINDEX" << subIndex << " =" << endl;
738           tsidx << "{" << endl;
739         }
740       }
741       tsidx << "};" << endl;
742       t << endl << "];" << endl;
743     }
744     t << endl << "var SYNCONMSG = '"  << theTranslator->trPanelSynchronisationTooltip(FALSE) << "';";
745     t << endl << "var SYNCOFFMSG = '" << theTranslator->trPanelSynchronisationTooltip(TRUE)  << "';";
746   }
747   ResourceMgr::instance().copyResource("navtree.js",htmlOutput);
748 }
749
750 //-----------------------------------------------------------
751
752 // new style images
753 void FTVHelp::generateTreeViewImages()
754 {
755   QCString dname=Config_getString(HTML_OUTPUT);
756   const ResourceMgr &rm = ResourceMgr::instance();
757   rm.copyResource("doc.luma",dname);
758   rm.copyResource("folderopen.luma",dname);
759   rm.copyResource("folderclosed.luma",dname);
760   rm.copyResource("splitbar.lum",dname);
761 }
762
763 // new style scripts
764 void FTVHelp::generateTreeViewScripts()
765 {
766   QCString htmlOutput = Config_getString(HTML_OUTPUT);
767
768   // generate navtree.js & navtreeindex.js
769   generateJSNavTree(m_indentNodes[0]);
770
771   // copy resize.js & navtree.css
772   ResourceMgr::instance().copyResource("resize.js",htmlOutput);
773   ResourceMgr::instance().copyResource("navtree.css",htmlOutput);
774 }
775
776 // write tree inside page
777 void FTVHelp::generateTreeViewInline(FTextStream &t)
778 {
779   int preferredNumEntries = Config_getInt(HTML_INDEX_NUM_ENTRIES);
780   t << "<div class=\"directory\">\n";
781   QListIterator<FTVNode> li(m_indentNodes[0]);
782   FTVNode *n;
783   int d=1, depth=1;
784   for (;(n=li.current());++li)
785   {
786     if (n->children.count()>0)
787     {
788       d = n->computeTreeDepth(2);
789       if (d>depth) depth=d;
790     }
791   }
792   int preferredDepth = depth;
793   // write level selector
794   if (depth>1)
795   {
796     t << "<div class=\"levels\">[";
797     t << theTranslator->trDetailLevel();
798     t << " ";
799     int i;
800     for (i=1;i<=depth;i++)
801     {
802       t << "<span onclick=\"javascript:toggleLevel(" << i << ");\">" << i << "</span>";
803     }
804     t << "]</div>";
805
806     if (preferredNumEntries>0)
807     {
808       preferredDepth=1;
809       for (int i=1;i<=depth;i++)
810       {
811         int num=0;
812         QListIterator<FTVNode> li(m_indentNodes[0]);
813         FTVNode *n;
814         for (;(n=li.current());++li)
815         {
816           num+=n->numNodesAtLevel(0,i);
817         }
818         if (num<=preferredNumEntries)
819         {
820           preferredDepth=i;
821         }
822         else
823         {
824           break;
825         }
826       }
827     }
828   }
829   //printf("preferred depth=%d\n",preferredDepth);
830
831   if (m_indentNodes[0].count())
832   {
833     t << "<table class=\"directory\">\n";
834     int index=0;
835     generateTree(t,m_indentNodes[0],0,preferredDepth,index);
836     t << "</table>\n";
837   }
838
839   t << "</div><!-- directory -->\n";
840 }
841
842 // write old style index.html and tree.html
843 void FTVHelp::generateTreeView()
844 {
845   generateTreeViewImages();
846   generateTreeViewScripts();
847 }