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