Blame src/ftvhelp.cpp

Packit 1c1d7e
/******************************************************************************
Packit 1c1d7e
 * ftvhelp.cpp,v 1.0 2000/09/06 16:09:00
Packit 1c1d7e
 *
Packit 1c1d7e
 * Copyright (C) 1997-2015 by Dimitri van Heesch.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Permission to use, copy, modify, and distribute this software and its
Packit 1c1d7e
 * documentation under the terms of the GNU General Public License is hereby
Packit 1c1d7e
 * granted. No representations are made about the suitability of this software
Packit 1c1d7e
 * for any purpose. It is provided "as is" without express or implied warranty.
Packit 1c1d7e
 * See the GNU General Public License for more details.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Documents produced by Doxygen are derivative works derived from the
Packit 1c1d7e
 * input used in their production; they are not affected by this license.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Original version contributed by Kenney Wong <kwong@ea.com>
Packit 1c1d7e
 * Modified by Dimitri van Heesch
Packit 1c1d7e
 *
Packit 1c1d7e
 * Folder Tree View for offline help on browsers that do not support HTML Help.
Packit 1c1d7e
 */
Packit 1c1d7e
Packit 1c1d7e
#include <stdio.h>
Packit 1c1d7e
#include <stdlib.h>
Packit 1c1d7e
#include <qlist.h>
Packit 1c1d7e
#include <qdict.h>
Packit 1c1d7e
#include <qfileinfo.h>
Packit 1c1d7e
Packit 1c1d7e
#include "ftvhelp.h"
Packit 1c1d7e
#include "config.h"
Packit 1c1d7e
#include "message.h"
Packit 1c1d7e
#include "doxygen.h"
Packit 1c1d7e
#include "language.h"
Packit 1c1d7e
#include "htmlgen.h"
Packit 1c1d7e
#include "layout.h"
Packit 1c1d7e
#include "pagedef.h"
Packit 1c1d7e
#include "docparser.h"
Packit 1c1d7e
#include "htmldocvisitor.h"
Packit 1c1d7e
#include "filedef.h"
Packit 1c1d7e
#include "util.h"
Packit 1c1d7e
#include "resourcemgr.h"
Packit 1c1d7e
Packit 1c1d7e
#define MAX_INDENT 1024
Packit 1c1d7e
Packit 1c1d7e
static int folderId=1;
Packit 1c1d7e
Packit 1c1d7e
struct FTVNode
Packit 1c1d7e
{
Packit 1c1d7e
  FTVNode(bool dir,const char *r,const char *f,const char *a,
Packit 1c1d7e
          const char *n,bool sepIndex,bool navIndex,Definition *df)
Packit 1c1d7e
    : isLast(TRUE), isDir(dir),ref(r),file(f),anchor(a),name(n), index(0),
Packit 1c1d7e
      parent(0), separateIndex(sepIndex), addToNavIndex(navIndex),
Packit 1c1d7e
      def(df) { children.setAutoDelete(TRUE); }
Packit 1c1d7e
  int computeTreeDepth(int level) const;
Packit 1c1d7e
  int numNodesAtLevel(int level,int maxLevel) const;
Packit 1c1d7e
  bool isLast;
Packit 1c1d7e
  bool isDir;
Packit 1c1d7e
  QCString ref;
Packit 1c1d7e
  QCString file;
Packit 1c1d7e
  QCString anchor;
Packit 1c1d7e
  QCString name;
Packit 1c1d7e
  int index;
Packit 1c1d7e
  QList<FTVNode> children;
Packit 1c1d7e
  FTVNode *parent;
Packit 1c1d7e
  bool separateIndex;
Packit 1c1d7e
  bool addToNavIndex;
Packit 1c1d7e
  Definition *def;
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
int FTVNode::computeTreeDepth(int level) const
Packit 1c1d7e
{
Packit 1c1d7e
  int maxDepth=level;
Packit 1c1d7e
  QListIterator<FTVNode> li(children);
Packit 1c1d7e
  FTVNode *n;
Packit 1c1d7e
  for (;(n=li.current());++li)
Packit 1c1d7e
  {
Packit 1c1d7e
    if (n->children.count()>0)
Packit 1c1d7e
    {
Packit 1c1d7e
      int d = n->computeTreeDepth(level+1);
Packit 1c1d7e
      if (d>maxDepth) maxDepth=d;
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  return maxDepth;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
int FTVNode::numNodesAtLevel(int level,int maxLevel) const
Packit 1c1d7e
{
Packit 1c1d7e
  int num=0;
Packit 1c1d7e
  if (level
Packit 1c1d7e
  {
Packit 1c1d7e
    num++; // this node
Packit 1c1d7e
    QListIterator<FTVNode> li(children);
Packit 1c1d7e
    FTVNode *n;
Packit 1c1d7e
    for (;(n=li.current());++li)
Packit 1c1d7e
    {
Packit 1c1d7e
      num+=n->numNodesAtLevel(level+1,maxLevel);
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  return num;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
//----------------------------------------------------------------------------
Packit 1c1d7e
Packit 1c1d7e
/*! Constructs an ftv help object.
Packit 1c1d7e
 *  The object has to be \link initialize() initialized\endlink before it can
Packit 1c1d7e
 *  be used.
Packit 1c1d7e
 */
Packit 1c1d7e
FTVHelp::FTVHelp(bool TLI)
Packit 1c1d7e
{
Packit 1c1d7e
  /* initial depth */
Packit 1c1d7e
  m_indentNodes = new QList<FTVNode>[MAX_INDENT];
Packit 1c1d7e
  m_indentNodes[0].setAutoDelete(TRUE);
Packit 1c1d7e
  m_indent=0;
Packit 1c1d7e
  m_topLevelIndex = TLI;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! Destroys the ftv help object. */
Packit 1c1d7e
FTVHelp::~FTVHelp()
Packit 1c1d7e
{
Packit 1c1d7e
  delete[] m_indentNodes;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! This will create a folder tree view table of contents file (tree.js).
Packit 1c1d7e
 *  \sa finalize()
Packit 1c1d7e
 */
Packit 1c1d7e
void FTVHelp::initialize()
Packit 1c1d7e
{
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! Finalizes the FTV help. This will finish and close the
Packit 1c1d7e
 *  contents file (index.js).
Packit 1c1d7e
 *  \sa initialize()
Packit 1c1d7e
 */
Packit 1c1d7e
void FTVHelp::finalize()
Packit 1c1d7e
{
Packit 1c1d7e
  generateTreeView();
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! Increase the level of the contents hierarchy.
Packit 1c1d7e
 *  This will start a new sublist in contents file.
Packit 1c1d7e
 *  \sa decContentsDepth()
Packit 1c1d7e
 */
Packit 1c1d7e
void FTVHelp::incContentsDepth()
Packit 1c1d7e
{
Packit 1c1d7e
  //printf("incContentsDepth() indent=%d\n",m_indent);
Packit 1c1d7e
  m_indent++;
Packit 1c1d7e
  ASSERT(m_indent
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! Decrease the level of the contents hierarchy.
Packit 1c1d7e
 *  This will end the current sublist.
Packit 1c1d7e
 *  \sa incContentsDepth()
Packit 1c1d7e
 */
Packit 1c1d7e
void FTVHelp::decContentsDepth()
Packit 1c1d7e
{
Packit 1c1d7e
  //printf("decContentsDepth() indent=%d\n",m_indent);
Packit 1c1d7e
  ASSERT(m_indent>0);
Packit 1c1d7e
  if (m_indent>0)
Packit 1c1d7e
  {
Packit 1c1d7e
    m_indent--;
Packit 1c1d7e
    QList<FTVNode> *nl = &m_indentNodes[m_indent];
Packit 1c1d7e
    FTVNode *parent = nl->getLast();
Packit 1c1d7e
    if (parent)
Packit 1c1d7e
    {
Packit 1c1d7e
      QList<FTVNode> *children = &m_indentNodes[m_indent+1];
Packit 1c1d7e
      while (!children->isEmpty())
Packit 1c1d7e
      {
Packit 1c1d7e
        parent->children.append(children->take(0));
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/*! Add a list item to the contents file.
Packit 1c1d7e
 *  \param isDir TRUE if the item is a directory, FALSE if it is a text
Packit 1c1d7e
 *  \param name The name of the item.
Packit 1c1d7e
 *  \param ref  the URL of to the item.
Packit 1c1d7e
 *  \param file the file containing the definition of the item
Packit 1c1d7e
 *  \param anchor the anchor within the file.
Packit 1c1d7e
 *  \param name the name of the item.
Packit 1c1d7e
 *  \param separateIndex put the entries in a separate index file
Packit 1c1d7e
 *  \param addToNavIndex add this entry to the quick navigation index
Packit 1c1d7e
 *  \param def Definition corresponding to this entry
Packit 1c1d7e
 */
Packit 1c1d7e
void FTVHelp::addContentsItem(bool isDir,
Packit 1c1d7e
                              const char *name,
Packit 1c1d7e
                              const char *ref,
Packit 1c1d7e
                              const char *file,
Packit 1c1d7e
                              const char *anchor,
Packit 1c1d7e
                              bool separateIndex,
Packit 1c1d7e
                              bool addToNavIndex,
Packit 1c1d7e
                              Definition *def
Packit 1c1d7e
                              )
Packit 1c1d7e
{
Packit 1c1d7e
  //printf("%p: m_indent=%d addContentsItem(%s,%s,%s,%s)\n",this,m_indent,name,ref,file,anchor);
Packit 1c1d7e
  QList<FTVNode> *nl = &m_indentNodes[m_indent];
Packit 1c1d7e
  FTVNode *newNode = new FTVNode(isDir,ref,file,anchor,name,separateIndex,addToNavIndex,def);
Packit 1c1d7e
  if (!nl->isEmpty())
Packit 1c1d7e
  {
Packit 1c1d7e
    nl->getLast()->isLast=FALSE;
Packit 1c1d7e
  }
Packit 1c1d7e
  nl->append(newNode);
Packit 1c1d7e
  newNode->index = nl->count()-1;
Packit 1c1d7e
  if (m_indent>0)
Packit 1c1d7e
  {
Packit 1c1d7e
    QList<FTVNode> *pnl = &m_indentNodes[m_indent-1];
Packit 1c1d7e
    newNode->parent = pnl->getLast();
Packit 1c1d7e
  }
Packit 1c1d7e
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static QCString node2URL(FTVNode *n,bool overruleFile=FALSE,bool srcLink=FALSE)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString url = n->file;
Packit 1c1d7e
  if (!url.isEmpty() && url.at(0)=='!')  // relative URL
Packit 1c1d7e
  {
Packit 1c1d7e
    // remove leading !
Packit 1c1d7e
    url = url.mid(1);
Packit 1c1d7e
  }
Packit 1c1d7e
  else if (!url.isEmpty() && url.at(0)=='^') // absolute URL
Packit 1c1d7e
  {
Packit 1c1d7e
    // skip, keep ^ in the output
Packit 1c1d7e
  }
Packit 1c1d7e
  else // local file (with optional anchor)
Packit 1c1d7e
  {
Packit 1c1d7e
    if (overruleFile && n->def && n->def->definitionType()==Definition::TypeFile)
Packit 1c1d7e
    {
Packit 1c1d7e
      FileDef *fd = (FileDef*)n->def;
Packit 1c1d7e
      if (srcLink)
Packit 1c1d7e
      {
Packit 1c1d7e
        url = fd->getSourceFileBase();
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        url = fd->getOutputFileBase();
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
    url+=Doxygen::htmlFileExtension;
Packit 1c1d7e
    if (!n->anchor.isEmpty()) url+="#"+n->anchor;
Packit 1c1d7e
  }
Packit 1c1d7e
  return url;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
QCString FTVHelp::generateIndentLabel(FTVNode *n,int level)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString result;
Packit 1c1d7e
  if (n->parent)
Packit 1c1d7e
  {
Packit 1c1d7e
    result=generateIndentLabel(n->parent,level+1);
Packit 1c1d7e
  }
Packit 1c1d7e
  result+=QCString().setNum(n->index)+"_";
Packit 1c1d7e
  return result;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void FTVHelp::generateIndent(FTextStream &t, FTVNode *n,bool opened)
Packit 1c1d7e
{
Packit 1c1d7e
  int indent=0;
Packit 1c1d7e
  FTVNode *p = n->parent;
Packit 1c1d7e
  while (p) { indent++; p=p->parent; }
Packit 1c1d7e
  if (n->isDir)
Packit 1c1d7e
  {
Packit 1c1d7e
    QCString dir = opened ? "▼" : "▶";
Packit 1c1d7e
    t << " "
Packit 1c1d7e
      << "
Packit 1c1d7e
    t << "onclick=\"toggleFolder('" << generateIndentLabel(n,0) << "')\"";
Packit 1c1d7e
    t << ">" << dir
Packit 1c1d7e
      << "";
Packit 1c1d7e
  }
Packit 1c1d7e
  else
Packit 1c1d7e
  {
Packit 1c1d7e
    t << " ";
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void FTVHelp::generateLink(FTextStream &t,FTVNode *n)
Packit 1c1d7e
{
Packit 1c1d7e
  //printf("FTVHelp::generateLink(ref=%s,file=%s,anchor=%s\n",
Packit 1c1d7e
  //    n->ref.data(),n->file.data(),n->anchor.data());
Packit 1c1d7e
  bool setTarget = FALSE;
Packit 1c1d7e
  if (n->file.isEmpty()) // no link
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "" << convertToHtml(n->name) << "";
Packit 1c1d7e
  }
Packit 1c1d7e
  else // link into other frame
Packit 1c1d7e
  {
Packit 1c1d7e
    if (!n->ref.isEmpty()) // link to entity imported via tag file
Packit 1c1d7e
    {
Packit 1c1d7e
      t << "
Packit 1c1d7e
      QCString result = externalLinkTarget();
Packit 1c1d7e
      if (result != "") setTarget = TRUE;
Packit 1c1d7e
      t << result << externalRef("",n->ref,FALSE);
Packit 1c1d7e
    }
Packit 1c1d7e
    else // local link
Packit 1c1d7e
    {
Packit 1c1d7e
      t << "
Packit 1c1d7e
    }
Packit 1c1d7e
    t << "href=\"";
Packit 1c1d7e
    t << externalRef("",n->ref,TRUE);
Packit 1c1d7e
    t << node2URL(n);
Packit 1c1d7e
    if (!setTarget)
Packit 1c1d7e
    {
Packit 1c1d7e
      if (m_topLevelIndex)
Packit 1c1d7e
        t << "\" target=\"basefrm\">";
Packit 1c1d7e
      else
Packit 1c1d7e
        t << "\" target=\"_self\">";
Packit 1c1d7e
    }
Packit 1c1d7e
    t << convertToHtml(n->name);
Packit 1c1d7e
    t << "";
Packit 1c1d7e
    if (!n->ref.isEmpty())
Packit 1c1d7e
    {
Packit 1c1d7e
      t << " [external]";
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static void generateBriefDoc(FTextStream &t,Definition *def)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString brief = def->briefDescription(TRUE);
Packit 1c1d7e
  //printf("*** %p: generateBriefDoc(%s)='%s'\n",def,def->name().data(),brief.data());
Packit 1c1d7e
  if (!brief.isEmpty())
Packit 1c1d7e
  {
Packit 1c1d7e
    DocNode *root = validatingParseDoc(def->briefFile(),def->briefLine(),
Packit 1c1d7e
        def,0,brief,FALSE,FALSE,0,TRUE,TRUE);
Packit 1c1d7e
    QCString relPath = relativePathToRoot(def->getOutputFileBase());
Packit 1c1d7e
    HtmlCodeGenerator htmlGen(t,relPath);
Packit 1c1d7e
    HtmlDocVisitor *visitor = new HtmlDocVisitor(t,htmlGen,def);
Packit 1c1d7e
    root->accept(visitor);
Packit 1c1d7e
    delete visitor;
Packit 1c1d7e
    delete root;
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void FTVHelp::generateTree(FTextStream &t, const QList<FTVNode> &nl,int level,int maxLevel,int &index)
Packit 1c1d7e
{
Packit 1c1d7e
  QListIterator<FTVNode> nli(nl);
Packit 1c1d7e
  FTVNode *n;
Packit 1c1d7e
  for (nli.toFirst();(n=nli.current());++nli)
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "
Packit 1c1d7e
    if ((index&1)==0) // even row
Packit 1c1d7e
      t << " class=\"even\"";
Packit 1c1d7e
    if (level>=maxLevel) // item invisible by default
Packit 1c1d7e
      t << " style=\"display:none;\"";
Packit 1c1d7e
    else // item visible by default
Packit 1c1d7e
      index++;
Packit 1c1d7e
    t << ">";
Packit 1c1d7e
    bool nodeOpened = level+1
Packit 1c1d7e
    generateIndent(t,n,nodeOpened);
Packit 1c1d7e
    if (n->isDir)
Packit 1c1d7e
    {
Packit 1c1d7e
      if (n->def && n->def->definitionType()==Definition::TypeGroup)
Packit 1c1d7e
      {
Packit 1c1d7e
        // no icon
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypePage)
Packit 1c1d7e
      {
Packit 1c1d7e
        // no icon
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "N";
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypeClass)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "C";
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "
Packit 1c1d7e
          << "\" class=\"iconf"
Packit 1c1d7e
          << (nodeOpened?"open":"closed")
Packit 1c1d7e
          << "\" onclick=\"toggleFolder('" << generateIndentLabel(n,0)
Packit 1c1d7e
          << "')\"> ";
Packit 1c1d7e
      }
Packit 1c1d7e
      generateLink(t,n);
Packit 1c1d7e
      t << "";
Packit 1c1d7e
      if (n->def)
Packit 1c1d7e
      {
Packit 1c1d7e
        generateBriefDoc(t,n->def);
Packit 1c1d7e
      }
Packit 1c1d7e
      t << "" << endl;
Packit 1c1d7e
      folderId++;
Packit 1c1d7e
      generateTree(t,n->children,level+1,maxLevel,index);
Packit 1c1d7e
    }
Packit 1c1d7e
    else // leaf node
Packit 1c1d7e
    {
Packit 1c1d7e
      FileDef *srcRef=0;
Packit 1c1d7e
      if (n->def && n->def->definitionType()==Definition::TypeFile &&
Packit 1c1d7e
          ((FileDef*)n->def)->generateSourceFile())
Packit 1c1d7e
      {
Packit 1c1d7e
        srcRef = (FileDef*)n->def;
Packit 1c1d7e
      }
Packit 1c1d7e
      if (srcRef)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "getSourceFileBase()
Packit 1c1d7e
          << Doxygen::htmlFileExtension
Packit 1c1d7e
          << "\">";
Packit 1c1d7e
      }
Packit 1c1d7e
      if (n->def && n->def->definitionType()==Definition::TypeGroup)
Packit 1c1d7e
      {
Packit 1c1d7e
        // no icon
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypePage)
Packit 1c1d7e
      {
Packit 1c1d7e
        // no icon
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypeNamespace)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "N";
Packit 1c1d7e
      }
Packit 1c1d7e
      else if (n->def && n->def->definitionType()==Definition::TypeClass)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "C";
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "";
Packit 1c1d7e
      }
Packit 1c1d7e
      if (srcRef)
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "";
Packit 1c1d7e
      }
Packit 1c1d7e
      generateLink(t,n);
Packit 1c1d7e
      t << "";
Packit 1c1d7e
      if (n->def)
Packit 1c1d7e
      {
Packit 1c1d7e
        generateBriefDoc(t,n->def);
Packit 1c1d7e
      }
Packit 1c1d7e
      t << "" << endl;
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
//-----------------------------------------------------------
Packit 1c1d7e
Packit 1c1d7e
struct NavIndexEntry
Packit 1c1d7e
{
Packit 1c1d7e
  NavIndexEntry(const QCString &u,const QCString &p) : url(u), path(p) {}
Packit 1c1d7e
  QCString url;
Packit 1c1d7e
  QCString path;
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
class NavIndexEntryList : public QList<NavIndexEntry>
Packit 1c1d7e
{
Packit 1c1d7e
  public:
Packit 1c1d7e
    NavIndexEntryList() : QList<NavIndexEntry>() { setAutoDelete(TRUE); }
Packit 1c1d7e
   ~NavIndexEntryList() {}
Packit 1c1d7e
  private:
Packit 1c1d7e
    int compareValues(const NavIndexEntry *item1,const NavIndexEntry *item2) const
Packit 1c1d7e
    {
Packit 1c1d7e
      // sort list based on url
Packit 1c1d7e
      return qstrcmp(item1->url,item2->url);
Packit 1c1d7e
    }
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
static QCString pathToNode(FTVNode *leaf,FTVNode *n)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString result;
Packit 1c1d7e
  if (n->parent)
Packit 1c1d7e
  {
Packit 1c1d7e
    result+=pathToNode(leaf,n->parent);
Packit 1c1d7e
  }
Packit 1c1d7e
  result+=QCString().setNum(n->index);
Packit 1c1d7e
  if (leaf!=n) result+=",";
Packit 1c1d7e
  return result;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static bool dupOfParent(const FTVNode *n)
Packit 1c1d7e
{
Packit 1c1d7e
  if (n->parent==0) return FALSE;
Packit 1c1d7e
  if (n->file==n->parent->file) return TRUE;
Packit 1c1d7e
  return FALSE;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static void generateJSLink(FTextStream &t,FTVNode *n)
Packit 1c1d7e
{
Packit 1c1d7e
  if (n->file.isEmpty()) // no link
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "\"" << convertToJSString(n->name) << "\", null, ";
Packit 1c1d7e
  }
Packit 1c1d7e
  else // link into other page
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "\"" << convertToJSString(n->name) << "\", \"";
Packit 1c1d7e
    t << externalRef("",n->ref,TRUE);
Packit 1c1d7e
    t << node2URL(n);
Packit 1c1d7e
    t << "\", ";
Packit 1c1d7e
  }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static QCString convertFileId2Var(const QCString &fileId)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString varId = fileId;
Packit 1c1d7e
  int i=varId.findRev('/');
Packit 1c1d7e
  if (i>=0) varId = varId.mid(i+1);
Packit 1c1d7e
  return substitute(varId,"-","_");
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static bool generateJSTree(NavIndexEntryList &navIndex,FTextStream &t,
Packit 1c1d7e
                           const QList<FTVNode> &nl,int level,bool &first)
Packit 1c1d7e
{
Packit 1c1d7e
  static QCString htmlOutput = Config_getString(HTML_OUTPUT);
Packit 1c1d7e
  QCString indentStr;
Packit 1c1d7e
  indentStr.fill(' ',level*2);
Packit 1c1d7e
  bool found=FALSE;
Packit 1c1d7e
  QListIterator<FTVNode> nli(nl);
Packit 1c1d7e
  FTVNode *n;
Packit 1c1d7e
  for (nli.toFirst();(n=nli.current());++nli)
Packit 1c1d7e
  {
Packit 1c1d7e
    // terminate previous entry
Packit 1c1d7e
    if (!first) t << "," << endl;
Packit 1c1d7e
    first=FALSE;
Packit 1c1d7e
Packit 1c1d7e
    // start entry
Packit 1c1d7e
    if (!found)
Packit 1c1d7e
    {
Packit 1c1d7e
      t << "[" << endl;
Packit 1c1d7e
    }
Packit 1c1d7e
    found=TRUE;
Packit 1c1d7e
Packit 1c1d7e
    if (n->addToNavIndex) // add entry to the navigation index
Packit 1c1d7e
    {
Packit 1c1d7e
      if (n->def && n->def->definitionType()==Definition::TypeFile)
Packit 1c1d7e
      {
Packit 1c1d7e
        FileDef *fd = (FileDef*)n->def;
Packit 1c1d7e
        bool doc,src;
Packit 1c1d7e
        doc = fileVisibleInIndex(fd,src);
Packit 1c1d7e
        if (doc)
Packit 1c1d7e
        {
Packit 1c1d7e
          navIndex.append(new NavIndexEntry(node2URL(n,TRUE,FALSE),pathToNode(n,n)));
Packit 1c1d7e
        }
Packit 1c1d7e
        if (src)
Packit 1c1d7e
        {
Packit 1c1d7e
          navIndex.append(new NavIndexEntry(node2URL(n,TRUE,TRUE),pathToNode(n,n)));
Packit 1c1d7e
        }
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        navIndex.append(new NavIndexEntry(node2URL(n),pathToNode(n,n)));
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
Packit 1c1d7e
    if (n->separateIndex) // store items in a separate file for dynamic loading
Packit 1c1d7e
    {
Packit 1c1d7e
      bool firstChild=TRUE;
Packit 1c1d7e
      t << indentStr << "  [ ";
Packit 1c1d7e
      generateJSLink(t,n);
Packit 1c1d7e
      if (n->children.count()>0) // write children to separate file for dynamic loading
Packit 1c1d7e
      {
Packit 1c1d7e
        QCString fileId = n->file;
Packit 1c1d7e
        if (n->anchor)
Packit 1c1d7e
        {
Packit 1c1d7e
          fileId+="_"+n->anchor;
Packit 1c1d7e
        }
Packit 1c1d7e
        if (dupOfParent(n))
Packit 1c1d7e
        {
Packit 1c1d7e
          fileId+="_dup";
Packit 1c1d7e
        }
Packit 1c1d7e
        QFile f(htmlOutput+"/"+fileId+".js");
Packit 1c1d7e
        if (f.open(IO_WriteOnly))
Packit 1c1d7e
        {
Packit 1c1d7e
          FTextStream tt(&f);
Packit 1c1d7e
          tt << "var " << convertFileId2Var(fileId) << " =" << endl;
Packit 1c1d7e
          generateJSTree(navIndex,tt,n->children,1,firstChild);
Packit 1c1d7e
          tt << endl << "];";
Packit 1c1d7e
        }
Packit 1c1d7e
        t << "\"" << fileId << "\" ]";
Packit 1c1d7e
      }
Packit 1c1d7e
      else // no children
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "null ]";
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
    else // show items in this file
Packit 1c1d7e
    {
Packit 1c1d7e
      bool firstChild=TRUE;
Packit 1c1d7e
      t << indentStr << "  [ ";
Packit 1c1d7e
      generateJSLink(t,n);
Packit 1c1d7e
      bool emptySection = !generateJSTree(navIndex,t,n->children,level+1,firstChild);
Packit 1c1d7e
      if (emptySection)
Packit 1c1d7e
        t << "null ]";
Packit 1c1d7e
      else
Packit 1c1d7e
        t << endl << indentStr << "  ] ]";
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  return found;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
static void generateJSNavTree(const QList<FTVNode> &nodeList)
Packit 1c1d7e
{
Packit 1c1d7e
  QCString htmlOutput = Config_getString(HTML_OUTPUT);
Packit 1c1d7e
  QFile f(htmlOutput+"/navtreedata.js");
Packit 1c1d7e
  NavIndexEntryList navIndex;
Packit 1c1d7e
  if (f.open(IO_WriteOnly) /*&& fidx.open(IO_WriteOnly)*/)
Packit 1c1d7e
  {
Packit 1c1d7e
    //FTextStream tidx(&fidx);
Packit 1c1d7e
    //tidx << "var NAVTREEINDEX =" << endl;
Packit 1c1d7e
    //tidx << "{" << endl;
Packit 1c1d7e
    FTextStream t(&f);
Packit 1c1d7e
		t << "/*\n@ @licstart  The following is the entire license notice for the\n"
Packit 1c1d7e
			"JavaScript code in this file.\n\nCopyright (C) 1997-2017 by Dimitri van Heesch\n\n"
Packit 1c1d7e
			"This program is free software; you can redistribute it and/or modify\n"
Packit 1c1d7e
			"it under the terms of the GNU General Public License as published by\n"
Packit 1c1d7e
			"the Free Software Foundation; either version 2 of the License, or\n"
Packit 1c1d7e
			"(at your option) any later version.\n\n"
Packit 1c1d7e
			"This program is distributed in the hope that it will be useful,\n"
Packit 1c1d7e
			"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit 1c1d7e
			" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit 1c1d7e
			" GNU General Public License for more details.\n\n"
Packit 1c1d7e
			"You should have received a copy of the GNU General Public License along\n"
Packit 1c1d7e
			"with this program; if not, write to the Free Software Foundation, Inc.,\n"
Packit 1c1d7e
			"51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n"
Packit 1c1d7e
			"@licend  The above is the entire license notice\n"
Packit 1c1d7e
			"for the JavaScript code in this file\n"
Packit 1c1d7e
			"*/\n";
Packit 1c1d7e
    t << "var NAVTREE =" << endl;
Packit 1c1d7e
    t << "[" << endl;
Packit 1c1d7e
    t << "  [ ";
Packit 1c1d7e
    QCString &projName = Config_getString(PROJECT_NAME);
Packit 1c1d7e
    if (projName.isEmpty())
Packit 1c1d7e
    {
Packit 1c1d7e
      if (Doxygen::mainPage && !Doxygen::mainPage->title().isEmpty()) // Use title of main page as root
Packit 1c1d7e
      {
Packit 1c1d7e
        t << "\"" << convertToJSString(Doxygen::mainPage->title()) << "\", ";
Packit 1c1d7e
      }
Packit 1c1d7e
      else // Use default section title as root
Packit 1c1d7e
      {
Packit 1c1d7e
        LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::MainPage);
Packit 1c1d7e
        t << "\"" << convertToJSString(lne->title()) << "\", ";
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
    else // use PROJECT_NAME as root tree element
Packit 1c1d7e
    {
Packit 1c1d7e
      t << "\"" << convertToJSString(projName) << "\", ";
Packit 1c1d7e
    }
Packit 1c1d7e
    t << "\"index" << Doxygen::htmlFileExtension << "\", ";
Packit 1c1d7e
Packit 1c1d7e
    // add special entry for index page
Packit 1c1d7e
    navIndex.append(new NavIndexEntry("index"+Doxygen::htmlFileExtension,""));
Packit 1c1d7e
    // related page index is written as a child of index.html, so add this as well
Packit 1c1d7e
    navIndex.append(new NavIndexEntry("pages"+Doxygen::htmlFileExtension,""));
Packit 1c1d7e
Packit 1c1d7e
    bool first=TRUE;
Packit 1c1d7e
    generateJSTree(navIndex,t,nodeList,1,first);
Packit 1c1d7e
Packit 1c1d7e
    if (first)
Packit 1c1d7e
      t << "]" << endl;
Packit 1c1d7e
    else
Packit 1c1d7e
      t << endl << "  ] ]" << endl;
Packit 1c1d7e
    t << "];" << endl << endl;
Packit 1c1d7e
Packit 1c1d7e
    // write the navigation index (and sub-indices)
Packit 1c1d7e
    navIndex.sort();
Packit 1c1d7e
    int subIndex=0;
Packit 1c1d7e
    int elemCount=0;
Packit 1c1d7e
    const int maxElemCount=250;
Packit 1c1d7e
    //QFile fidx(htmlOutput+"/navtreeindex.js");
Packit 1c1d7e
    QFile fsidx(htmlOutput+"/navtreeindex0.js");
Packit 1c1d7e
    if (/*fidx.open(IO_WriteOnly) &&*/ fsidx.open(IO_WriteOnly))
Packit 1c1d7e
    {
Packit 1c1d7e
      //FTextStream tidx(&fidx);
Packit 1c1d7e
      FTextStream tsidx(&fsidx);
Packit 1c1d7e
      t << "var NAVTREEINDEX =" << endl;
Packit 1c1d7e
      t << "[" << endl;
Packit 1c1d7e
      tsidx << "var NAVTREEINDEX" << subIndex << " =" << endl;
Packit 1c1d7e
      tsidx << "{" << endl;
Packit 1c1d7e
      QListIterator<NavIndexEntry> li(navIndex);
Packit 1c1d7e
      NavIndexEntry *e;
Packit 1c1d7e
      bool first=TRUE;
Packit 1c1d7e
      for (li.toFirst();(e=li.current());) // for each entry
Packit 1c1d7e
      {
Packit 1c1d7e
        if (elemCount==0)
Packit 1c1d7e
        {
Packit 1c1d7e
          if (!first)
Packit 1c1d7e
          {
Packit 1c1d7e
            t << "," << endl;
Packit 1c1d7e
          }
Packit 1c1d7e
          else
Packit 1c1d7e
          {
Packit 1c1d7e
            first=FALSE;
Packit 1c1d7e
          }
Packit 1c1d7e
          t << "\"" << e->url << "\"";
Packit 1c1d7e
        }
Packit 1c1d7e
        tsidx << "\"" << e->url << "\":[" << e->path << "]";
Packit 1c1d7e
        ++li;
Packit 1c1d7e
        if (li.current() && elemCount
Packit 1c1d7e
        tsidx << endl;
Packit 1c1d7e
Packit 1c1d7e
        elemCount++;
Packit 1c1d7e
        if (li.current() && elemCount>=maxElemCount) // switch to new sub-index
Packit 1c1d7e
        {
Packit 1c1d7e
          tsidx << "};" << endl;
Packit 1c1d7e
          elemCount=0;
Packit 1c1d7e
          fsidx.close();
Packit 1c1d7e
          subIndex++;
Packit 1c1d7e
          fsidx.setName(htmlOutput+"/navtreeindex"+QCString().setNum(subIndex)+".js");
Packit 1c1d7e
          if (!fsidx.open(IO_WriteOnly)) break;
Packit 1c1d7e
          tsidx.setDevice(&fsidx);
Packit 1c1d7e
          tsidx << "var NAVTREEINDEX" << subIndex << " =" << endl;
Packit 1c1d7e
          tsidx << "{" << endl;
Packit 1c1d7e
        }
Packit 1c1d7e
      }
Packit 1c1d7e
      tsidx << "};" << endl;
Packit 1c1d7e
      t << endl << "];" << endl;
Packit 1c1d7e
    }
Packit 1c1d7e
    t << endl << "var SYNCONMSG = '"  << theTranslator->trPanelSynchronisationTooltip(FALSE) << "';";
Packit 1c1d7e
    t << endl << "var SYNCOFFMSG = '" << theTranslator->trPanelSynchronisationTooltip(TRUE)  << "';";
Packit 1c1d7e
  }
Packit 1c1d7e
  ResourceMgr::instance().copyResource("navtree.js",htmlOutput);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
//-----------------------------------------------------------
Packit 1c1d7e
Packit 1c1d7e
// new style images
Packit 1c1d7e
void FTVHelp::generateTreeViewImages()
Packit 1c1d7e
{
Packit 1c1d7e
  QCString dname=Config_getString(HTML_OUTPUT);
Packit 1c1d7e
  const ResourceMgr &rm = ResourceMgr::instance();
Packit 1c1d7e
  rm.copyResource("doc.luma",dname);
Packit 1c1d7e
  rm.copyResource("folderopen.luma",dname);
Packit 1c1d7e
  rm.copyResource("folderclosed.luma",dname);
Packit 1c1d7e
  rm.copyResource("splitbar.lum",dname);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
// new style scripts
Packit 1c1d7e
void FTVHelp::generateTreeViewScripts()
Packit 1c1d7e
{
Packit 1c1d7e
  QCString htmlOutput = Config_getString(HTML_OUTPUT);
Packit 1c1d7e
Packit 1c1d7e
  // generate navtree.js & navtreeindex.js
Packit 1c1d7e
  generateJSNavTree(m_indentNodes[0]);
Packit 1c1d7e
Packit 1c1d7e
  // copy resize.js & navtree.css
Packit 1c1d7e
  ResourceMgr::instance().copyResource("resize.js",htmlOutput);
Packit 1c1d7e
  ResourceMgr::instance().copyResource("navtree.css",htmlOutput);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
// write tree inside page
Packit 1c1d7e
void FTVHelp::generateTreeViewInline(FTextStream &t)
Packit 1c1d7e
{
Packit 1c1d7e
  int preferredNumEntries = Config_getInt(HTML_INDEX_NUM_ENTRIES);
Packit 1c1d7e
  t << "
\n";
Packit 1c1d7e
  QListIterator<FTVNode> li(m_indentNodes[0]);
Packit 1c1d7e
  FTVNode *n;
Packit 1c1d7e
  int d=1, depth=1;
Packit 1c1d7e
  for (;(n=li.current());++li)
Packit 1c1d7e
  {
Packit 1c1d7e
    if (n->children.count()>0)
Packit 1c1d7e
    {
Packit 1c1d7e
      d = n->computeTreeDepth(2);
Packit 1c1d7e
      if (d>depth) depth=d;
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  int preferredDepth = depth;
Packit 1c1d7e
  // write level selector
Packit 1c1d7e
  if (depth>1)
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "
[";
Packit 1c1d7e
    t << theTranslator->trDetailLevel();
Packit 1c1d7e
    t << " ";
Packit 1c1d7e
    int i;
Packit 1c1d7e
    for (i=1;i<=depth;i++)
Packit 1c1d7e
    {
Packit 1c1d7e
      t << "" << i << "";
Packit 1c1d7e
    }
Packit 1c1d7e
    t << "]";
Packit 1c1d7e
Packit 1c1d7e
    if (preferredNumEntries>0)
Packit 1c1d7e
    {
Packit 1c1d7e
      preferredDepth=1;
Packit 1c1d7e
      for (int i=1;i<=depth;i++)
Packit 1c1d7e
      {
Packit 1c1d7e
        int num=0;
Packit 1c1d7e
        QListIterator<FTVNode> li(m_indentNodes[0]);
Packit 1c1d7e
        FTVNode *n;
Packit 1c1d7e
        for (;(n=li.current());++li)
Packit 1c1d7e
        {
Packit 1c1d7e
          num+=n->numNodesAtLevel(0,i);
Packit 1c1d7e
        }
Packit 1c1d7e
        if (num<=preferredNumEntries)
Packit 1c1d7e
        {
Packit 1c1d7e
          preferredDepth=i;
Packit 1c1d7e
        }
Packit 1c1d7e
        else
Packit 1c1d7e
        {
Packit 1c1d7e
          break;
Packit 1c1d7e
        }
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  //printf("preferred depth=%d\n",preferredDepth);
Packit 1c1d7e
Packit 1c1d7e
  t << "\n";
Packit 1c1d7e
  int index=0;
Packit 1c1d7e
  generateTree(t,m_indentNodes[0],0,preferredDepth,index);
Packit 1c1d7e
  t << "\n";
Packit 1c1d7e
Packit 1c1d7e
  t << "\n";
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
// write old style index.html and tree.html
Packit 1c1d7e
void FTVHelp::generateTreeView()
Packit 1c1d7e
{
Packit 1c1d7e
  generateTreeViewImages();
Packit 1c1d7e
  generateTreeViewScripts();
Packit 1c1d7e
}