e5760592e8e644d1ce170da825e49c76151774f6
[platform/upstream/doxygen.git] / src / htmlgen.cpp
1 /******************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby
9  * granted. No representations are made about the suitability of this software
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 #include <stdlib.h>
19
20 #include <qdir.h>
21 #include <qregexp.h>
22 #include "message.h"
23 #include "htmlgen.h"
24 #include "config.h"
25 #include "util.h"
26 #include "doxygen.h"
27 #include "logos.h"
28 #include "diagram.h"
29 #include "version.h"
30 #include "dot.h"
31 #include "language.h"
32 #include "htmlhelp.h"
33 #include "docparser.h"
34 #include "htmldocvisitor.h"
35 #include "searchindex.h"
36 #include "pagedef.h"
37 #include "debug.h"
38 #include "dirdef.h"
39 #include "vhdldocgen.h"
40 #include "layout.h"
41 #include "image.h"
42 #include "ftvhelp.h"
43 #include "bufstr.h"
44 #include "resourcemgr.h"
45
46
47 //#define DBG_HTML(x) x;
48 #define DBG_HTML(x)
49
50 static QCString g_header;
51 static QCString g_footer;
52 static QCString g_mathjax_code;
53
54
55 // note: this is only active if DISABLE_INDEX=YES, if DISABLE_INDEX is disabled, this
56 // part will be rendered inside menu.js
57 static void writeClientSearchBox(FTextStream &t,const char *relPath)
58 {
59   t << "        <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n";
60   t << "        <span class=\"left\">\n";
61   t << "          <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag_sel.png\"\n";
62   t << "               onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
63   t << "               onmouseout=\"return searchBox.OnSearchSelectHide()\"\n";
64   t << "               alt=\"\"/>\n";
65   t << "          <input type=\"text\" id=\"MSearchField\" value=\""
66     << theTranslator->trSearch() << "\" accesskey=\"S\"\n";
67   t << "               onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
68   t << "               onblur=\"searchBox.OnSearchFieldFocus(false)\" \n";
69   t << "               onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n";
70   t << "          </span><span class=\"right\">\n";
71   t << "            <a id=\"MSearchClose\" href=\"javascript:searchBox.CloseResultsWindow()\">"
72     << "<img id=\"MSearchCloseImg\" border=\"0\" src=\"" << relPath << "search/close.png\" alt=\"\"/></a>\n";
73   t << "          </span>\n";
74   t << "        </div>\n";
75 }
76
77 // note: this is only active if DISABLE_INDEX=YES. if DISABLE_INDEX is disabled, this
78 // part will be rendered inside menu.js
79 static void writeServerSearchBox(FTextStream &t,const char *relPath,bool highlightSearch)
80 {
81   static bool externalSearch = Config_getBool(EXTERNAL_SEARCH);
82   t << "        <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n";
83   t << "          <div class=\"left\">\n";
84   t << "            <form id=\"FSearchBox\" action=\"" << relPath;
85   if (externalSearch)
86   {
87     t << "search" << Doxygen::htmlFileExtension;
88   }
89   else
90   {
91     t << "search.php";
92   }
93   t << "\" method=\"get\">\n";
94   t << "              <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag.png\" alt=\"\"/>\n";
95   if (!highlightSearch)
96   {
97     t << "              <input type=\"text\" id=\"MSearchField\" name=\"query\" value=\""
98       << theTranslator->trSearch() << "\" size=\"20\" accesskey=\"S\" \n";
99     t << "                     onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n";
100     t << "                     onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n";
101     t << "            </form>\n";
102     t << "          </div><div class=\"right\"></div>\n";
103     t << "        </div>\n";
104   }
105 }
106
107 //------------------------------------------------------------------------
108
109 /// Clear a text block \a s from \a begin to \a end markers
110 QCString clearBlock(const char *s,const char *begin,const char *end)
111 {
112   if (s==0 || begin==0 || end==0) return s;
113   const char *p, *q;
114   int beginLen = qstrlen(begin);
115   int endLen = qstrlen(end);
116   int resLen = 0;
117   for (p=s; (q=strstr(p,begin))!=0; p=q+endLen)
118   {
119     resLen+=(int)(q-p);
120     p=q+beginLen;
121     if ((q=strstr(p,end))==0)
122     {
123       resLen+=beginLen;
124       break;
125     }
126   }
127   resLen+=qstrlen(p);
128   // resLen is the length of the string without the marked block
129
130   QCString result(resLen+1);
131   char *r;
132   for (r=result.rawData(), p=s; (q=strstr(p,begin))!=0; p=q+endLen)
133   {
134     int l = (int)(q-p);
135     memcpy(r,p,l);
136     r+=l;
137     p=q+beginLen;
138     if ((q=strstr(p,end))==0)
139     {
140       memcpy(r,begin,beginLen);
141       r+=beginLen;
142       break;
143     }
144   }
145   qstrcpy(r,p);
146   return result;
147 }
148 //----------------------------------------------------------------------
149
150 QCString selectBlock(const QCString& s,const QCString &name,bool enable)
151 {
152   // TODO: this is an expensive function that is called a lot -> optimize it
153   const QCString begin = "<!--BEGIN " + name + "-->";
154   const QCString end = "<!--END " + name + "-->";
155   const QCString nobegin = "<!--BEGIN !" + name + "-->";
156   const QCString noend = "<!--END !" + name + "-->";
157
158   QCString result = s;
159   if (enable)
160   {
161     result = substitute(result, begin, "");
162     result = substitute(result, end, "");
163     result = clearBlock(result, nobegin, noend);
164   }
165   else
166   {
167     result = substitute(result, nobegin, "");
168     result = substitute(result, noend, "");
169     result = clearBlock(result, begin, end);
170   }
171
172   return result;
173 }
174
175 static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch)
176 {
177   QGString result;
178   FTextStream t(&result);
179   if (serverSide)
180   {
181     writeServerSearchBox(t, relPath, highlightSearch);
182   }
183   else
184   {
185     writeClientSearchBox(t, relPath);
186   }
187   return QCString(result);
188 }
189
190 static QCString removeEmptyLines(const QCString &s)
191 {
192   BufStr out(s.length()+1);
193   const char *p=s.data();
194   if (p)
195   {
196     char c;
197     while ((c=*p++))
198     {
199       if (c=='\n')
200       {
201         const char *e = p;
202         while (*e==' ' || *e=='\t') e++;
203         if (*e=='\n')
204         {
205           p=e;
206         }
207         else out.addChar(c);
208       }
209       else
210       {
211         out.addChar(c);
212       }
213     }
214   }
215   out.addChar('\0');
216   //printf("removeEmptyLines(%s)=%s\n",s.data(),out.data());
217   return out.data();
218 }
219
220 static QCString substituteHtmlKeywords(const QCString &s,
221                                        const QCString &title,
222                                        const QCString &relPath,
223                                        const QCString &navPath=QCString())
224 {
225   // Build CSS/Javascript tags depending on treeview, search engine settings
226   QCString cssFile;
227   QStrList extraCssFile;
228   QCString generatedBy;
229   QCString treeViewCssJs;
230   QCString searchCssJs;
231   QCString searchBox;
232   QCString mathJaxJs;
233   QCString extraCssText;
234
235   static QCString projectName = Config_getString(PROJECT_NAME);
236   static bool timeStamp = Config_getBool(HTML_TIMESTAMP);
237   static bool treeView = Config_getBool(GENERATE_TREEVIEW);
238   static bool searchEngine = Config_getBool(SEARCHENGINE);
239   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
240   static bool mathJax = Config_getBool(USE_MATHJAX);
241   static QCString mathJaxFormat = Config_getEnum(MATHJAX_FORMAT);
242   static bool disableIndex = Config_getBool(DISABLE_INDEX);
243   static bool hasProjectName = !projectName.isEmpty();
244   static bool hasProjectNumber = !Config_getString(PROJECT_NUMBER).isEmpty();
245   static bool hasProjectBrief = !Config_getString(PROJECT_BRIEF).isEmpty();
246   static bool hasProjectLogo = !Config_getString(PROJECT_LOGO).isEmpty();
247   static bool titleArea = (hasProjectName || hasProjectBrief || hasProjectLogo || (disableIndex && searchEngine));
248
249   cssFile = Config_getString(HTML_STYLESHEET);
250   if (cssFile.isEmpty())
251   {
252     cssFile = "doxygen.css";
253   }
254   else
255   {
256     QFileInfo cssfi(cssFile);
257     if (cssfi.exists())
258     {
259       cssFile = cssfi.fileName().utf8();
260     }
261     else
262     {
263       cssFile = "doxygen.css";
264     }
265   }
266
267   extraCssText = "";
268   extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET);
269   for (uint i=0; i<extraCssFile.count(); ++i)
270   {
271     QCString fileName(extraCssFile.at(i));
272     if (!fileName.isEmpty())
273     {
274       QFileInfo fi(fileName);
275       if (fi.exists())
276       {
277         extraCssText += "<link href=\"$relpath^"+stripPath(fileName)+"\" rel=\"stylesheet\" type=\"text/css\"/>\n";
278       }
279     }
280   }
281
282   if (timeStamp)
283   {
284     generatedBy = theTranslator->trGeneratedAt(dateToString(TRUE), convertToHtml(Config_getString(PROJECT_NAME)));
285   }
286   else
287   {
288     generatedBy = theTranslator->trGeneratedBy();
289   }
290
291   if (treeView)
292   {
293     treeViewCssJs = "<link href=\"$relpath^navtree.css\" rel=\"stylesheet\" type=\"text/css\"/>\n"
294                         "<script type=\"text/javascript\" src=\"$relpath^resize.js\"></script>\n"
295                         "<script type=\"text/javascript\" src=\"$relpath^navtreedata.js\"></script>\n"
296                         "<script type=\"text/javascript\" src=\"$relpath^navtree.js\"></script>\n"
297                         "<script type=\"text/javascript\">\n"
298                         "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n"
299                         "  $(document).ready(initResizable);\n"
300                         "/* @license-end */"
301                         "</script>";
302   }
303
304   if (searchEngine)
305   {
306     searchCssJs = "<link href=\"$relpath^search/search.css\" rel=\"stylesheet\" type=\"text/css\"/>\n";
307     if (!serverBasedSearch)
308     {
309       searchCssJs += "<script type=\"text/javascript\" src=\"$relpath^search/searchdata.js\"></script>\n";
310     }
311     searchCssJs += "<script type=\"text/javascript\" src=\"$relpath^search/search.js\"></script>\n";
312
313     if (!serverBasedSearch)
314     {
315       if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS))
316       {
317         searchCssJs += "<script type=\"text/javascript\">\n"
318                                         "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n"
319                                 "  $(document).ready(function() { init_search(); });\n"
320                                         "/* @license-end */\n"
321                                         "</script>";
322       }
323     }
324     else
325     {
326       if (disableIndex || !Config_getBool(HTML_DYNAMIC_MENUS))
327       {
328         searchCssJs += "<script type=\"text/javascript\">\n"
329                                         "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n"
330                                         "  $(document).ready(function() {\n"
331                                         "    if ($('.searchresults').length > 0) { searchBox.DOMSearchField().focus(); }\n"
332                                         "  });\n"
333                                         "  /* @license-end */\n"
334                                         "</script>\n";
335       }
336
337       // OPENSEARCH_PROVIDER {
338       searchCssJs += "<link rel=\"search\" href=\"" + relPath +
339                      "search_opensearch.php?v=opensearch.xml\" "
340                      "type=\"application/opensearchdescription+xml\" title=\"" +
341                      (hasProjectName ? projectName : QCString("Doxygen")) +
342                      "\"/>";
343       // OPENSEARCH_PROVIDER }
344     }
345     searchBox = getSearchBox(serverBasedSearch, relPath, FALSE);
346   }
347
348   if (mathJax)
349   {
350     QCString path = Config_getString(MATHJAX_RELPATH);
351     if (path.isEmpty() || path.left(2)=="..") // relative path
352     {
353       path.prepend(relPath);
354     }
355     mathJaxJs = "<script type=\"text/x-mathjax-config\">\n"
356                 "  MathJax.Hub.Config({\n"
357                 "    extensions: [\"tex2jax.js\"";
358     QStrList &mathJaxExtensions = Config_getList(MATHJAX_EXTENSIONS);
359     const char *s = mathJaxExtensions.first();
360     while (s)
361     {
362       mathJaxJs+= ", \""+QCString(s)+".js\"";
363       s = mathJaxExtensions.next();
364     }
365     if (mathJaxFormat.isEmpty())
366     {
367       mathJaxFormat = "HTML-CSS";
368     }
369     mathJaxJs += "],\n"
370                  "    jax: [\"input/TeX\",\"output/"+mathJaxFormat+"\"],\n"
371                  "});\n";
372     if (!g_mathjax_code.isEmpty())
373     {
374       mathJaxJs += g_mathjax_code;
375       mathJaxJs += "\n";
376     }
377     mathJaxJs += "</script>";
378     mathJaxJs += "<script type=\"text/javascript\" async src=\"" + path + "MathJax.js\"></script>\n";
379   }
380
381   // first substitute generic keywords
382   QCString result = substituteKeywords(s,title,
383         convertToHtml(Config_getString(PROJECT_NAME)),
384         convertToHtml(Config_getString(PROJECT_NUMBER)),
385         convertToHtml(Config_getString(PROJECT_BRIEF)));
386
387   // additional HTML only keywords
388   result = substitute(result,"$navpath",navPath);
389   result = substitute(result,"$stylesheet",cssFile);
390   result = substitute(result,"$treeview",treeViewCssJs);
391   result = substitute(result,"$searchbox",searchBox);
392   result = substitute(result,"$search",searchCssJs);
393   result = substitute(result,"$mathjax",mathJaxJs);
394   result = substitute(result,"$generatedby",generatedBy);
395   result = substitute(result,"$extrastylesheet",extraCssText);
396   result = substitute(result,"$relpath$",relPath); //<-- obsolete: for backwards compatibility only
397   result = substitute(result,"$relpath^",relPath); //<-- must be last
398
399   // additional HTML only conditional blocks
400   result = selectBlock(result,"DISABLE_INDEX",disableIndex);
401   result = selectBlock(result,"GENERATE_TREEVIEW",treeView);
402   result = selectBlock(result,"SEARCHENGINE",searchEngine);
403   result = selectBlock(result,"TITLEAREA",titleArea);
404   result = selectBlock(result,"PROJECT_NAME",hasProjectName);
405   result = selectBlock(result,"PROJECT_NUMBER",hasProjectNumber);
406   result = selectBlock(result,"PROJECT_BRIEF",hasProjectBrief);
407   result = selectBlock(result,"PROJECT_LOGO",hasProjectLogo);
408
409   result = removeEmptyLines(result);
410
411   return result;
412 }
413
414 //--------------------------------------------------------------------------
415
416 HtmlCodeGenerator::HtmlCodeGenerator()
417    : m_streamSet(FALSE), m_col(0)
418 {
419 }
420
421 HtmlCodeGenerator::HtmlCodeGenerator(FTextStream &t,const QCString &relPath)
422    : m_col(0), m_relPath(relPath)
423 {
424   setTextStream(t);
425 }
426
427 void HtmlCodeGenerator::setTextStream(FTextStream &t)
428 {
429   m_streamSet = t.device()!=0;
430   m_t.setDevice(t.device());
431 }
432
433 void HtmlCodeGenerator::setRelativePath(const QCString &path)
434 {
435   m_relPath = path;
436 }
437
438 void HtmlCodeGenerator::codify(const char *str)
439 {
440   static int tabSize = Config_getInt(TAB_SIZE);
441   if (str && m_streamSet)
442   {
443     const char *p=str;
444     char c;
445     int spacesToNextTabStop;
446     while (*p)
447     {
448       c=*p++;
449       switch(c)
450       {
451         case '\t': spacesToNextTabStop =
452                          tabSize - (m_col%tabSize);
453                    m_t << Doxygen::spaces.left(spacesToNextTabStop);
454                    m_col+=spacesToNextTabStop;
455                    break;
456         case '\n': m_t << "\n"; m_col=0;
457                    break;
458         case '\r': break;
459         case '<':  m_t << "&lt;"; m_col++;
460                    break;
461         case '>':  m_t << "&gt;"; m_col++;
462                    break;
463         case '&':  m_t << "&amp;"; m_col++;
464                    break;
465         case '\'': m_t << "&#39;"; m_col++; // &apos; is not valid XHTML
466                    break;
467         case '"':  m_t << "&quot;"; m_col++;
468                    break;
469         case '\\':
470                    if (*p=='<')
471                      { m_t << "&lt;"; p++; }
472                    else if (*p=='>')
473                      { m_t << "&gt;"; p++; }
474                    else
475                      m_t << "\\";
476                    m_col++;
477                    break;
478         default:   p=writeUtf8Char(m_t,p-1);
479                    m_col++;
480                    break;
481       }
482     }
483   }
484 }
485
486 void HtmlCodeGenerator::docify(const char *str)
487 {
488   if (str && m_streamSet)
489   {
490     const char *p=str;
491     char c;
492     while (*p)
493     {
494       c=*p++;
495       switch(c)
496       {
497         case '<':  m_t << "&lt;"; break;
498         case '>':  m_t << "&gt;"; break;
499         case '&':  m_t << "&amp;"; break;
500         case '"':  m_t << "&quot;"; break;
501         case '\\':
502                    if (*p=='<')
503                      { m_t << "&lt;"; p++; }
504                    else if (*p=='>')
505                      { m_t << "&gt;"; p++; }
506                    else
507                      m_t << "\\";
508                    break;
509         default:   m_t << c;
510       }
511     }
512   }
513 }
514
515 void HtmlCodeGenerator::writeLineNumber(const char *ref,const char *filename,
516                                     const char *anchor,int l)
517 {
518   if (!m_streamSet) return;
519   const int maxLineNrStr = 10;
520   char lineNumber[maxLineNrStr];
521   char lineAnchor[maxLineNrStr];
522   qsnprintf(lineNumber,maxLineNrStr,"%5d",l);
523   qsnprintf(lineAnchor,maxLineNrStr,"l%05d",l);
524
525   m_t << "<div class=\"line\">";
526   m_t << "<a name=\"" << lineAnchor << "\"></a><span class=\"lineno\">";
527   if (filename)
528   {
529     _writeCodeLink("line",ref,filename,anchor,lineNumber,0);
530   }
531   else
532   {
533     codify(lineNumber);
534   }
535   m_t << "</span>";
536   m_t << "&#160;";
537 }
538
539 void HtmlCodeGenerator::writeCodeLink(const char *ref,const char *f,
540                                       const char *anchor, const char *name,
541                                       const char *tooltip)
542 {
543   if (!m_streamSet) return;
544   //printf("writeCodeLink(ref=%s,f=%s,anchor=%s,name=%s,tooltip=%s)\n",ref,f,anchor,name,tooltip);
545   _writeCodeLink("code",ref,f,anchor,name,tooltip);
546 }
547
548 void HtmlCodeGenerator::_writeCodeLink(const char *className,
549                                       const char *ref,const char *f,
550                                       const char *anchor, const char *name,
551                                       const char *tooltip)
552 {
553   if (ref)
554   {
555     m_t << "<a class=\"" << className << "Ref\" ";
556     m_t << externalLinkTarget() << externalRef(m_relPath,ref,FALSE);
557   }
558   else
559   {
560     m_t << "<a class=\"" << className << "\" ";
561   }
562   m_t << "href=\"";
563   m_t << externalRef(m_relPath,ref,TRUE);
564   if (f) m_t << f << Doxygen::htmlFileExtension;
565   if (anchor) m_t << "#" << anchor;
566   m_t << "\"";
567   if (tooltip) m_t << " title=\"" << convertToHtml(tooltip) << "\"";
568   m_t << ">";
569   docify(name);
570   m_t << "</a>";
571   m_col+=qstrlen(name);
572 }
573
574 void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo,
575                                      const char *decl, const char *desc,
576                                      const SourceLinkInfo &defInfo,
577                                      const SourceLinkInfo &declInfo)
578 {
579   m_t << "<div class=\"ttc\" id=\"" << id << "\">";
580   m_t << "<div class=\"ttname\">";
581   if (!docInfo.url.isEmpty())
582   {
583     m_t << "<a href=\"";
584     m_t << externalRef(m_relPath,docInfo.ref,TRUE);
585     m_t << docInfo.url << Doxygen::htmlFileExtension;
586     if (!docInfo.anchor.isEmpty())
587     {
588       m_t << "#" << docInfo.anchor;
589     }
590     m_t << "\">";
591   }
592   docify(docInfo.name);
593   if (!docInfo.url.isEmpty())
594   {
595     m_t << "</a>";
596   }
597   m_t << "</div>";
598   if (decl)
599   {
600     m_t << "<div class=\"ttdeci\">";
601     docify(decl);
602     m_t << "</div>";
603   }
604   if (desc)
605   {
606     m_t << "<div class=\"ttdoc\">";
607     docify(desc); // desc is already HTML escaped; but there are still < and > signs
608     m_t << "</div>";
609   }
610   if (!defInfo.file.isEmpty())
611   {
612     m_t << "<div class=\"ttdef\"><b>Definition:</b> ";
613     if (!defInfo.url.isEmpty())
614     {
615       m_t << "<a href=\"";
616       m_t << externalRef(m_relPath,defInfo.ref,TRUE);
617       m_t << defInfo.url << Doxygen::htmlFileExtension;
618       if (!defInfo.anchor.isEmpty())
619       {
620         m_t << "#" << defInfo.anchor;
621       }
622       m_t << "\">";
623     }
624     m_t << defInfo.file << ":" << defInfo.line;
625     if (!defInfo.url.isEmpty())
626     {
627       m_t << "</a>";
628     }
629     m_t << "</div>";
630   }
631   if (!declInfo.file.isEmpty())
632   {
633     m_t << "<div class=\"ttdecl\"><b>Declaration:</b> ";
634     if (!declInfo.url.isEmpty())
635     {
636       m_t << "<a href=\"";
637       m_t << externalRef(m_relPath,declInfo.ref,TRUE);
638       m_t << declInfo.url << Doxygen::htmlFileExtension;
639       if (!declInfo.anchor.isEmpty())
640       {
641         m_t << "#" << declInfo.anchor;
642       }
643       m_t << "\">";
644     }
645     m_t << declInfo.file << ":" << declInfo.line;
646     if (!declInfo.url.isEmpty())
647     {
648       m_t << "</a>";
649     }
650     m_t << "</div>";
651   }
652   m_t << "</div>" << endl;
653 }
654
655
656 void HtmlCodeGenerator::startCodeLine(bool hasLineNumbers)
657 {
658   if (m_streamSet)
659   {
660     if (!hasLineNumbers) m_t << "<div class=\"line\">";
661     m_col=0;
662   }
663 }
664
665 void HtmlCodeGenerator::endCodeLine()
666 {
667   if (m_streamSet) m_t << "</div>";
668 }
669
670 void HtmlCodeGenerator::startFontClass(const char *s)
671 {
672   if (m_streamSet) m_t << "<span class=\"" << s << "\">";
673 }
674
675 void HtmlCodeGenerator::endFontClass()
676 {
677   if (m_streamSet) m_t << "</span>";
678 }
679
680 void HtmlCodeGenerator::writeCodeAnchor(const char *anchor)
681 {
682   if (m_streamSet) m_t << "<a name=\"" << anchor << "\"></a>";
683 }
684
685 //--------------------------------------------------------------------------
686
687 HtmlGenerator::HtmlGenerator() : OutputGenerator()
688 {
689   dir=Config_getString(HTML_OUTPUT);
690   m_emptySection=FALSE;
691 }
692
693 HtmlGenerator::~HtmlGenerator()
694 {
695   //printf("HtmlGenerator::~HtmlGenerator()\n");
696 }
697
698 void HtmlGenerator::init()
699 {
700   QCString dname=Config_getString(HTML_OUTPUT);
701   QDir d(dname);
702   if (!d.exists() && !d.mkdir(dname))
703   {
704     err("Could not create output directory %s\n",dname.data());
705     exit(1);
706   }
707   //writeLogo(dname);
708   if (!Config_getString(HTML_HEADER).isEmpty())
709   {
710     g_header=fileToString(Config_getString(HTML_HEADER));
711     //printf("g_header='%s'\n",g_header.data());
712   }
713   else
714   {
715     g_header = ResourceMgr::instance().getAsString("header.html");
716   }
717
718   if (!Config_getString(HTML_FOOTER).isEmpty())
719   {
720     g_footer=fileToString(Config_getString(HTML_FOOTER));
721     //printf("g_footer='%s'\n",g_footer.data());
722   }
723   else
724   {
725     g_footer = ResourceMgr::instance().getAsString("footer.html");
726   }
727
728   if (Config_getBool(USE_MATHJAX))
729   {
730     if (!Config_getString(MATHJAX_CODEFILE).isEmpty())
731     {
732       g_mathjax_code=fileToString(Config_getString(MATHJAX_CODEFILE));
733       //printf("g_mathjax_code='%s'\n",g_mathjax_code.data());
734     }
735   }
736   createSubDirs(d);
737
738   ResourceMgr &mgr = ResourceMgr::instance();
739   if (Config_getBool(HTML_DYNAMIC_MENUS))
740   {
741     mgr.copyResourceAs("tabs.css",dname,"tabs.css");
742   }
743   else // stylesheet for the 'old' static tabs
744   {
745     mgr.copyResourceAs("fixed_tabs.css",dname,"tabs.css");
746   }
747   mgr.copyResource("jquery.js",dname);
748   if (Config_getBool(INTERACTIVE_SVG))
749   {
750     mgr.copyResource("svgpan.js",dname);
751   }
752   if (!Config_getBool(DISABLE_INDEX) && Config_getBool(HTML_DYNAMIC_MENUS))
753   {
754     mgr.copyResource("menu.js",dname);
755   }
756
757   {
758     QFile f(dname+"/dynsections.js");
759     if (f.open(IO_WriteOnly))
760     {
761       FTextStream t(&f);
762       t << mgr.getAsString("dynsections.js");
763       if (Config_getBool(SOURCE_BROWSER) && Config_getBool(SOURCE_TOOLTIPS))
764       {
765         t << endl <<
766           "$(document).ready(function() {\n"
767           "  $('.code,.codeRef').each(function() {\n"
768           "    $(this).data('powertip',$('#'+$(this).attr('href').replace(/.*\\//,'').replace(/[^a-z_A-Z0-9]/g,'_')).html());\n"
769           "    $(this).powerTip({ placement: 's', smartPlacement: true, mouseOnToPopup: true });\n"
770           "  });\n"
771           "});\n";
772       }
773     }
774   }
775 }
776
777 /// Additional initialization after indices have been created
778 void HtmlGenerator::writeTabData()
779 {
780   Doxygen::indexList->addStyleSheetFile("tabs.css");
781   QCString dname=Config_getString(HTML_OUTPUT);
782   ResourceMgr &mgr = ResourceMgr::instance();
783   //writeColoredImgData(dname,colored_tab_data);
784   mgr.copyResource("tab_a.lum",dname);
785   mgr.copyResource("tab_b.lum",dname);
786   mgr.copyResource("tab_h.lum",dname);
787   mgr.copyResource("tab_s.lum",dname);
788   mgr.copyResource("nav_h.lum",dname);
789   mgr.copyResource("nav_f.lum",dname);
790   mgr.copyResource("bc_s.luma",dname);
791   mgr.copyResource("doxygen.luma",dname);
792   mgr.copyResource("closed.luma",dname);
793   mgr.copyResource("open.luma",dname);
794   mgr.copyResource("bdwn.luma",dname);
795   mgr.copyResource("sync_on.luma",dname);
796   mgr.copyResource("sync_off.luma",dname);
797
798   //{
799   //  unsigned char shadow[6] = { 5, 5, 5, 5, 5, 5 };
800   //  unsigned char shadow_alpha[6]  = { 80, 60, 40, 20, 10, 0 };
801   //  ColoredImage img(1,6,shadow,shadow_alpha,0,0,100);
802   //  img.save(dname+"/nav_g.png");
803   //}
804   mgr.copyResource("nav_g.png",dname);
805 }
806
807 void HtmlGenerator::writeSearchData(const char *dir)
808 {
809   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
810   //writeImgData(dir,serverBasedSearch ? search_server_data : search_client_data);
811   ResourceMgr &mgr = ResourceMgr::instance();
812
813   mgr.copyResource("search_l.png",dir);
814   Doxygen::indexList->addImageFile("search/search_l.png");
815   mgr.copyResource("search_m.png",dir);
816   Doxygen::indexList->addImageFile("search/search_m.png");
817   mgr.copyResource("search_r.png",dir);
818   Doxygen::indexList->addImageFile("search/search_r.png");
819   if (serverBasedSearch)
820   {
821     mgr.copyResource("mag.png",dir);
822     Doxygen::indexList->addImageFile("search/mag.png");
823   }
824   else
825   {
826     mgr.copyResource("close.png",dir);
827     Doxygen::indexList->addImageFile("search/close.png");
828     mgr.copyResource("mag_sel.png",dir);
829     Doxygen::indexList->addImageFile("search/mag_sel.png");
830   }
831
832   QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
833   QFile f(searchDirName+"/search.css");
834   if (f.open(IO_WriteOnly))
835   {
836     FTextStream t(&f);
837     QCString searchCss;
838     if (Config_getBool(DISABLE_INDEX))
839     {
840       searchCss = mgr.getAsString("search_nomenu.css");
841     }
842     else if (!Config_getBool(HTML_DYNAMIC_MENUS))
843     {
844       searchCss = mgr.getAsString("search_fixedtabs.css");
845     }
846     else
847     {
848       searchCss = mgr.getAsString("search.css");
849     }
850     searchCss = substitute(replaceColorMarkers(searchCss),"$doxygenversion",versionString);
851     t << searchCss;
852     Doxygen::indexList->addStyleSheetFile("search/search.css");
853   }
854 }
855
856 void HtmlGenerator::writeStyleSheetFile(QFile &file)
857 {
858   FTextStream t(&file);
859   t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",versionString));
860 }
861
862 void HtmlGenerator::writeHeaderFile(QFile &file, const char * /*cssname*/)
863 {
864   FTextStream t(&file);
865   t << "<!-- HTML header for doxygen " << versionString << "-->" << endl;
866   t << ResourceMgr::instance().getAsString("header.html");
867 }
868
869 void HtmlGenerator::writeFooterFile(QFile &file)
870 {
871   FTextStream t(&file);
872   t << "<!-- HTML footer for doxygen " << versionString << "-->" <<  endl;
873   t << ResourceMgr::instance().getAsString("footer.html");
874 }
875
876 void HtmlGenerator::startFile(const char *name,const char *,
877                               const char *title)
878 {
879   //printf("HtmlGenerator::startFile(%s)\n",name);
880   QCString fileName=name;
881   lastTitle=title;
882   relPath = relativePathToRoot(fileName);
883
884   if (fileName.right(Doxygen::htmlFileExtension.length())!=Doxygen::htmlFileExtension)
885   {
886     fileName+=Doxygen::htmlFileExtension;
887   }
888   startPlainFile(fileName);
889   m_codeGen.setTextStream(t);
890   m_codeGen.setRelativePath(relPath);
891   Doxygen::indexList->addIndexFile(fileName);
892
893   lastFile = fileName;
894   t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),relPath);
895
896   t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
897     << versionString << " -->" << endl;
898   //static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
899   static bool searchEngine = Config_getBool(SEARCHENGINE);
900   if (searchEngine /*&& !generateTreeView*/)
901   {
902     t << "<script type=\"text/javascript\">\n";
903                 t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
904                 t << "var searchBox = new SearchBox(\"searchBox\", \""
905       << relPath<< "search\",false,'" << theTranslator->trSearch() << "');\n";
906                 t << "/* @license-end */\n";
907     t << "</script>\n";
908   }
909   //generateDynamicSections(t,relPath);
910   m_sectionCount=0;
911 }
912
913 void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &relPath)
914 {
915   static bool searchEngine      = Config_getBool(SEARCHENGINE);
916   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
917   if (searchEngine && !serverBasedSearch)
918   {
919     (void)relPath;
920     t << "<!-- window showing the filter options -->\n";
921     t << "<div id=\"MSearchSelectWindow\"\n";
922     t << "     onmouseover=\"return searchBox.OnSearchSelectShow()\"\n";
923     t << "     onmouseout=\"return searchBox.OnSearchSelectHide()\"\n";
924     t << "     onkeydown=\"return searchBox.OnSearchSelectKey(event)\">\n";
925     t << "</div>\n";
926     t << "\n";
927     t << "<!-- iframe showing the search results (closed by default) -->\n";
928     t << "<div id=\"MSearchResultsWindow\">\n";
929     t << "<iframe src=\"javascript:void(0)\" frameborder=\"0\" \n";
930     t << "        name=\"MSearchResults\" id=\"MSearchResults\">\n";
931     t << "</iframe>\n";
932     t << "</div>\n";
933     t << "\n";
934   }
935 }
936
937 void HtmlGenerator::writeSearchInfo()
938 {
939   writeSearchInfo(t,relPath);
940 }
941
942
943 QCString HtmlGenerator::writeLogoAsString(const char *path)
944 {
945   static bool timeStamp = Config_getBool(HTML_TIMESTAMP);
946   QCString result;
947   if (timeStamp)
948   {
949     result += theTranslator->trGeneratedAt(
950                dateToString(TRUE),
951                Config_getString(PROJECT_NAME)
952               );
953   }
954   else
955   {
956     result += theTranslator->trGeneratedBy();
957   }
958   result += "&#160;\n<a href=\"http://www.doxygen.org/index.html\">\n"
959             "<img class=\"footer\" src=\"";
960   result += path;
961   result += "doxygen.png\" alt=\"doxygen\"/></a> ";
962   result += versionString;
963   result += " ";
964   return result;
965 }
966
967 void HtmlGenerator::writeLogo()
968 {
969   t << writeLogoAsString(relPath);
970 }
971
972 void HtmlGenerator::writePageFooter(FTextStream &t,const QCString &lastTitle,
973                               const QCString &relPath,const QCString &navPath)
974 {
975   t << substituteHtmlKeywords(g_footer,convertToHtml(lastTitle),relPath,navPath);
976 }
977
978 void HtmlGenerator::writeFooter(const char *navPath)
979 {
980   writePageFooter(t,lastTitle,relPath,navPath);
981 }
982
983 void HtmlGenerator::endFile()
984 {
985   endPlainFile();
986 }
987
988 void HtmlGenerator::startProjectNumber()
989 {
990   t << "<h3 class=\"version\">";
991 }
992
993 void HtmlGenerator::endProjectNumber()
994 {
995   t << "</h3>";
996 }
997
998 void HtmlGenerator::writeStyleInfo(int part)
999 {
1000   //printf("writeStyleInfo(%d)\n",part);
1001   if (part==0)
1002   {
1003     if (Config_getString(HTML_STYLESHEET).isEmpty()) // write default style sheet
1004     {
1005       //printf("write doxygen.css\n");
1006       startPlainFile("doxygen.css");
1007
1008       // alternative, cooler looking titles
1009       //t << "H1 { text-align: center; border-width: thin none thin none;" << endl;
1010       //t << "     border-style : double; border-color : blue; padding-left : 1em; padding-right : 1em }" << endl;
1011
1012       t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",versionString));
1013       endPlainFile();
1014       Doxygen::indexList->addStyleSheetFile("doxygen.css");
1015     }
1016     else // write user defined style sheet
1017     {
1018       QCString cssname=Config_getString(HTML_STYLESHEET);
1019       QFileInfo cssfi(cssname);
1020       if (!cssfi.exists() || !cssfi.isFile() || !cssfi.isReadable())
1021       {
1022         err("style sheet %s does not exist or is not readable!", Config_getString(HTML_STYLESHEET).data());
1023       }
1024       else
1025       {
1026         // convert style sheet to string
1027         QCString fileStr = fileToString(cssname);
1028         // write the string into the output dir
1029         startPlainFile(cssfi.fileName().utf8());
1030         t << fileStr;
1031         endPlainFile();
1032       }
1033       Doxygen::indexList->addStyleSheetFile(cssfi.fileName().utf8());
1034     }
1035     static QStrList extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET);
1036     for (uint i=0; i<extraCssFile.count(); ++i)
1037     {
1038       QCString fileName(extraCssFile.at(i));
1039       if (!fileName.isEmpty())
1040       {
1041         QFileInfo fi(fileName);
1042         if (fi.exists())
1043         {
1044           Doxygen::indexList->addStyleSheetFile(fi.fileName().utf8());
1045         }
1046       }
1047     }
1048
1049     Doxygen::indexList->addStyleSheetFile("jquery.js");
1050     Doxygen::indexList->addStyleSheetFile("dynsections.js");
1051     if (Config_getBool(INTERACTIVE_SVG))
1052     {
1053       Doxygen::indexList->addStyleSheetFile("svgpan.js");
1054     }
1055   }
1056 }
1057
1058 void HtmlGenerator::startDoxyAnchor(const char *,const char *,
1059                                     const char *anchor, const char *,
1060                                     const char *)
1061 {
1062   t << "<a id=\"" << anchor << "\"></a>";
1063 }
1064
1065 void HtmlGenerator::endDoxyAnchor(const char *,const char *)
1066 {
1067 }
1068
1069 //void HtmlGenerator::newParagraph()
1070 //{
1071 //  t << endl << "<p>" << endl;
1072 //}
1073
1074 void HtmlGenerator::startParagraph(const char *classDef)
1075 {
1076   if (classDef)
1077     t << endl << "<p class=\"" << classDef << "\">";
1078   else
1079     t << endl << "<p>";
1080 }
1081
1082 void HtmlGenerator::endParagraph()
1083 {
1084   t << "</p>" << endl;
1085 }
1086
1087 void HtmlGenerator::writeString(const char *text)
1088 {
1089   t << text;
1090 }
1091
1092 void HtmlGenerator::startIndexListItem()
1093 {
1094   t << "<li>";
1095 }
1096
1097 void HtmlGenerator::endIndexListItem()
1098 {
1099   t << "</li>" << endl;
1100 }
1101
1102 void HtmlGenerator::startIndexItem(const char *ref,const char *f)
1103 {
1104   //printf("HtmlGenerator::startIndexItem(%s,%s)\n",ref,f);
1105   if (ref || f)
1106   {
1107     if (ref)
1108     {
1109       t << "<a class=\"elRef\" ";
1110       t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
1111     }
1112     else
1113     {
1114       t << "<a class=\"el\" ";
1115     }
1116     t << "href=\"";
1117     t << externalRef(relPath,ref,TRUE);
1118     if (f) t << f << Doxygen::htmlFileExtension << "\">";
1119   }
1120   else
1121   {
1122     t << "<b>";
1123   }
1124 }
1125
1126 void HtmlGenerator::endIndexItem(const char *ref,const char *f)
1127 {
1128   //printf("HtmlGenerator::endIndexItem(%s,%s,%s)\n",ref,f,name);
1129   if (ref || f)
1130   {
1131     t << "</a>";
1132   }
1133   else
1134   {
1135     t << "</b>";
1136   }
1137 }
1138
1139 void HtmlGenerator::writeStartAnnoItem(const char *,const char *f,
1140                                        const char *path,const char *name)
1141 {
1142   t << "<li>";
1143   if (path) docify(path);
1144   t << "<a class=\"el\" href=\"" << f << Doxygen::htmlFileExtension << "\">";
1145   docify(name);
1146   t << "</a> ";
1147 }
1148
1149 void HtmlGenerator::writeObjectLink(const char *ref,const char *f,
1150                                     const char *anchor, const char *name)
1151 {
1152   if (ref)
1153   {
1154     t << "<a class=\"elRef\" ";
1155     t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
1156   }
1157   else
1158   {
1159     t << "<a class=\"el\" ";
1160   }
1161   t << "href=\"";
1162   t << externalRef(relPath,ref,TRUE);
1163   if (f) t << f << Doxygen::htmlFileExtension;
1164   if (anchor) t << "#" << anchor;
1165   t << "\">";
1166   docify(name);
1167   t << "</a>";
1168 }
1169
1170 void HtmlGenerator::startTextLink(const char *f,const char *anchor)
1171 {
1172   t << "<a href=\"";
1173   if (f)   t << relPath << f << Doxygen::htmlFileExtension;
1174   if (anchor) t << "#" << anchor;
1175   t << "\">";
1176 }
1177
1178 void HtmlGenerator::endTextLink()
1179 {
1180   t << "</a>";
1181 }
1182
1183 void HtmlGenerator::startHtmlLink(const char *url)
1184 {
1185   static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
1186   t << "<a ";
1187   if (generateTreeView) t << "target=\"top\" ";
1188   t << "href=\"";
1189   if (url) t << url;
1190   t << "\">";
1191 }
1192
1193 void HtmlGenerator::endHtmlLink()
1194 {
1195   t << "</a>";
1196 }
1197
1198 void HtmlGenerator::startGroupHeader(int extraIndentLevel)
1199 {
1200   if (extraIndentLevel==2)
1201   {
1202     t << "<h4 class=\"groupheader\">";
1203   }
1204   else if (extraIndentLevel==1)
1205   {
1206     t << "<h3 class=\"groupheader\">";
1207   }
1208   else // extraIndentLevel==0
1209   {
1210     t << "<h2 class=\"groupheader\">";
1211   }
1212 }
1213
1214 void HtmlGenerator::endGroupHeader(int extraIndentLevel)
1215 {
1216   if (extraIndentLevel==2)
1217   {
1218     t << "</h4>" << endl;
1219   }
1220   else if (extraIndentLevel==1)
1221   {
1222     t << "</h3>" << endl;
1223   }
1224   else
1225   {
1226     t << "</h2>" << endl;
1227   }
1228 }
1229
1230 void HtmlGenerator::startSection(const char *lab,const char *,SectionInfo::SectionType type)
1231 {
1232   switch(type)
1233   {
1234     case SectionInfo::Page:          t << "\n\n<h1>"; break;
1235     case SectionInfo::Section:       t << "\n\n<h2>"; break;
1236     case SectionInfo::Subsection:    t << "\n\n<h3>"; break;
1237     case SectionInfo::Subsubsection: t << "\n\n<h4>"; break;
1238     case SectionInfo::Paragraph:     t << "\n\n<h5>"; break;
1239     default: ASSERT(0); break;
1240   }
1241   t << "<a id=\"" << lab << "\"></a>";
1242 }
1243
1244 void HtmlGenerator::endSection(const char *,SectionInfo::SectionType type)
1245 {
1246   switch(type)
1247   {
1248     case SectionInfo::Page:          t << "</h1>"; break;
1249     case SectionInfo::Section:       t << "</h2>"; break;
1250     case SectionInfo::Subsection:    t << "</h3>"; break;
1251     case SectionInfo::Subsubsection: t << "</h4>"; break;
1252     case SectionInfo::Paragraph:     t << "</h5>"; break;
1253     default: ASSERT(0); break;
1254   }
1255 }
1256
1257 void HtmlGenerator::docify(const char *str)
1258 {
1259   docify(str,FALSE);
1260 }
1261
1262 void HtmlGenerator::docify(const char *str,bool inHtmlComment)
1263 {
1264   if (str)
1265   {
1266     const char *p=str;
1267     char c;
1268     while (*p)
1269     {
1270       c=*p++;
1271       switch(c)
1272       {
1273         case '<':  t << "&lt;"; break;
1274         case '>':  t << "&gt;"; break;
1275         case '&':  t << "&amp;"; break;
1276         case '"':  t << "&quot;"; break;
1277         case '-':  if (inHtmlComment) t << "&#45;"; else t << "-"; break;
1278         case '\\':
1279                    if (*p=='<')
1280                      { t << "&lt;"; p++; }
1281                    else if (*p=='>')
1282                      { t << "&gt;"; p++; }
1283                    else
1284                      t << "\\";
1285                    break;
1286         default:   t << c;
1287       }
1288     }
1289   }
1290 }
1291
1292 void HtmlGenerator::writeChar(char c)
1293 {
1294   char cs[2];
1295   cs[0]=c;
1296   cs[1]=0;
1297   docify(cs);
1298 }
1299
1300 //--- helper function for dynamic sections -------------------------
1301
1302 static void startSectionHeader(FTextStream &t,
1303                                const QCString &relPath,int sectionCount)
1304 {
1305   //t << "<!-- startSectionHeader -->";
1306   static bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
1307   if (dynamicSections)
1308   {
1309     t << "<div id=\"dynsection-" << sectionCount << "\" "
1310          "onclick=\"return toggleVisibility(this)\" "
1311          "class=\"dynheader closed\" "
1312          "style=\"cursor:pointer;\">" << endl;
1313     t << "  <img id=\"dynsection-" << sectionCount << "-trigger\" src=\""
1314       << relPath << "closed.png\" alt=\"+\"/> ";
1315   }
1316   else
1317   {
1318     t << "<div class=\"dynheader\">" << endl;
1319   }
1320 }
1321
1322 static void endSectionHeader(FTextStream &t)
1323 {
1324   //t << "<!-- endSectionHeader -->";
1325   t << "</div>" << endl;
1326 }
1327
1328 static void startSectionSummary(FTextStream &t,int sectionCount)
1329 {
1330   //t << "<!-- startSectionSummary -->";
1331   static bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
1332   if (dynamicSections)
1333   {
1334     t << "<div id=\"dynsection-" << sectionCount << "-summary\" "
1335          "class=\"dynsummary\" "
1336          "style=\"display:block;\">" << endl;
1337   }
1338 }
1339
1340 static void endSectionSummary(FTextStream &t)
1341 {
1342   //t << "<!-- endSectionSummary -->";
1343   static bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
1344   if (dynamicSections)
1345   {
1346     t << "</div>" << endl;
1347   }
1348 }
1349
1350 static void startSectionContent(FTextStream &t,int sectionCount)
1351 {
1352   //t << "<!-- startSectionContent -->";
1353   static bool dynamicSections = Config_getBool(HTML_DYNAMIC_SECTIONS);
1354   if (dynamicSections)
1355   {
1356     t << "<div id=\"dynsection-" << sectionCount << "-content\" "
1357          "class=\"dyncontent\" "
1358          "style=\"display:none;\">" << endl;
1359   }
1360   else
1361   {
1362     t << "<div class=\"dyncontent\">" << endl;
1363   }
1364 }
1365
1366 static void endSectionContent(FTextStream &t)
1367 {
1368   //t << "<!-- endSectionContent -->";
1369   t << "</div>" << endl;
1370 }
1371
1372 //----------------------------
1373
1374 void HtmlGenerator::startClassDiagram()
1375 {
1376   startSectionHeader(t,relPath,m_sectionCount);
1377 }
1378
1379 void HtmlGenerator::endClassDiagram(const ClassDiagram &d,
1380                                 const char *fileName,const char *name)
1381 {
1382   endSectionHeader(t);
1383   startSectionSummary(t,m_sectionCount);
1384   endSectionSummary(t);
1385   startSectionContent(t,m_sectionCount);
1386   t << " <div class=\"center\">" << endl;
1387   t << "  <img src=\"";
1388   t << relPath << fileName << ".png\" usemap=\"#" << convertToId(name);
1389   t << "_map\" alt=\"\"/>" << endl;
1390   t << "  <map id=\"" << convertToId(name);
1391   t << "_map\" name=\"" << convertToId(name);
1392   t << "_map\">" << endl;
1393
1394   d.writeImage(t,dir,relPath,fileName);
1395   t << " </div>";
1396   endSectionContent(t);
1397   m_sectionCount++;
1398 }
1399
1400
1401 void HtmlGenerator::startMemberList()
1402 {
1403   DBG_HTML(t << "<!-- startMemberList -->" << endl)
1404 }
1405
1406 void HtmlGenerator::endMemberList()
1407 {
1408   DBG_HTML(t << "<!-- endMemberList -->" << endl)
1409 }
1410
1411 // anonymous type:
1412 //  0 = single column right aligned
1413 //  1 = double column left aligned
1414 //  2 = single column left aligned
1415 void HtmlGenerator::startMemberItem(const char *anchor,int annoType,const char *inheritId)
1416 {
1417   DBG_HTML(t << "<!-- startMemberItem() -->" << endl)
1418   if (m_emptySection)
1419   {
1420     t << "<table class=\"memberdecls\">" << endl;
1421     m_emptySection=FALSE;
1422   }
1423   t << "<tr class=\"memitem:" << anchor;
1424   if (inheritId)
1425   {
1426     t << " inherit " << inheritId;
1427   }
1428   t << "\">";
1429   switch(annoType)
1430   {
1431     case 0:  t << "<td class=\"memItemLeft\" align=\"right\" valign=\"top\">"; break;
1432     case 1:  t << "<td class=\"memItemLeft\" >"; break;
1433     case 2:  t << "<td class=\"memItemLeft\" valign=\"top\">"; break;
1434     default: t << "<td class=\"memTemplParams\" colspan=\"2\">"; break;
1435   }
1436 }
1437
1438 void HtmlGenerator::endMemberItem()
1439 {
1440   t << "</td></tr>";
1441   t << endl;
1442 }
1443
1444 void HtmlGenerator::startMemberTemplateParams()
1445 {
1446 }
1447
1448 void HtmlGenerator::endMemberTemplateParams(const char *anchor,const char *inheritId)
1449 {
1450   t << "</td></tr>" << endl;
1451   t << "<tr class=\"memitem:" << anchor;
1452   if (inheritId)
1453   {
1454     t << " inherit " << inheritId;
1455   }
1456   t << "\"><td class=\"memTemplItemLeft\" align=\"right\" valign=\"top\">";
1457 }
1458
1459
1460 void HtmlGenerator::insertMemberAlign(bool templ)
1461 {
1462   DBG_HTML(t << "<!-- insertMemberAlign -->" << endl)
1463   QCString className = templ ? "memTemplItemRight" : "memItemRight";
1464   t << "&#160;</td><td class=\"" << className << "\" valign=\"bottom\">";
1465 }
1466
1467 void HtmlGenerator::startMemberDescription(const char *anchor,const char *inheritId)
1468 {
1469   DBG_HTML(t << "<!-- startMemberDescription -->" << endl)
1470     if (m_emptySection)
1471     {
1472       t << "<table class=\"memberdecls\">" << endl;
1473       m_emptySection=FALSE;
1474     }
1475   t << "<tr class=\"memdesc:" << anchor;
1476   if (inheritId)
1477   {
1478     t << " inherit " << inheritId;
1479   }
1480   t << "\"><td class=\"mdescLeft\">&#160;</td><td class=\"mdescRight\">";
1481 }
1482
1483 void HtmlGenerator::endMemberDescription()
1484 {
1485   DBG_HTML(t << "<!-- endMemberDescription -->" << endl)
1486   t << "<br /></td></tr>" << endl;
1487 }
1488
1489 void HtmlGenerator::startMemberSections()
1490 {
1491   DBG_HTML(t << "<!-- startMemberSections -->" << endl)
1492   m_emptySection=TRUE; // we postpone writing <table> until we actually
1493                        // write a row to prevent empty tables, which
1494                        // are not valid XHTML!
1495 }
1496
1497 void HtmlGenerator::endMemberSections()
1498 {
1499   DBG_HTML(t << "<!-- endMemberSections -->" << endl)
1500   if (!m_emptySection)
1501   {
1502     t << "</table>" << endl;
1503   }
1504 }
1505
1506 void HtmlGenerator::startMemberHeader(const char *anchor)
1507 {
1508   DBG_HTML(t << "<!-- startMemberHeader -->" << endl)
1509   if (!m_emptySection)
1510   {
1511     t << "</table>";
1512     m_emptySection=TRUE;
1513   }
1514   if (m_emptySection)
1515   {
1516     t << "<table class=\"memberdecls\">" << endl;
1517     m_emptySection=FALSE;
1518   }
1519   t << "<tr class=\"heading\"><td colspan=\"2\"><h2 class=\"groupheader\">";
1520   if (anchor)
1521   {
1522     t << "<a name=\"" << anchor << "\"></a>" << endl;
1523   }
1524 }
1525
1526 void HtmlGenerator::endMemberHeader()
1527 {
1528   DBG_HTML(t << "<!-- endMemberHeader -->" << endl)
1529   t << "</h2></td></tr>" << endl;
1530 }
1531
1532 void HtmlGenerator::startMemberSubtitle()
1533 {
1534   DBG_HTML(t << "<!-- startMemberSubtitle -->" << endl)
1535   t << "<tr><td class=\"ititle\" colspan=\"2\">";
1536 }
1537
1538 void HtmlGenerator::endMemberSubtitle()
1539 {
1540   DBG_HTML(t << "<!-- endMemberSubtitle -->" << endl)
1541   t << "</td></tr>" << endl;
1542 }
1543
1544 void HtmlGenerator::startIndexList()
1545 {
1546   t << "<table>"  << endl;
1547 }
1548
1549 void HtmlGenerator::endIndexList()
1550 {
1551   t << "</table>" << endl;
1552 }
1553
1554 void HtmlGenerator::startIndexKey()
1555 {
1556   // inserted 'class = ...', 02 jan 2002, jh
1557   t << "  <tr><td class=\"indexkey\">";
1558 }
1559
1560 void HtmlGenerator::endIndexKey()
1561 {
1562   t << "</td>";
1563 }
1564
1565 void HtmlGenerator::startIndexValue(bool)
1566 {
1567   // inserted 'class = ...', 02 jan 2002, jh
1568   t << "<td class=\"indexvalue\">";
1569 }
1570
1571 void HtmlGenerator::endIndexValue(const char *,bool)
1572 {
1573   t << "</td></tr>" << endl;
1574 }
1575
1576 void HtmlGenerator::startMemberDocList()
1577 {
1578   DBG_HTML(t << "<!-- startMemberDocList -->" << endl;)
1579 }
1580
1581 void HtmlGenerator::endMemberDocList()
1582 {
1583   DBG_HTML(t << "<!-- endMemberDocList -->" << endl;)
1584 }
1585
1586 void HtmlGenerator::startMemberDoc( const char *clName, const char *memName,
1587                                     const char *anchor, const char *title,
1588                                     int memCount, int memTotal, bool showInline)
1589 {
1590   DBG_HTML(t << "<!-- startMemberDoc -->" << endl;)
1591   t << "\n<h2 class=\"memtitle\">"
1592     << "<span class=\"permalink\"><a href=\"#" << anchor << "\">&#9670;&nbsp;</a></span>";
1593   docify(title);
1594   if (memTotal>1)
1595   {
1596     t << " <span class=\"overload\">[" << memCount << "/" << memTotal <<"]</span>";
1597   }
1598   t << "</h2>"
1599     << endl;
1600   t << "\n<div class=\"memitem\">" << endl;
1601   t << "<div class=\"memproto\">" << endl;
1602 }
1603
1604 void HtmlGenerator::startMemberDocPrefixItem()
1605 {
1606   DBG_HTML(t << "<!-- startMemberDocPrefixItem -->" << endl;)
1607   t << "<div class=\"memtemplate\">" << endl;
1608 }
1609
1610 void HtmlGenerator::endMemberDocPrefixItem()
1611 {
1612   DBG_HTML(t << "<!-- endMemberDocPrefixItem -->" << endl;)
1613   t << "</div>" << endl;
1614 }
1615
1616 void HtmlGenerator::startMemberDocName(bool /*align*/)
1617 {
1618   DBG_HTML(t << "<!-- startMemberDocName -->" << endl;)
1619
1620   t << "      <table class=\"memname\">" << endl;
1621
1622   t << "        <tr>" << endl;
1623   t << "          <td class=\"memname\">";
1624 }
1625
1626 void HtmlGenerator::endMemberDocName()
1627 {
1628   DBG_HTML(t << "<!-- endMemberDocName -->" << endl;)
1629   t << "</td>" << endl;
1630 }
1631
1632 void HtmlGenerator::startParameterList(bool openBracket)
1633 {
1634   DBG_HTML(t << "<!-- startParameterList -->" << endl;)
1635   t << "          <td>";
1636   if (openBracket) t << "(";
1637   t << "</td>" << endl;
1638 }
1639
1640 void HtmlGenerator::startParameterType(bool first,const char *key)
1641 {
1642   if (first)
1643   {
1644     DBG_HTML(t << "<!-- startFirstParameterType -->" << endl;)
1645     t << "          <td class=\"paramtype\">";
1646   }
1647   else
1648   {
1649     DBG_HTML(t << "<!-- startParameterType -->" << endl;)
1650     t << "        <tr>" << endl;
1651     t << "          <td class=\"paramkey\">";
1652     if (key) t << key;
1653     t << "</td>" << endl;
1654     t << "          <td></td>" << endl;
1655     t << "          <td class=\"paramtype\">";
1656   }
1657 }
1658
1659 void HtmlGenerator::endParameterType()
1660 {
1661   DBG_HTML(t << "<!-- endParameterType -->" << endl;)
1662   t << "&#160;</td>" << endl;
1663 }
1664
1665 void HtmlGenerator::startParameterName(bool /*oneArgOnly*/)
1666 {
1667   DBG_HTML(t << "<!-- startParameterName -->" << endl;)
1668   t << "          <td class=\"paramname\">";
1669 }
1670
1671 void HtmlGenerator::endParameterName(bool last,bool emptyList,bool closeBracket)
1672 {
1673   DBG_HTML(t << "<!-- endParameterName -->" << endl;)
1674   if (last)
1675   {
1676     if (emptyList)
1677     {
1678       if (closeBracket) t << "</td><td>)";
1679       t << "</td>" << endl;
1680       t << "          <td>";
1681     }
1682     else
1683     {
1684       t << "&#160;</td>" << endl;
1685       t << "        </tr>" << endl;
1686       t << "        <tr>" << endl;
1687       t << "          <td></td>" << endl;
1688       t << "          <td>";
1689       if (closeBracket) t << ")";
1690       t << "</td>" << endl;
1691       t << "          <td></td><td>";
1692     }
1693   }
1694   else
1695   {
1696     t << "</td>" << endl;
1697     t << "        </tr>" << endl;
1698   }
1699 }
1700
1701 void HtmlGenerator::endParameterList()
1702 {
1703   DBG_HTML(t << "<!-- endParameterList -->" << endl;)
1704   t << "</td>" << endl;
1705   t << "        </tr>" << endl;
1706 }
1707
1708 void HtmlGenerator::exceptionEntry(const char* prefix,bool closeBracket)
1709 {
1710   DBG_HTML(t << "<!-- exceptionEntry -->" << endl;)
1711   t << "</td>" << endl;
1712   t << "        </tr>" << endl;
1713   t << "        <tr>" << endl;
1714   t << "          <td align=\"right\">";
1715   // colspan 2 so it gets both parameter type and parameter name columns
1716   if (prefix)
1717     t << prefix << "</td><td>(</td><td colspan=\"2\">";
1718   else if (closeBracket)
1719     t << "</td><td>)</td><td></td><td>";
1720   else
1721     t << "</td><td></td><td colspan=\"2\">";
1722 }
1723
1724 void HtmlGenerator::endMemberDoc(bool hasArgs)
1725 {
1726   DBG_HTML(t << "<!-- endMemberDoc -->" << endl;)
1727   if (!hasArgs)
1728   {
1729     t << "        </tr>" << endl;
1730   }
1731   t << "      </table>" << endl;
1732  // t << "</div>" << endl;
1733 }
1734
1735 void HtmlGenerator::startDotGraph()
1736 {
1737   startSectionHeader(t,relPath,m_sectionCount);
1738 }
1739
1740 void HtmlGenerator::endDotGraph(const DotClassGraph &g)
1741 {
1742   bool generateLegend = Config_getBool(GENERATE_LEGEND);
1743   bool umlLook = Config_getBool(UML_LOOK);
1744   endSectionHeader(t);
1745   startSectionSummary(t,m_sectionCount);
1746   endSectionSummary(t);
1747   startSectionContent(t,m_sectionCount);
1748
1749   g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,TRUE,m_sectionCount);
1750   if (generateLegend && !umlLook)
1751   {
1752     t << "<center><span class=\"legend\">[";
1753     startHtmlLink(relPath+"graph_legend"+Doxygen::htmlFileExtension);
1754     t << theTranslator->trLegend();
1755     endHtmlLink();
1756     t << "]</span></center>";
1757   }
1758
1759   endSectionContent(t);
1760   m_sectionCount++;
1761 }
1762
1763 void HtmlGenerator::startInclDepGraph()
1764 {
1765   startSectionHeader(t,relPath,m_sectionCount);
1766 }
1767
1768 void HtmlGenerator::endInclDepGraph(const DotInclDepGraph &g)
1769 {
1770   endSectionHeader(t);
1771   startSectionSummary(t,m_sectionCount);
1772   endSectionSummary(t);
1773   startSectionContent(t,m_sectionCount);
1774
1775   g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount);
1776
1777   endSectionContent(t);
1778   m_sectionCount++;
1779 }
1780
1781 void HtmlGenerator::startGroupCollaboration()
1782 {
1783   startSectionHeader(t,relPath,m_sectionCount);
1784 }
1785
1786 void HtmlGenerator::endGroupCollaboration(const DotGroupCollaboration &g)
1787 {
1788   endSectionHeader(t);
1789   startSectionSummary(t,m_sectionCount);
1790   endSectionSummary(t);
1791   startSectionContent(t,m_sectionCount);
1792
1793   g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount);
1794
1795   endSectionContent(t);
1796   m_sectionCount++;
1797 }
1798
1799 void HtmlGenerator::startCallGraph()
1800 {
1801   startSectionHeader(t,relPath,m_sectionCount);
1802 }
1803
1804 void HtmlGenerator::endCallGraph(const DotCallGraph &g)
1805 {
1806   endSectionHeader(t);
1807   startSectionSummary(t,m_sectionCount);
1808   endSectionSummary(t);
1809   startSectionContent(t,m_sectionCount);
1810
1811   g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount);
1812
1813   endSectionContent(t);
1814   m_sectionCount++;
1815 }
1816
1817 void HtmlGenerator::startDirDepGraph()
1818 {
1819   startSectionHeader(t,relPath,m_sectionCount);
1820 }
1821
1822 void HtmlGenerator::endDirDepGraph(const DotDirDeps &g)
1823 {
1824   endSectionHeader(t);
1825   startSectionSummary(t,m_sectionCount);
1826   endSectionSummary(t);
1827   startSectionContent(t,m_sectionCount);
1828
1829   g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount);
1830
1831   endSectionContent(t);
1832   m_sectionCount++;
1833 }
1834
1835 void HtmlGenerator::writeGraphicalHierarchy(const DotGfxHierarchyTable &g)
1836 {
1837   g.writeGraph(t,dir,fileName);
1838 }
1839
1840 void HtmlGenerator::startMemberGroupHeader(bool)
1841 {
1842   t << "<tr><td colspan=\"2\"><div class=\"groupHeader\">";
1843 }
1844
1845 void HtmlGenerator::endMemberGroupHeader()
1846 {
1847   t << "</div></td></tr>" << endl;
1848 }
1849
1850 void HtmlGenerator::startMemberGroupDocs()
1851 {
1852   t << "<tr><td colspan=\"2\"><div class=\"groupText\">";
1853 }
1854
1855 void HtmlGenerator::endMemberGroupDocs()
1856 {
1857   t << "</div></td></tr>" << endl;
1858 }
1859
1860 void HtmlGenerator::startMemberGroup()
1861 {
1862 }
1863
1864 void HtmlGenerator::endMemberGroup(bool)
1865 {
1866 }
1867
1868 void HtmlGenerator::startIndent()
1869 {
1870   DBG_HTML(t << "<!-- startIndent -->" << endl;)
1871
1872   t << "<div class=\"memdoc\">\n";
1873 }
1874
1875 void HtmlGenerator::endIndent()
1876 {
1877   DBG_HTML(t << "<!-- endIndent -->" << endl;)
1878   t << endl << "</div>" << endl << "</div>" << endl;
1879 }
1880
1881 void HtmlGenerator::addIndexItem(const char *,const char *)
1882 {
1883 }
1884
1885 void HtmlGenerator::writeNonBreakableSpace(int n)
1886 {
1887   int i;
1888   for (i=0;i<n;i++)
1889   {
1890     t << "&#160;";
1891   }
1892 }
1893
1894 void HtmlGenerator::startDescTable(const char *title)
1895 {
1896   t << "<table class=\"fieldtable\">" << endl
1897     << "<tr><th colspan=\"2\">" << title << "</th></tr>";
1898 }
1899 void HtmlGenerator::endDescTable()
1900 {
1901   t << "</table>" << endl;
1902 }
1903
1904 void HtmlGenerator::startDescTableRow()
1905 {
1906   t << "<tr>";
1907 }
1908
1909 void HtmlGenerator::endDescTableRow()
1910 {
1911   t << "</tr>" << endl;
1912 }
1913
1914 void HtmlGenerator::startDescTableTitle()
1915 {
1916   t << "<td class=\"fieldname\">";
1917 }
1918
1919 void HtmlGenerator::endDescTableTitle()
1920 {
1921   t << "&#160;</td>";
1922 }
1923
1924 void HtmlGenerator::startDescTableData()
1925 {
1926   t << "<td class=\"fielddoc\">";
1927 }
1928
1929 void HtmlGenerator::endDescTableData()
1930 {
1931   t << "</td>";
1932 }
1933
1934 void HtmlGenerator::startSimpleSect(SectionTypes,
1935                                 const char *filename,const char *anchor,
1936                                 const char *title)
1937 {
1938   t << "<dl><dt><b>";
1939   if (filename)
1940   {
1941     writeObjectLink(0,filename,anchor,title);
1942   }
1943   else
1944   {
1945     docify(title);
1946   }
1947   t << "</b></dt>";
1948 }
1949
1950 void HtmlGenerator::endSimpleSect()
1951 {
1952   t << "</dl>";
1953 }
1954
1955 void HtmlGenerator::startParamList(ParamListTypes,
1956                                 const char *title)
1957 {
1958   t << "<dl><dt><b>";
1959   docify(title);
1960   t << "</b></dt>";
1961 }
1962
1963 void HtmlGenerator::endParamList()
1964 {
1965   t << "</dl>";
1966 }
1967
1968 void HtmlGenerator::writeDoc(DocNode *n,Definition *ctx,MemberDef *)
1969 {
1970   HtmlDocVisitor *visitor = new HtmlDocVisitor(t,m_codeGen,ctx);
1971   n->accept(visitor);
1972   delete visitor;
1973 }
1974
1975 //---------------- helpers for index generation -----------------------------
1976
1977 static void startQuickIndexList(FTextStream &t,bool compact,bool topLevel=TRUE)
1978 {
1979   if (compact)
1980   {
1981     if (topLevel)
1982     {
1983       t << "  <div id=\"navrow1\" class=\"tabs\">\n";
1984     }
1985     else
1986     {
1987       t << "  <div id=\"navrow2\" class=\"tabs2\">\n";
1988     }
1989     t << "    <ul class=\"tablist\">\n";
1990   }
1991   else
1992   {
1993     t << "<ul>";
1994   }
1995 }
1996
1997 static void endQuickIndexList(FTextStream &t,bool compact)
1998 {
1999   if (compact)
2000   {
2001     t << "    </ul>\n";
2002     t << "  </div>\n";
2003   }
2004   else
2005   {
2006     t << "</ul>\n";
2007   }
2008 }
2009
2010 static void startQuickIndexItem(FTextStream &t,const char *l,
2011                                 bool hl,bool /*compact*/,
2012                                 const QCString &relPath)
2013 {
2014   t << "      <li";
2015   if (hl)
2016   {
2017     t << " class=\"current\"";
2018   }
2019   t << ">";
2020   if (l) t << "<a href=\"" << correctURL(l,relPath) << "\">";
2021   t << "<span>";
2022 }
2023
2024 static void endQuickIndexItem(FTextStream &t,const char *l)
2025 {
2026   t << "</span>";
2027   if (l) t << "</a>";
2028   t << "</li>\n";
2029 }
2030
2031 static bool quickLinkVisible(LayoutNavEntry::Kind kind)
2032 {
2033   static bool showFiles = Config_getBool(SHOW_FILES);
2034   static bool showNamespaces = Config_getBool(SHOW_NAMESPACES);
2035   switch (kind)
2036   {
2037     case LayoutNavEntry::MainPage:         return TRUE;
2038     case LayoutNavEntry::User:             return TRUE;
2039     case LayoutNavEntry::UserGroup:        return TRUE;
2040     case LayoutNavEntry::Pages:            return indexedPages>0;
2041     case LayoutNavEntry::Modules:          return documentedGroups>0;
2042     case LayoutNavEntry::Namespaces:       return documentedNamespaces>0 && showNamespaces;
2043     case LayoutNavEntry::NamespaceList:    return documentedNamespaces>0 && showNamespaces;
2044     case LayoutNavEntry::NamespaceMembers: return documentedNamespaceMembers[NMHL_All]>0;
2045     case LayoutNavEntry::Classes:          return annotatedClasses>0;
2046     case LayoutNavEntry::ClassList:        return annotatedClasses>0;
2047     case LayoutNavEntry::ClassIndex:       return annotatedClasses>0;
2048     case LayoutNavEntry::ClassHierarchy:   return hierarchyClasses>0;
2049     case LayoutNavEntry::ClassMembers:     return documentedClassMembers[CMHL_All]>0;
2050     case LayoutNavEntry::Files:            return documentedHtmlFiles>0 && showFiles;
2051     case LayoutNavEntry::FileList:         return documentedHtmlFiles>0 && showFiles;
2052     case LayoutNavEntry::FileGlobals:      return documentedFileMembers[FMHL_All]>0;
2053     //case LayoutNavEntry::Dirs:             return documentedDirs>0;
2054     case LayoutNavEntry::Examples:         return Doxygen::exampleSDict->count()>0;
2055   }
2056   return FALSE;
2057 }
2058
2059 static void renderQuickLinksAsTree(FTextStream &t,const QCString &relPath,LayoutNavEntry *root)
2060
2061 {
2062   QListIterator<LayoutNavEntry> li(root->children());
2063   LayoutNavEntry *entry;
2064   int count=0;
2065   for (li.toFirst();(entry=li.current());++li)
2066   {
2067     if (entry->visible() && quickLinkVisible(entry->kind())) count++;
2068   }
2069   if (count>0) // at least one item is visible
2070   {
2071     startQuickIndexList(t,FALSE);
2072     for (li.toFirst();(entry=li.current());++li)
2073     {
2074       if (entry->visible() && quickLinkVisible(entry->kind()))
2075       {
2076         QCString url = entry->url();
2077         t << "<li><a href=\"" << relPath << url << "\"><span>";
2078         t << fixSpaces(entry->title());
2079         t << "</span></a>\n";
2080         // recursive into child list
2081         renderQuickLinksAsTree(t,relPath,entry);
2082         t << "</li>";
2083       }
2084     }
2085     endQuickIndexList(t,FALSE);
2086   }
2087 }
2088
2089
2090 static void renderQuickLinksAsTabs(FTextStream &t,const QCString &relPath,
2091                              LayoutNavEntry *hlEntry,LayoutNavEntry::Kind kind,
2092                              bool highlightParent,bool highlightSearch)
2093 {
2094   if (hlEntry->parent()) // first draw the tabs for the parent of hlEntry
2095   {
2096     renderQuickLinksAsTabs(t,relPath,hlEntry->parent(),kind,highlightParent,highlightSearch);
2097   }
2098   if (hlEntry->parent() && hlEntry->parent()->children().count()>0) // draw tabs for row containing hlEntry
2099   {
2100     bool topLevel = hlEntry->parent()->parent()==0;
2101     QListIterator<LayoutNavEntry> li(hlEntry->parent()->children());
2102     LayoutNavEntry *entry;
2103
2104     int count=0;
2105     for (li.toFirst();(entry=li.current());++li)
2106     {
2107       if (entry->visible() && quickLinkVisible(entry->kind())) count++;
2108     }
2109     if (count>0) // at least one item is visible
2110     {
2111       startQuickIndexList(t,TRUE,topLevel);
2112       for (li.toFirst();(entry=li.current());++li)
2113       {
2114         if (entry->visible() && quickLinkVisible(entry->kind()))
2115         {
2116           QCString url = entry->url();
2117           startQuickIndexItem(t,url,
2118               entry==hlEntry  &&
2119               (entry->children().count()>0 ||
2120                (entry->kind()==kind && !highlightParent)
2121               ),
2122               TRUE,relPath);
2123           t << fixSpaces(entry->title());
2124           endQuickIndexItem(t,url);
2125         }
2126       }
2127       if (hlEntry->parent()==LayoutDocManager::instance().rootNavEntry()) // first row is special as it contains the search box
2128       {
2129         static bool searchEngine      = Config_getBool(SEARCHENGINE);
2130         static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
2131         if (searchEngine)
2132         {
2133           t << "      <li>\n";
2134           if (!serverBasedSearch) // pure client side search
2135           {
2136             writeClientSearchBox(t,relPath);
2137             t << "      </li>\n";
2138           }
2139           else // server based search
2140           {
2141             writeServerSearchBox(t,relPath,highlightSearch);
2142             if (!highlightSearch)
2143             {
2144               t << "      </li>\n";
2145             }
2146           }
2147         }
2148         if (!highlightSearch) // on the search page the index will be ended by the
2149           // page itself
2150         {
2151           endQuickIndexList(t,TRUE);
2152         }
2153       }
2154       else // normal case for other rows than first one
2155       {
2156         endQuickIndexList(t,TRUE);
2157       }
2158     }
2159   }
2160 }
2161
2162 static void writeDefaultQuickLinks(FTextStream &t,bool compact,
2163                                    HighlightedItem hli,
2164                                    const char *file,
2165                                    const QCString &relPath)
2166 {
2167   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
2168   static bool searchEngine = Config_getBool(SEARCHENGINE);
2169   static bool externalSearch = Config_getBool(EXTERNAL_SEARCH);
2170   LayoutNavEntry *root = LayoutDocManager::instance().rootNavEntry();
2171   LayoutNavEntry::Kind kind = (LayoutNavEntry::Kind)-1;
2172   LayoutNavEntry::Kind altKind = (LayoutNavEntry::Kind)-1; // fall back for the old layout file
2173   bool highlightParent=FALSE;
2174   switch (hli) // map HLI enums to LayoutNavEntry::Kind enums
2175   {
2176     case HLI_Main:             kind = LayoutNavEntry::MainPage;         break;
2177     case HLI_Modules:          kind = LayoutNavEntry::Modules;          break;
2178     //case HLI_Directories:      kind = LayoutNavEntry::Dirs;             break;
2179     case HLI_Namespaces:       kind = LayoutNavEntry::NamespaceList;    altKind = LayoutNavEntry::Namespaces;  break;
2180     case HLI_Hierarchy:        kind = LayoutNavEntry::ClassHierarchy;   break;
2181     case HLI_Classes:          kind = LayoutNavEntry::ClassIndex;       altKind = LayoutNavEntry::Classes;     break;
2182     case HLI_Annotated:        kind = LayoutNavEntry::ClassList;        altKind = LayoutNavEntry::Classes;     break;
2183     case HLI_Files:            kind = LayoutNavEntry::FileList;         altKind = LayoutNavEntry::Files;       break;
2184     case HLI_NamespaceMembers: kind = LayoutNavEntry::NamespaceMembers; break;
2185     case HLI_Functions:        kind = LayoutNavEntry::ClassMembers;     break;
2186     case HLI_Globals:          kind = LayoutNavEntry::FileGlobals;      break;
2187     case HLI_Pages:            kind = LayoutNavEntry::Pages;            break;
2188     case HLI_Examples:         kind = LayoutNavEntry::Examples;         break;
2189     case HLI_UserGroup:        kind = LayoutNavEntry::UserGroup;        break;
2190     case HLI_ClassVisible:     kind = LayoutNavEntry::ClassList;        altKind = LayoutNavEntry::Classes;
2191                                highlightParent = TRUE; break;
2192     case HLI_NamespaceVisible: kind = LayoutNavEntry::NamespaceList;    altKind = LayoutNavEntry::Namespaces;
2193                                highlightParent = TRUE; break;
2194     case HLI_FileVisible:      kind = LayoutNavEntry::FileList;         altKind = LayoutNavEntry::Files;
2195                                highlightParent = TRUE; break;
2196     case HLI_None:   break;
2197     case HLI_Search: break;
2198   }
2199
2200   if (compact && Config_getBool(HTML_DYNAMIC_MENUS))
2201   {
2202     QCString searchPage;
2203     if (externalSearch)
2204     {
2205       searchPage = "search" + Doxygen::htmlFileExtension;
2206     }
2207     else
2208     {
2209       searchPage = "search.php";
2210     }
2211     t << "<script type=\"text/javascript\" src=\"" << relPath << "menudata.js\"></script>" << endl;
2212     t << "<script type=\"text/javascript\" src=\"" << relPath << "menu.js\"></script>" << endl;
2213     t << "<script type=\"text/javascript\">" << endl;
2214                 t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
2215     t << "$(function() {" << endl;
2216     t << "  initMenu('" << relPath << "',"
2217       << (searchEngine?"true":"false") << ","
2218       << (serverBasedSearch?"true":"false") << ",'"
2219       << searchPage << "','"
2220       << theTranslator->trSearch() << "');" << endl;
2221     if (Config_getBool(SEARCHENGINE))
2222     {
2223       if (!serverBasedSearch)
2224       {
2225         t << "  $(document).ready(function() { init_search(); });\n";
2226       }
2227       else
2228       {
2229                                 t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
2230         t << "  $(document).ready(function() {\n"
2231           << "    if ($('.searchresults').length > 0) { searchBox.DOMSearchField().focus(); }\n"
2232           << "  });\n";
2233       }
2234     }
2235     t << "});" << endl;
2236                 t << "/* @license-end */";
2237     t << "</script>" << endl;
2238     t << "<div id=\"main-nav\"></div>" << endl;
2239   }
2240   else if (compact) // && !Config_getBool(HTML_DYNAMIC_MENUS)
2241   {
2242     // find highlighted index item
2243     LayoutNavEntry *hlEntry = root->find(kind,kind==LayoutNavEntry::UserGroup ? file : 0);
2244     if (!hlEntry && altKind!=(LayoutNavEntry::Kind)-1) { hlEntry=root->find(altKind); kind=altKind; }
2245     if (!hlEntry) // highlighted item not found in the index! -> just show the level 1 index...
2246     {
2247       highlightParent=TRUE;
2248       hlEntry = root->children().getFirst();
2249       if (hlEntry==0)
2250       {
2251         return; // argl, empty index!
2252       }
2253     }
2254     if (kind==LayoutNavEntry::UserGroup)
2255     {
2256       LayoutNavEntry *e = hlEntry->children().getFirst();
2257       if (e)
2258       {
2259         hlEntry = e;
2260       }
2261     }
2262     renderQuickLinksAsTabs(t,relPath,hlEntry,kind,highlightParent,hli==HLI_Search);
2263   }
2264   else
2265   {
2266     renderQuickLinksAsTree(t,relPath,root);
2267   }
2268 }
2269
2270 void HtmlGenerator::endQuickIndices()
2271 {
2272   t << "</div><!-- top -->" << endl;
2273 }
2274
2275 QCString HtmlGenerator::writeSplitBarAsString(const char *name,const char *relpath)
2276 {
2277   static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2278   QCString result;
2279   // write split bar
2280   if (generateTreeView)
2281   {
2282     result = QCString(
2283                                                                                         "<div id=\"side-nav\" class=\"ui-resizable side-nav-resizable\">\n"
2284                                                                                         "  <div id=\"nav-tree\">\n"
2285                                                                                         "    <div id=\"nav-tree-contents\">\n"
2286                                                                                         "      <div id=\"nav-sync\" class=\"sync\"></div>\n"
2287                                                                                         "    </div>\n"
2288                                                                                         "  </div>\n"
2289                                                                                         "  <div id=\"splitbar\" style=\"-moz-user-select:none;\" \n"
2290                                                                                         "       class=\"ui-resizable-handle\">\n"
2291                                                                                         "  </div>\n"
2292                                                                                         "</div>\n"
2293                                                                                         "<script type=\"text/javascript\">\n"
2294                                                                                         "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n"
2295                                                                                         "$(document).ready(function(){initNavTree('") +
2296                         QCString(name) + Doxygen::htmlFileExtension +
2297                         QCString("','") + relpath +
2298                         QCString("');});\n"
2299                                                          "/* @license-end */\n"
2300                                                          "</script>\n"
2301                                                          "<div id=\"doc-content\">\n");
2302   }
2303   return result;
2304 }
2305
2306 void HtmlGenerator::writeSplitBar(const char *name)
2307 {
2308   t << writeSplitBarAsString(name,relPath);
2309 }
2310
2311 void HtmlGenerator::writeNavigationPath(const char *s)
2312 {
2313   t << substitute(s,"$relpath^",relPath);
2314 }
2315
2316 void HtmlGenerator::startContents()
2317 {
2318   t << "<div class=\"contents\">" << endl;
2319 }
2320
2321 void HtmlGenerator::endContents()
2322 {
2323   t << "</div><!-- contents -->" << endl;
2324 }
2325
2326 void HtmlGenerator::writeQuickLinks(bool compact,HighlightedItem hli,const char *file)
2327 {
2328   writeDefaultQuickLinks(t,compact,hli,file,relPath);
2329 }
2330
2331 // PHP based search script
2332 void HtmlGenerator::writeSearchPage()
2333 {
2334   static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2335   static bool disableIndex = Config_getBool(DISABLE_INDEX);
2336   static QCString projectName = Config_getString(PROJECT_NAME);
2337   static QCString htmlOutput = Config_getString(HTML_OUTPUT);
2338
2339   // OPENSEARCH_PROVIDER {
2340   QCString configFileName = htmlOutput+"/search_config.php";
2341   QFile cf(configFileName);
2342   if (cf.open(IO_WriteOnly))
2343   {
2344     FTextStream t(&cf);
2345     t << "<script language=\"php\">\n\n";
2346     t << "$config = array(\n";
2347     t << "  'PROJECT_NAME' => \"" << convertToHtml(projectName) << "\",\n";
2348     t << "  'GENERATE_TREEVIEW' => " << (generateTreeView?"true":"false") << ",\n";
2349     t << "  'DISABLE_INDEX' => " << (disableIndex?"true":"false") << ",\n";
2350     t << ");\n\n";
2351     t << "$translator = array(\n";
2352     t << "  'search_results_title' => \"" << theTranslator->trSearchResultsTitle() << "\",\n";
2353     t << "  'search_results' => array(\n";
2354     t << "    0 => \"" << theTranslator->trSearchResults(0) << "\",\n";
2355     t << "    1 => \"" << theTranslator->trSearchResults(1) << "\",\n";
2356     t << "    2 => \"" << substitute(theTranslator->trSearchResults(2), "$", "\\$") << "\",\n";
2357     t << "  ),\n";
2358     t << "  'search_matches' => \"" << theTranslator->trSearchMatches() << "\",\n";
2359     t << "  'search' => \"" << theTranslator->trSearch() << "\",\n";
2360     t << "  'split_bar' => \"" << substitute(substitute(writeSplitBarAsString("search",""), "\"","\\\""), "\n","\\n") << "\",\n";
2361     t << "  'logo' => \"" << substitute(substitute(writeLogoAsString(""), "\"","\\\""), "\n","\\n") << "\",\n";
2362     t << ");\n\n";
2363     t << "</script>\n";
2364   }
2365
2366   ResourceMgr::instance().copyResource("search_functions.php",htmlOutput);
2367   ResourceMgr::instance().copyResource("search_opensearch.php",htmlOutput);
2368   // OPENSEARCH_PROVIDER }
2369
2370   QCString fileName = htmlOutput+"/search.php";
2371   QFile f(fileName);
2372   if (f.open(IO_WriteOnly))
2373   {
2374     FTextStream t(&f);
2375     t << substituteHtmlKeywords(g_header,"Search","");
2376
2377     t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
2378       << versionString << " -->" << endl;
2379     t << "<script type=\"text/javascript\">\n";
2380                 t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
2381                 t << "var searchBox = new SearchBox(\"searchBox\", \""
2382       << "search\",false,'" << theTranslator->trSearch() << "');\n";
2383                 t << "/* @license-end */\n";
2384     t << "</script>\n";
2385     if (!Config_getBool(DISABLE_INDEX))
2386     {
2387       writeDefaultQuickLinks(t,TRUE,HLI_Search,0,"");
2388     }
2389     else
2390     {
2391       t << "</div>" << endl;
2392     }
2393
2394     t << "<script language=\"php\">\n";
2395     t << "require_once \"search_functions.php\";\n";
2396     t << "main();\n";
2397     t << "</script>\n";
2398
2399     // Write empty navigation path, to make footer connect properly
2400     if (generateTreeView)
2401     {
2402       t << "</div><!-- doc-content -->\n";
2403     }
2404
2405     writePageFooter(t,"Search","","");
2406   }
2407   QCString scriptName = htmlOutput+"/search/search.js";
2408   QFile sf(scriptName);
2409   if (sf.open(IO_WriteOnly))
2410   {
2411     FTextStream t(&sf);
2412     t << ResourceMgr::instance().getAsString("extsearch.js");
2413   }
2414   else
2415   {
2416      err("Failed to open file '%s' for writing...\n",scriptName.data());
2417   }
2418 }
2419
2420 void HtmlGenerator::writeExternalSearchPage()
2421 {
2422   static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
2423   static bool disableIndex = Config_getBool(DISABLE_INDEX);
2424   QCString fileName = Config_getString(HTML_OUTPUT)+"/search"+Doxygen::htmlFileExtension;
2425   QFile f(fileName);
2426   if (f.open(IO_WriteOnly))
2427   {
2428     FTextStream t(&f);
2429     t << substituteHtmlKeywords(g_header,"Search","");
2430
2431     t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
2432       << versionString << " -->" << endl;
2433     t << "<script type=\"text/javascript\">\n";
2434                 t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
2435                 t << "var searchBox = new SearchBox(\"searchBox\", \""
2436       << "search\",false,'" << theTranslator->trSearch() << "');\n";
2437                 t << "/* @license-end */\n";
2438     t << "</script>\n";
2439     if (!Config_getBool(DISABLE_INDEX))
2440     {
2441       writeDefaultQuickLinks(t,TRUE,HLI_Search,0,"");
2442       t << "            <input type=\"text\" id=\"MSearchField\" name=\"query\" value=\"\" size=\"20\" accesskey=\"S\" onfocus=\"searchBox.OnSearchFieldFocus(true)\" onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n";
2443       t << "            </form>\n";
2444       t << "          </div><div class=\"right\"></div>\n";
2445       t << "        </div>\n";
2446       t << "      </li>\n";
2447       t << "    </ul>\n";
2448       t << "  </div>\n";
2449       t << "</div>\n";
2450     }
2451     else
2452     {
2453       t << "</div>" << endl;
2454     }
2455     t << writeSplitBarAsString("search","");
2456     t << "<div class=\"header\">" << endl;
2457     t << "  <div class=\"headertitle\">" << endl;
2458     t << "    <div class=\"title\">" << theTranslator->trSearchResultsTitle() << "</div>" << endl;
2459     t << "  </div>" << endl;
2460     t << "</div>" << endl;
2461     t << "<div class=\"contents\">" << endl;
2462
2463     t << "<div id=\"searchresults\"></div>" << endl;
2464     t << "</div>" << endl;
2465
2466     if (generateTreeView)
2467     {
2468       t << "</div><!-- doc-content -->" << endl;
2469     }
2470
2471     writePageFooter(t,"Search","","");
2472
2473   }
2474   QCString scriptName = Config_getString(HTML_OUTPUT)+"/search/search.js";
2475   QFile sf(scriptName);
2476   if (sf.open(IO_WriteOnly))
2477   {
2478     FTextStream t(&sf);
2479     t << "var searchResultsText=["
2480       << "\"" << theTranslator->trSearchResults(0) << "\","
2481       << "\"" << theTranslator->trSearchResults(1) << "\","
2482       << "\"" << theTranslator->trSearchResults(2) << "\"];" << endl;
2483     t << "var serverUrl=\"" << Config_getString(SEARCHENGINE_URL) << "\";" << endl;
2484     t << "var tagMap = {" << endl;
2485     bool first=TRUE;
2486     // add search mappings
2487     QStrList &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS);
2488     char *ml=extraSearchMappings.first();
2489     while (ml)
2490     {
2491       QCString mapLine = ml;
2492       int eqPos = mapLine.find('=');
2493       if (eqPos!=-1) // tag command contains a destination
2494       {
2495         QCString tagName = mapLine.left(eqPos).stripWhiteSpace();
2496         QCString destName = mapLine.right(mapLine.length()-eqPos-1).stripWhiteSpace();
2497         if (!tagName.isEmpty())
2498         {
2499           if (!first) t << "," << endl;
2500           t << "  \"" << tagName << "\": \"" << destName << "\"";
2501           first=FALSE;
2502         }
2503       }
2504       ml=extraSearchMappings.next();
2505     }
2506     if (!first) t << endl;
2507     t << "};" << endl << endl;
2508     t << ResourceMgr::instance().getAsString("extsearch.js");
2509     t << endl;
2510     t << "$(document).ready(function() {" << endl;
2511     t << "  var query = trim(getURLParameter('query'));" << endl;
2512     t << "  if (query) {" << endl;
2513     t << "    searchFor(query,0,20);" << endl;
2514     t << "  } else {" << endl;
2515     t << "    var results = $('#results');" << endl;
2516     t << "    results.html('<p>" << theTranslator->trSearchResults(0) << "</p>');" << endl;
2517     t << "  }" << endl;
2518     t << "});" << endl;
2519   }
2520   else
2521   {
2522      err("Failed to open file '%s' for writing...\n",scriptName.data());
2523   }
2524 }
2525
2526 void HtmlGenerator::startConstraintList(const char *header)
2527 {
2528   t << "<div class=\"typeconstraint\">" << endl;
2529   t << "<dl><dt><b>" << header << "</b></dt><dd>" << endl;
2530   t << "<table border=\"0\" cellspacing=\"2\" cellpadding=\"0\">" << endl;
2531 }
2532
2533 void HtmlGenerator::startConstraintParam()
2534 {
2535   t << "<tr><td valign=\"top\"><em>";
2536 }
2537
2538 void HtmlGenerator::endConstraintParam()
2539 {
2540   t << "</em></td>";
2541 }
2542
2543 void HtmlGenerator::startConstraintType()
2544 {
2545   t << "<td>&#160;:</td><td valign=\"top\"><em>";
2546 }
2547
2548 void HtmlGenerator::endConstraintType()
2549 {
2550   t << "</em></td>";
2551 }
2552
2553 void HtmlGenerator::startConstraintDocs()
2554 {
2555   t << "<td>&#160;";
2556 }
2557
2558 void HtmlGenerator::endConstraintDocs()
2559 {
2560   t << "</td></tr>" << endl;
2561 }
2562
2563 void HtmlGenerator::endConstraintList()
2564 {
2565   t << "</table>" << endl;
2566   t << "</dd>" << endl;
2567   t << "</dl>" << endl;
2568   t << "</div>" << endl;
2569 }
2570
2571 void HtmlGenerator::lineBreak(const char *style)
2572 {
2573   if (style)
2574   {
2575     t << "<br class=\"" << style << "\" />" << endl;
2576   }
2577   else
2578   {
2579     t << "<br />" << endl;
2580   }
2581 }
2582
2583 void HtmlGenerator::startHeaderSection()
2584 {
2585   t << "<div class=\"header\">" << endl;
2586 }
2587
2588 void HtmlGenerator::startTitleHead(const char *)
2589 {
2590   t << "  <div class=\"headertitle\">" << endl;
2591   startTitle();
2592 }
2593
2594 void HtmlGenerator::endTitleHead(const char *,const char *)
2595 {
2596   endTitle();
2597   t << "  </div>" << endl;
2598 }
2599
2600 void HtmlGenerator::endHeaderSection()
2601 {
2602   t << "</div><!--header-->" << endl;
2603 }
2604
2605 void HtmlGenerator::startInlineHeader()
2606 {
2607   if (m_emptySection)
2608   {
2609     t << "<table class=\"memberdecls\">" << endl;
2610     m_emptySection=FALSE;
2611   }
2612   t << "<tr><td colspan=\"2\"><h3>";
2613 }
2614
2615 void HtmlGenerator::endInlineHeader()
2616 {
2617   t << "</h3></td></tr>" << endl;
2618 }
2619
2620 void HtmlGenerator::startMemberDocSimple(bool isEnum)
2621 {
2622   DBG_HTML(t << "<!-- startMemberDocSimple -->" << endl;)
2623   t << "<table class=\"fieldtable\">" << endl;
2624   t << "<tr><th colspan=\"" << (isEnum?"2":"3") << "\">";
2625   t << (isEnum? theTranslator->trEnumerationValues() :
2626        theTranslator->trCompoundMembers()) << "</th></tr>" << endl;
2627 }
2628
2629 void HtmlGenerator::endMemberDocSimple(bool)
2630 {
2631   DBG_HTML(t << "<!-- endMemberDocSimple -->" << endl;)
2632   t << "</table>" << endl;
2633 }
2634
2635 void HtmlGenerator::startInlineMemberType()
2636 {
2637   DBG_HTML(t << "<!-- startInlineMemberType -->" << endl;)
2638   t << "<tr><td class=\"fieldtype\">" << endl;
2639 }
2640
2641 void HtmlGenerator::endInlineMemberType()
2642 {
2643   DBG_HTML(t << "<!-- endInlineMemberType -->" << endl;)
2644   t << "</td>" << endl;
2645 }
2646
2647 void HtmlGenerator::startInlineMemberName()
2648 {
2649   DBG_HTML(t << "<!-- startInlineMemberName -->" << endl;)
2650   t << "<td class=\"fieldname\">" << endl;
2651 }
2652
2653 void HtmlGenerator::endInlineMemberName()
2654 {
2655   DBG_HTML(t << "<!-- endInlineMemberName -->" << endl;)
2656   t << "</td>" << endl;
2657 }
2658
2659 void HtmlGenerator::startInlineMemberDoc()
2660 {
2661   DBG_HTML(t << "<!-- startInlineMemberDoc -->" << endl;)
2662   t << "<td class=\"fielddoc\">" << endl;
2663 }
2664
2665 void HtmlGenerator::endInlineMemberDoc()
2666 {
2667   DBG_HTML(t << "<!-- endInlineMemberDoc -->" << endl;)
2668   t << "</td></tr>" << endl;
2669 }
2670
2671 void HtmlGenerator::startLabels()
2672 {
2673   DBG_HTML(t << "<!-- startLabels -->" << endl;)
2674   t << "<span class=\"mlabels\">";
2675 }
2676
2677 void HtmlGenerator::writeLabel(const char *l,bool /*isLast*/)
2678 {
2679   DBG_HTML(t << "<!-- writeLabel(" << l << ") -->" << endl;)
2680   //t << "<tt>[" << l << "]</tt>";
2681   //if (!isLast) t << ", ";
2682   t << "<span class=\"mlabel\">" << l << "</span>";
2683 }
2684
2685 void HtmlGenerator::endLabels()
2686 {
2687   DBG_HTML(t << "<!-- endLabels -->" << endl;)
2688   t << "</span>";
2689 }
2690
2691 void HtmlGenerator::writeInheritedSectionTitle(
2692                   const char *id,    const char *ref,
2693                   const char *file,  const char *anchor,
2694                   const char *title, const char *name)
2695 {
2696   DBG_HTML(t << "<!-- writeInheritedSectionTitle -->" << endl;)
2697   QCString a = anchor;
2698   if (!a.isEmpty()) a.prepend("#");
2699   QCString classLink = QCString("<a class=\"el\" href=\"");
2700   if (ref)
2701   {
2702     classLink+= externalLinkTarget() + externalRef(relPath,ref,TRUE);
2703   }
2704   else
2705   {
2706     classLink+=relPath;
2707   }
2708   classLink+=file+Doxygen::htmlFileExtension+a;
2709   classLink+=QCString("\">")+convertToHtml(name,FALSE)+"</a>";
2710   t << "<tr class=\"inherit_header " << id << "\">"
2711     << "<td colspan=\"2\" onclick=\"javascript:toggleInherit('" << id << "')\">"
2712     << "<img src=\"" << relPath << "closed.png\" alt=\"-\"/>&#160;"
2713     << theTranslator->trInheritedFrom(convertToHtml(title,FALSE),classLink)
2714     << "</td></tr>" << endl;
2715 }
2716
2717 void HtmlGenerator::writeSummaryLink(const char *file,const char *anchor,const char *title,bool first)
2718 {
2719   if (first)
2720   {
2721     t << "  <div class=\"summary\">\n";
2722   }
2723   else
2724   {
2725     t << " &#124;\n";
2726   }
2727   t << "<a href=\"";
2728   if (file)
2729   {
2730     t << relPath << file;
2731     t << Doxygen::htmlFileExtension;
2732   }
2733   else
2734   {
2735     t << "#";
2736     t << anchor;
2737   }
2738   t << "\">";
2739   t << title;
2740   t << "</a>";
2741 }
2742
2743 void HtmlGenerator::endMemberDeclaration(const char *anchor,const char *inheritId)
2744 {
2745   t << "<tr class=\"separator:" << anchor;
2746   if (inheritId)
2747   {
2748     t << " inherit " << inheritId;
2749   }
2750   t << "\"><td class=\"memSeparator\" colspan=\"2\">&#160;</td></tr>\n";
2751 }
2752
2753 void HtmlGenerator::setCurrentDoc(Definition *context,const char *anchor,bool isSourceFile)
2754 {
2755   if (Doxygen::searchIndex)
2756   {
2757     Doxygen::searchIndex->setCurrentDoc(context,anchor,isSourceFile);
2758   }
2759 }
2760
2761 void HtmlGenerator::addWord(const char *word,bool hiPriority)
2762 {
2763   if (Doxygen::searchIndex)
2764   {
2765     Doxygen::searchIndex->addWord(word,hiPriority);
2766   }
2767 }