My Project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
htmldocvisitor.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  *
4  *
5  *
6  * Copyright (C) 1997-2015 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby
10  * granted. No representations are made about the suitability of this software
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18 
19 #include <qdir.h>
20 #include "htmldocvisitor.h"
21 #include "docparser.h"
22 #include "language.h"
23 #include "doxygen.h"
24 #include "outputgen.h"
25 #include "dot.h"
26 #include "message.h"
27 #include "config.h"
28 #include "htmlgen.h"
29 #include "parserintf.h"
30 #include "msc.h"
31 #include "dia.h"
32 #include "util.h"
33 #include "vhdldocgen.h"
34 #include "filedef.h"
35 #include "memberdef.h"
36 #include "htmlentity.h"
37 #include "plantuml.h"
38 
39 static const int NUM_HTML_LIST_TYPES = 4;
40 static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
41 
42 static QCString convertIndexWordToAnchor(const QString &word)
43 {
44  static char hex[] = "0123456789abcdef";
45  QCString result="a";
46  const char *str = word.data();
47  unsigned char c;
48  if (str)
49  {
50  while ((c = *str++))
51  {
52  if ((c >= 'a' && c <= 'z') || // ALPHA
53  (c >= 'A' && c <= 'Z') || // ALPHA
54  (c >= '0' && c <= '9') || // DIGIT
55  c == '-' ||
56  c == '.' ||
57  c == '_'
58  )
59  {
60  result += c;
61  }
62  else
63  {
64  char enc[4];
65  enc[0] = ':';
66  enc[1] = hex[(c & 0xf0) >> 4];
67  enc[2] = hex[c & 0xf];
68  enc[3] = 0;
69  result += enc;
70  }
71  }
72  }
73  return result;
74 }
75 
77 {
78  switch (n->kind())
79  {
80  /* <ul> */
84  /* <dl> */
89  /* <table> */
91  /* <h?> */
94  /* \internal */
96  /* <div> */
100  /* <hr> */
102  /* CopyDoc gets paragraph markers from the wrapping DocPara node,
103  * but needs to insert them for all documentation being copied to
104  * preserve formatting.
105  */
106  case DocNode::Kind_Copy:
107  /* <blockquote> */
109  /* \parblock */
111  return TRUE;
113  {
114  DocVerbatim *dv = (DocVerbatim*)n;
115  return dv->type()!=DocVerbatim::HtmlOnly || dv->isBlock();
116  }
118  return ((DocStyleChange*)n)->style()==DocStyleChange::Preformatted ||
119  ((DocStyleChange*)n)->style()==DocStyleChange::Div ||
120  ((DocStyleChange*)n)->style()==DocStyleChange::Center;
122  return !((DocFormula*)n)->isInline();
123  default:
124  break;
125  }
126  return FALSE;
127 }
128 
129 static QString htmlAttribsToString(const HtmlAttribList &attribs)
130 {
131  QString result;
132  HtmlAttribListIterator li(attribs);
133  HtmlAttrib *att;
134  for (li.toFirst();(att=li.current());++li)
135  {
136  if (!att->value.isEmpty()) // ignore attribute without values as they
137  // are not XHTML compliant
138  {
139  result+=" ";
140  result+=att->name;
141  result+="=\""+convertToXML(att->value)+"\"";
142  }
143  }
144  return result;
145 }
146 
147 //-------------------------------------------------------------------------
148 
150  Definition *ctx)
151  : DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE),
152  m_hide(FALSE), m_ctx(ctx)
153 {
154  if (ctx) m_langExt=ctx->getDefFileExtension();
155 }
156 
157  //--------------------------------------
158  // visitor functions for leaf nodes
159  //--------------------------------------
160 
162 {
163  //printf("word: %s\n",w->word().data());
164  if (m_hide) return;
165  filter(w->word());
166 }
167 
169 {
170  if (m_hide) return;
171  //printf("linked word: %s\n",w->word().data());
172  startLink(w->ref(),w->file(),w->relPath(),w->anchor(),w->tooltip());
173  filter(w->word());
174  endLink();
175 }
176 
178 {
179  if (m_hide) return;
180  if (m_insidePre)
181  {
182  m_t << w->chars();
183  }
184  else
185  {
186  m_t << " ";
187  }
188 }
189 
191 {
192  if (m_hide) return;
193  const char *res = HtmlEntityMapper::instance()->html(s->symbol());
194  if (res)
195  {
196  m_t << res;
197  }
198  else
199  {
200  err("HTML: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
201  }
202 }
203 
205 {
206  m_t << "<a href=\"#\" onclick=\"location.href='mai'+'lto:'";
207  uint i;
208  int size=3;
209  for (i=0;i<url.length();)
210  {
211  m_t << "+'" << url.mid(i,size) << "'";
212  i+=size;
213  if (size==3) size=2; else size=3;
214  }
215  m_t << "; return false;\">";
216 }
217 
219 {
220  if (m_hide) return;
221  if (u->isEmail()) // mail address
222  {
223  QCString url = u->url();
225  uint size=5,i;
226  for (i=0;i<url.length();)
227  {
228  filter(url.mid(i,size));
229  if (i<url.length()-size) m_t << "<span style=\"display: none;\">.nosp@m.</span>";
230  i+=size;
231  if (size==5) size=4; else size=5;
232  }
233  m_t << "</a>";
234  }
235  else // web address
236  {
237  m_t << "<a href=\"";
238  m_t << u->url() << "\">";
239  filter(u->url());
240  m_t << "</a>";
241  }
242 }
243 
245 {
246  if (m_hide) return;
247  m_t << "<br />\n";
248 }
249 
251 {
252  if (m_hide) return;
253  forceEndParagraph(hr);
254  m_t << "<hr/>\n";
256 }
257 
259 {
260  if (m_hide) return;
261  switch (s->style())
262  {
264  if (s->enable()) m_t << "<b" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</b>";
265  break;
267  if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>";
268  break;
270  if (s->enable()) m_t << "<code" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</code>";
271  break;
273  if (s->enable()) m_t << "<sub" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sub>";
274  break;
276  if (s->enable()) m_t << "<sup" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sup>";
277  break;
279  if (s->enable())
280  {
282  m_t << "<center" << htmlAttribsToString(s->attribs()) << ">";
283  }
284  else
285  {
286  m_t << "</center>";
288  }
289  break;
291  if (s->enable()) m_t << "<small" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</small>";
292  break;
294  if (s->enable())
295  {
297  m_t << "<pre" << htmlAttribsToString(s->attribs()) << ">";
298  m_insidePre=TRUE;
299  }
300  else
301  {
302  m_insidePre=FALSE;
303  m_t << "</pre>";
305  }
306  break;
307  case DocStyleChange::Div:
308  if (s->enable())
309  {
311  m_t << "<div" << htmlAttribsToString(s->attribs()) << ">";
312  }
313  else
314  {
315  m_t << "</div>";
317  }
318  break;
320  if (s->enable()) m_t << "<span" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</span>";
321  break;
322 
323  }
324 }
325 
326 
328 {
329  if (s->hasCaption())
330  {
331  t << "<div class=\"caption\">" << endl;
332  }
333 }
334 
335 
337 {
338  if (s->hasCaption())
339  {
340  t << "</div>" << endl;
341  }
342 }
343 
344 
345 static void visitCaption(HtmlDocVisitor *parent, QList<DocNode> children)
346 {
347  QListIterator<DocNode> cli(children);
348  DocNode *n;
349  for (cli.toFirst();(n=cli.current());++cli) n->accept(parent);
350 }
351 
352 
354 {
355  if (m_hide) return;
356  QCString lang = m_langExt;
357  if (!s->language().isEmpty()) // explicit language setting
358  {
359  lang = s->language();
360  }
361  SrcLangExt langExt = getLanguageFromFileName(lang);
362  switch(s->type())
363  {
364  case DocVerbatim::Code:
366  m_t << PREFRAG_START;
368  ->parseCode(m_ci,
369  s->context(),
370  s->text(),
371  langExt,
372  s->isExample(),
373  s->exampleFile(),
374  0, // fileDef
375  -1, // startLine
376  -1, // endLine
377  FALSE, // inlineFragment
378  0, // memberDef
379  TRUE, // show line numbers
380  m_ctx // search context
381  );
382  m_t << PREFRAG_END;
384  break;
385  case DocVerbatim::Verbatim:
387  m_t << /*PREFRAG_START <<*/ "<pre class=\"fragment\">";
388  filter(s->text());
389  m_t << "</pre>" /*<< PREFRAG_END*/;
391  break;
392  case DocVerbatim::HtmlOnly:
393  if (s->isBlock()) forceEndParagraph(s);
394  m_t << s->text();
395  if (s->isBlock()) forceStartParagraph(s);
396  break;
397  case DocVerbatim::ManOnly:
399  case DocVerbatim::XmlOnly:
402  /* nothing */
403  break;
404 
405  case DocVerbatim::Dot:
406  {
407  static int dotindex = 1;
408  QCString fileName(4096);
409 
411  fileName.sprintf("%s%d%s",
412  (Config_getString(HTML_OUTPUT)+"/inline_dotgraph_").data(),
413  dotindex++,
414  ".dot"
415  );
416  QFile file(fileName);
417  if (!file.open(IO_WriteOnly))
418  {
419  err("Could not open file %s for writing\n",fileName.data());
420  }
421  else
422  {
423  file.writeBlock( s->text(), s->text().length() );
424  file.close();
425 
426  m_t << "<div align=\"center\">" << endl;
427  writeDotFile(fileName,s->relPath(),s->context());
428  visitPreCaption(m_t, s);
429  visitCaption(this, s->children());
430  visitPostCaption(m_t, s);
431  m_t << "</div>" << endl;
432 
433  if (Config_getBool(DOT_CLEANUP)) file.remove();
434  }
436  }
437  break;
438  case DocVerbatim::Msc:
439  {
441 
442  static int mscindex = 1;
443  QCString baseName(4096);
444 
445  baseName.sprintf("%s%d",
446  (Config_getString(HTML_OUTPUT)+"/inline_mscgraph_").data(),
447  mscindex++
448  );
449  QFile file(baseName+".msc");
450  if (!file.open(IO_WriteOnly))
451  {
452  err("Could not open file %s.msc for writing\n",baseName.data());
453  }
454  else
455  {
456  QCString text = "msc {";
457  text+=s->text();
458  text+="}";
459 
460  file.writeBlock( text, text.length() );
461  file.close();
462 
463  m_t << "<div align=\"center\">" << endl;
464  writeMscFile(baseName+".msc",s->relPath(),s->context());
465  visitPreCaption(m_t, s);
466  visitCaption(this, s->children());
467  visitPostCaption(m_t, s);
468  m_t << "</div>" << endl;
469 
470  if (Config_getBool(DOT_CLEANUP)) file.remove();
471  }
473  }
474  break;
476  {
478 
479  static QCString htmlOutput = Config_getString(HTML_OUTPUT);
480  QCString baseName = writePlantUMLSource(htmlOutput,s->exampleFile(),s->text());
481  m_t << "<div align=\"center\">" << endl;
482  writePlantUMLFile(baseName,s->relPath(),s->context());
483  visitPreCaption(m_t, s);
484  visitCaption(this, s->children());
485  visitPostCaption(m_t, s);
486  m_t << "</div>" << endl;
488  }
489  break;
490  }
491 }
492 
494 {
495  if (m_hide) return;
496  m_t << "<a class=\"anchor\" id=\"" << anc->anchor() << "\"></a>";
497 }
498 
500 {
501  if (m_hide) return;
502  SrcLangExt langExt = getLanguageFromFileName(inc->extension());
503  switch(inc->type())
504  {
505  case DocInclude::Include:
506  forceEndParagraph(inc);
507  m_t << PREFRAG_START;
509  ->parseCode(m_ci,
510  inc->context(),
511  inc->text(),
512  langExt,
513  inc->isExample(),
514  inc->exampleFile(),
515  0, // fileDef
516  -1, // startLine
517  -1, // endLine
518  TRUE, // inlineFragment
519  0, // memberDef
520  FALSE, // show line numbers
521  m_ctx // search context
522  );
523  m_t << PREFRAG_END;
524  forceStartParagraph(inc);
525  break;
527  {
528  forceEndParagraph(inc);
529  m_t << PREFRAG_START;
530  QFileInfo cfi( inc->file() );
531  FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
533  ->parseCode(m_ci,
534  inc->context(),
535  inc->text(),
536  langExt,
537  inc->isExample(),
538  inc->exampleFile(),
539  &fd, // fileDef,
540  -1, // start line
541  -1, // end line
542  FALSE, // inline fragment
543  0, // memberDef
544  TRUE, // show line numbers
545  m_ctx // search context
546  );
547  m_t << PREFRAG_END;
548  forceStartParagraph(inc);
549  }
550  break;
552  break;
554  m_t << inc->text();
555  break;
557  break;
559  forceEndParagraph(inc);
560  m_t << /*PREFRAG_START <<*/ "<pre class=\"fragment\">";
561  filter(inc->text());
562  m_t << "</pre>" /*<< PREFRAG_END*/;
563  forceStartParagraph(inc);
564  break;
565  case DocInclude::Snippet:
566  {
567  forceEndParagraph(inc);
568  m_t << PREFRAG_START;
570  ->parseCode(m_ci,
571  inc->context(),
572  extractBlock(inc->text(),inc->blockId()),
573  langExt,
574  inc->isExample(),
575  inc->exampleFile(),
576  0,
577  -1, // startLine
578  -1, // endLine
579  TRUE, // inlineFragment
580  0, // memberDef
581  TRUE, // show line number
582  m_ctx // search context
583  );
584  m_t << PREFRAG_END;
585  forceStartParagraph(inc);
586  }
587  break;
590  err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
591  "Please create a bug report\n",__FILE__);
592  break;
593  }
594 }
595 
597 {
598  //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
599  // op->type(),op->isFirst(),op->isLast(),op->text().data());
600  if (op->isFirst())
601  {
602  if (!m_hide) m_t << PREFRAG_START;
603  pushEnabled();
604  m_hide=TRUE;
605  }
607  if (op->type()!=DocIncOperator::Skip)
608  {
609  popEnabled();
610  if (!m_hide)
611  {
613  ->parseCode(
614  m_ci,
615  op->context(),
616  op->text(),
617  langExt,
618  op->isExample(),
619  op->exampleFile(),
620  0, // fileDef
621  -1, // startLine
622  -1, // endLine
623  FALSE, // inline fragment
624  0, // memberDef
625  TRUE, // show line numbers
626  m_ctx // search context
627  );
628  }
629  pushEnabled();
630  m_hide=TRUE;
631  }
632  if (op->isLast())
633  {
634  popEnabled();
635  if (!m_hide) m_t << PREFRAG_END;
636  }
637  else
638  {
639  if (!m_hide) m_t << endl;
640  }
641 }
642 
644 {
645  if (m_hide) return;
646  bool bDisplay = !f->isInline();
647  if (bDisplay)
648  {
650  m_t << "<p class=\"formulaDsp\">" << endl;
651  }
652 
653  if (Config_getBool(USE_MATHJAX))
654  {
655  QCString text = f->text();
656  bool closeInline = FALSE;
657  if (!bDisplay && !text.isEmpty() && text.at(0)=='$' &&
658  text.at(text.length()-1)=='$')
659  {
660  closeInline=TRUE;
661  text = text.mid(1,text.length()-2);
662  m_t << "\\(";
663  }
664  m_t << convertToHtml(text);
665  if (closeInline)
666  {
667  m_t << "\\)";
668  }
669  }
670  else
671  {
672  m_t << "<img class=\"formula"
673  << (bDisplay ? "Dsp" : "Inl");
674  m_t << "\" alt=\"";
676  m_t << "\"";
677  // TODO: cache image dimensions on formula generation and give height/width
678  // for faster preloading and better rendering of the page
679  m_t << " src=\"" << f->relPath() << f->name() << ".png\"/>";
680 
681  }
682  if (bDisplay)
683  {
684  m_t << endl << "</p>" << endl;
686  }
687 }
688 
690 {
691  QCString anchor = convertIndexWordToAnchor(e->entry());
692  if (e->member())
693  {
694  anchor.prepend(e->member()->anchor()+"_");
695  }
696  m_t << "<a name=\"" << anchor << "\"></a>";
697  //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n",
698  // e->entry().data(),
699  // e->scope() ? e->scope()->name().data() : "<null>",
700  // e->member() ? e->member()->name().data() : "<null>"
701  // );
702  Doxygen::indexList->addIndexItem(e->scope(),e->member(),anchor,e->entry());
703 }
704 
706 {
707  m_t << "</dd>" << endl;
708  m_t << "<dd>" << endl;
709 }
710 
712 {
713  if (m_hide) return;
714  if (!cite->file().isEmpty())
715  {
716  startLink(cite->ref(),cite->file(),cite->relPath(),cite->anchor());
717  }
718  else
719  {
720  m_t << "<b>[";
721  }
722  filter(cite->text());
723  if (!cite->file().isEmpty())
724  {
725  endLink();
726  }
727  else
728  {
729  m_t << "]</b>";
730  }
731 }
732 
733 
734 //--------------------------------------
735 // visitor functions for compound nodes
736 //--------------------------------------
737 
738 
740 {
741  //printf("DocAutoList::visitPre\n");
742  if (m_hide) return;
744  if (l->isEnumList())
745  {
746  //
747  // Do list type based on depth:
748  // 1.
749  // a.
750  // i.
751  // A.
752  // 1. (repeat)...
753  //
754  m_t << "<ol type=\"" << types[l->depth() % NUM_HTML_LIST_TYPES] << "\">";
755  }
756  else
757  {
758  m_t << "<ul>";
759  }
760  if (!l->isPreformatted()) m_t << "\n";
761 }
762 
764 {
765  //printf("DocAutoList::visitPost\n");
766  if (m_hide) return;
767  if (l->isEnumList())
768  {
769  m_t << "</ol>";
770  }
771  else
772  {
773  m_t << "</ul>";
774  }
775  if (!l->isPreformatted()) m_t << "\n";
777 }
778 
780 {
781  if (m_hide) return;
782  m_t << "<li>";
783 }
784 
786 {
787  if (m_hide) return;
788  m_t << "</li>";
789  if (!li->isPreformatted()) m_t << "\n";
790 }
791 
792 template<class T>
793 bool isFirstChildNode(T *parent, DocNode *node)
794 {
795  return parent->children().getFirst()==node;
796 }
797 
798 template<class T>
799 bool isLastChildNode(T *parent, DocNode *node)
800 {
801  return parent->children().getLast()==node;
802 }
803 
805 {
806  QList<DocNode> nodes = parent->children();
807  int i = nodes.findRef(par);
808  if (i==-1) return FALSE;
809  int count = parent->children().count();
810  if (count>1 && i==0) // first node
811  {
812  if (nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
813  {
814  return TRUE;
815  }
816  }
817  else if (count>1 && i==count-1) // last node
818  {
819  if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep)
820  {
821  return TRUE;
822  }
823  }
824  else if (count>2 && i>0 && i<count-1) // intermediate node
825  {
826  if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep &&
827  nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
828  {
829  return TRUE;
830  }
831  }
832  return FALSE;
833 }
834 
835 static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
836 {
837  int t=0;
838  isFirst=FALSE;
839  isLast=FALSE;
840  if (p && p->parent())
841  {
842  switch (p->parent()->kind())
843  {
845  { // hierarchy: node N -> para -> parblock -> para
846  // adapt return value to kind of N
848  if ( p->parent()->parent() && p->parent()->parent()->parent() )
849  {
850  kind = p->parent()->parent()->parent()->kind();
851  }
852  isFirst=isFirstChildNode((DocParBlock*)p->parent(),p);
853  isLast =isLastChildNode ((DocParBlock*)p->parent(),p);
854  t=0;
855  if (isFirst)
856  {
857  if (kind==DocNode::Kind_HtmlListItem ||
859  {
860  t=1;
861  }
862  else if (kind==DocNode::Kind_HtmlDescData ||
863  kind==DocNode::Kind_XRefItem ||
865  {
866  t=2;
867  }
868  else if (kind==DocNode::Kind_HtmlCell ||
870  {
871  t=5;
872  }
873  }
874  if (isLast)
875  {
876  if (kind==DocNode::Kind_HtmlListItem ||
878  {
879  t=3;
880  }
881  else if (kind==DocNode::Kind_HtmlDescData ||
882  kind==DocNode::Kind_XRefItem ||
884  {
885  t=4;
886  }
887  else if (kind==DocNode::Kind_HtmlCell ||
889  {
890  t=6;
891  }
892  }
893  break;
894  }
896  isFirst=isFirstChildNode((DocAutoListItem*)p->parent(),p);
897  isLast =isLastChildNode ((DocAutoListItem*)p->parent(),p);
898  t=1; // not used
899  break;
901  isFirst=TRUE;
902  isLast =TRUE;
903  t=1; // not used
904  break;
906  isFirst=TRUE;
907  isLast =TRUE;
908  t=1; // not used
909  break;
911  isFirst=isFirstChildNode((DocHtmlListItem*)p->parent(),p);
912  isLast =isLastChildNode ((DocHtmlListItem*)p->parent(),p);
913  if (isFirst) t=1;
914  if (isLast) t=3;
915  break;
917  isFirst=isFirstChildNode((DocSecRefItem*)p->parent(),p);
918  isLast =isLastChildNode ((DocSecRefItem*)p->parent(),p);
919  if (isFirst) t=1;
920  if (isLast) t=3;
921  break;
923  isFirst=isFirstChildNode((DocHtmlDescData*)p->parent(),p);
924  isLast =isLastChildNode ((DocHtmlDescData*)p->parent(),p);
925  if (isFirst) t=2;
926  if (isLast) t=4;
927  break;
929  isFirst=isFirstChildNode((DocXRefItem*)p->parent(),p);
930  isLast =isLastChildNode ((DocXRefItem*)p->parent(),p);
931  if (isFirst) t=2;
932  if (isLast) t=4;
933  break;
935  isFirst=isFirstChildNode((DocSimpleSect*)p->parent(),p);
936  isLast =isLastChildNode ((DocSimpleSect*)p->parent(),p);
937  if (isFirst) t=2;
938  if (isLast) t=4;
940  // if the paragraph is enclosed with separators it will
941  // be included in <dd>..</dd> so avoid addition paragraph
942  // markers
943  {
944  isFirst=isLast=TRUE;
945  }
946  break;
948  isFirst=isFirstChildNode((DocHtmlCell*)p->parent(),p);
949  isLast =isLastChildNode ((DocHtmlCell*)p->parent(),p);
950  if (isFirst) t=5;
951  if (isLast) t=6;
952  break;
953  default:
954  break;
955  }
956  //printf("para=%p parent()->kind=%d isFirst=%d isLast=%d t=%d\n",
957  // p,p->parent()->kind(),isFirst,isLast,t);
958  }
959  return t;
960 }
961 
963 {
964  if (m_hide) return;
965 
966  //printf("DocPara::visitPre: parent of kind %d ",
967  // p->parent() ? p->parent()->kind() : -1);
968 
969  bool needsTag = FALSE;
970  if (p && p->parent())
971  {
972  switch (p->parent()->kind())
973  {
983  case DocNode::Kind_Copy:
986  needsTag = TRUE;
987  break;
988  case DocNode::Kind_Root:
989  needsTag = !((DocRoot*)p->parent())->singleLine();
990  break;
991  default:
992  needsTag = FALSE;
993  }
994  }
995 
996  // if the first element of a paragraph is something that should be outside of
997  // the paragraph (<ul>,<dl>,<table>,..) then that will already started the
998  // paragraph and we don't need to do it here
999  uint nodeIndex = 0;
1000  if (p && nodeIndex<p->children().count())
1001  {
1002  while (nodeIndex<p->children().count() &&
1003  p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace)
1004  {
1005  nodeIndex++;
1006  }
1007  if (nodeIndex<p->children().count())
1008  {
1009  DocNode *n = p->children().at(nodeIndex);
1010  if (mustBeOutsideParagraph(n))
1011  {
1012  needsTag = FALSE;
1013  }
1014  }
1015  }
1016 
1017  // check if this paragraph is the first or last child of a <li> or <dd>.
1018  // this allows us to mark the tag with a special class so we can
1019  // fix the otherwise ugly spacing.
1020  int t;
1021  static const char *contexts[7] =
1022  { "", // 0
1023  " class=\"startli\"", // 1
1024  " class=\"startdd\"", // 2
1025  " class=\"endli\"", // 3
1026  " class=\"enddd\"", // 4
1027  " class=\"starttd\"", // 5
1028  " class=\"endtd\"" // 6
1029  };
1030  bool isFirst;
1031  bool isLast;
1032  t = getParagraphContext(p,isFirst,isLast);
1033  //printf("startPara first=%d last=%d\n",isFirst,isLast);
1034  if (isFirst && isLast) needsTag=FALSE;
1035 
1036  //printf(" needsTag=%d\n",needsTag);
1037  // write the paragraph tag (if needed)
1038  if (needsTag) m_t << "<p" << contexts[t] << ">";
1039 }
1040 
1042 {
1043  bool needsTag = FALSE;
1044  if (p->parent())
1045  {
1046  switch (p->parent()->kind())
1047  {
1048  case DocNode::Kind_Section:
1057  case DocNode::Kind_Copy:
1060  needsTag = TRUE;
1061  break;
1062  case DocNode::Kind_Root:
1063  needsTag = !((DocRoot*)p->parent())->singleLine();
1064  break;
1065  default:
1066  needsTag = FALSE;
1067  }
1068  }
1069 
1070  // if the last element of a paragraph is something that should be outside of
1071  // the paragraph (<ul>,<dl>,<table>) then that will already have ended the
1072  // paragraph and we don't need to do it here
1073  int nodeIndex = p->children().count()-1;
1074  if (nodeIndex>=0)
1075  {
1076  while (nodeIndex>=0 && p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace)
1077  {
1078  nodeIndex--;
1079  }
1080  if (nodeIndex>=0)
1081  {
1082  DocNode *n = p->children().at(nodeIndex);
1083  if (mustBeOutsideParagraph(n))
1084  {
1085  needsTag = FALSE;
1086  }
1087  }
1088  }
1089 
1090  bool isFirst;
1091  bool isLast;
1092  getParagraphContext(p,isFirst,isLast);
1093  //printf("endPara first=%d last=%d\n",isFirst,isLast);
1094  if (isFirst && isLast) needsTag=FALSE;
1095 
1096  //printf("DocPara::visitPost needsTag=%d\n",needsTag);
1097 
1098  if (needsTag) m_t << "</p>\n";
1099 
1100 }
1101 
1103 {
1104 }
1105 
1107 {
1108 }
1109 
1111 {
1112  if (m_hide) return;
1113  forceEndParagraph(s);
1114  m_t << "<dl class=\"section " << s->typeString() << "\"><dt>";
1115  switch(s->type())
1116  {
1117  case DocSimpleSect::See:
1118  m_t << theTranslator->trSeeAlso(); break;
1119  case DocSimpleSect::Return:
1120  m_t << theTranslator->trReturns(); break;
1121  case DocSimpleSect::Author:
1122  m_t << theTranslator->trAuthor(TRUE,TRUE); break;
1123  case DocSimpleSect::Authors:
1124  m_t << theTranslator->trAuthor(TRUE,FALSE); break;
1125  case DocSimpleSect::Version:
1126  m_t << theTranslator->trVersion(); break;
1127  case DocSimpleSect::Since:
1128  m_t << theTranslator->trSince(); break;
1129  case DocSimpleSect::Date:
1130  m_t << theTranslator->trDate(); break;
1131  case DocSimpleSect::Note:
1132  m_t << theTranslator->trNote(); break;
1134  m_t << theTranslator->trWarning(); break;
1135  case DocSimpleSect::Pre:
1136  m_t << theTranslator->trPrecondition(); break;
1137  case DocSimpleSect::Post:
1138  m_t << theTranslator->trPostcondition(); break;
1140  m_t << theTranslator->trCopyright(); break;
1141  case DocSimpleSect::Invar:
1142  m_t << theTranslator->trInvariant(); break;
1143  case DocSimpleSect::Remark:
1144  m_t << theTranslator->trRemarks(); break;
1146  m_t << theTranslator->trAttention(); break;
1147  case DocSimpleSect::User: break;
1148  case DocSimpleSect::Rcs: break;
1149  case DocSimpleSect::Unknown: break;
1150  }
1151 
1152  // special case 1: user defined title
1153  if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
1154  {
1155  m_t << "</dt><dd>";
1156  }
1157 }
1158 
1160 {
1161  if (m_hide) return;
1162  m_t << "</dd></dl>\n";
1164 }
1165 
1167 {
1168 }
1169 
1171 {
1172  if (m_hide) return;
1173  m_t << "</dt><dd>";
1174 }
1175 
1177 {
1178  if (m_hide) return;
1179  forceEndParagraph(sl);
1180  m_t << "<ul>";
1181  if (!sl->isPreformatted()) m_t << "\n";
1182 
1183 }
1184 
1186 {
1187  if (m_hide) return;
1188  m_t << "</ul>";
1189  if (!sl->isPreformatted()) m_t << "\n";
1190  forceStartParagraph(sl);
1191 }
1192 
1194 {
1195  if (m_hide) return;
1196  m_t << "<li>";
1197 }
1198 
1200 {
1201  if (m_hide) return;
1202  m_t << "</li>";
1203  if (!li->isPreformatted()) m_t << "\n";
1204 }
1205 
1207 {
1208  if (m_hide) return;
1209  forceEndParagraph(s);
1210  m_t << "<h" << s->level() << ">";
1211  m_t << "<a class=\"anchor\" id=\"" << s->anchor();
1212  m_t << "\"></a>" << endl;
1213  filter(convertCharEntitiesToUTF8(s->title().data()));
1214  m_t << "</h" << s->level() << ">\n";
1215 }
1216 
1218 {
1220 }
1221 
1223 {
1224  if (m_hide) return;
1225  forceEndParagraph(s);
1226  if (s->type()==DocHtmlList::Ordered)
1227  {
1228  m_t << "<ol" << htmlAttribsToString(s->attribs()) << ">\n";
1229  }
1230  else
1231  {
1232  m_t << "<ul" << htmlAttribsToString(s->attribs()) << ">\n";
1233  }
1234 }
1235 
1237 {
1238  if (m_hide) return;
1239  if (s->type()==DocHtmlList::Ordered)
1240  {
1241  m_t << "</ol>";
1242  }
1243  else
1244  {
1245  m_t << "</ul>";
1246  }
1247  if (!s->isPreformatted()) m_t << "\n";
1249 }
1250 
1252 {
1253  if (m_hide) return;
1254  m_t << "<li" << htmlAttribsToString(i->attribs()) << ">";
1255  if (!i->isPreformatted()) m_t << "\n";
1256 }
1257 
1259 {
1260  if (m_hide) return;
1261  m_t << "</li>\n";
1262 }
1263 
1265 {
1266  if (m_hide) return;
1267  forceEndParagraph(dl);
1268  m_t << "<dl" << htmlAttribsToString(dl->attribs()) << ">\n";
1269 }
1270 
1272 {
1273  if (m_hide) return;
1274  m_t << "</dl>\n";
1275  forceStartParagraph(dl);
1276 }
1277 
1279 {
1280  if (m_hide) return;
1281  m_t << "<dt" << htmlAttribsToString(dt->attribs()) << ">";
1282 }
1283 
1285 {
1286  if (m_hide) return;
1287  m_t << "</dt>\n";
1288 }
1289 
1291 {
1292  if (m_hide) return;
1293  m_t << "<dd" << htmlAttribsToString(dd->attribs()) << ">";
1294 }
1295 
1297 {
1298  if (m_hide) return;
1299  m_t << "</dd>\n";
1300 }
1301 
1303 {
1304  if (m_hide) return;
1305 
1306  forceEndParagraph(t);
1307 
1308  if (t->hasCaption())
1309  {
1310  m_t << "<a class=\"anchor\" id=\"" << t->caption()->anchor() << "\"></a>\n";
1311  }
1312 
1313  QString attrs = htmlAttribsToString(t->attribs());
1314  if (attrs.isEmpty())
1315  {
1316  m_t << "<table class=\"doxtable\">\n";
1317  }
1318  else
1319  {
1320  m_t << "<table" << htmlAttribsToString(t->attribs()) << ">\n";
1321  }
1322 }
1323 
1325 {
1326  if (m_hide) return;
1327  m_t << "</table>\n";
1329 }
1330 
1332 {
1333  if (m_hide) return;
1334  m_t << "<tr" << htmlAttribsToString(tr->attribs()) << ">\n";
1335 }
1336 
1338 {
1339  if (m_hide) return;
1340  m_t << "</tr>\n";
1341 }
1342 
1344 {
1345  if (m_hide) return;
1346  if (c->isHeading())
1347  {
1348  m_t << "<th" << htmlAttribsToString(c->attribs()) << ">";
1349  }
1350  else
1351  {
1352  m_t << "<td" << htmlAttribsToString(c->attribs()) << ">";
1353  }
1354 }
1355 
1357 {
1358  if (m_hide) return;
1359  if (c->isHeading()) m_t << "</th>"; else m_t << "</td>";
1360 }
1361 
1363 {
1364  if (m_hide) return;
1365  m_t << "<caption" << htmlAttribsToString(c->attribs()) << ">";
1366 }
1367 
1369 {
1370  if (m_hide) return;
1371  m_t << "</caption>\n";
1372 }
1373 
1375 {
1376  if (m_hide) return;
1377  //forceEndParagraph(i);
1378  //m_t << "<p><b>" << theTranslator->trForInternalUseOnly() << "</b></p>" << endl;
1379 }
1380 
1382 {
1383  if (m_hide) return;
1384  //forceStartParagraph(i);
1385 }
1386 
1388 {
1389  if (m_hide) return;
1390  if (href->url().left(7)=="mailto:")
1391  {
1392  writeObfuscatedMailAddress(href->url().mid(7));
1393  }
1394  else
1395  {
1396  QCString url = correctURL(href->url(),href->relPath());
1397  m_t << "<a href=\"" << convertToXML(url) << "\""
1398  << htmlAttribsToString(href->attribs()) << ">";
1399  }
1400 }
1401 
1403 {
1404  if (m_hide) return;
1405  m_t << "</a>";
1406 }
1407 
1409 {
1410  if (m_hide) return;
1411  forceEndParagraph(header);
1412  m_t << "<h" << header->level()
1413  << htmlAttribsToString(header->attribs()) << ">";
1414 }
1415 
1417 {
1418  if (m_hide) return;
1419  m_t << "</h" << header->level() << ">\n";
1420  forceStartParagraph(header);
1421 }
1422 
1424 {
1425  if (img->type()==DocImage::Html)
1426  {
1427  forceEndParagraph(img);
1428  if (m_hide) return;
1429  QString baseName=img->name();
1430  int i;
1431  if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1)
1432  {
1433  baseName=baseName.right(baseName.length()-i-1);
1434  }
1435  m_t << "<div class=\"image\">" << endl;
1436  QCString url = img->url();
1437  QCString sizeAttribs;
1438  if (!img->width().isEmpty())
1439  {
1440  sizeAttribs+=" width=\""+img->width()+"\"";
1441  }
1442  if (!img->height().isEmpty())
1443  {
1444  sizeAttribs+=" height=\""+img->height()+"\"";
1445  }
1446  if (url.isEmpty())
1447  {
1448  if (img->name().right(4)==".svg")
1449  {
1450  m_t << "<object type=\"image/svg+xml\" data=\"" << img->relPath() << img->name()
1451  << "\"" << sizeAttribs << htmlAttribsToString(img->attribs()) << ">" << baseName
1452  << "</object>" << endl;
1453  }
1454  else
1455  {
1456  m_t << "<img src=\"" << img->relPath() << img->name() << "\" alt=\""
1457  << baseName << "\"" << sizeAttribs << htmlAttribsToString(img->attribs())
1458  << "/>" << endl;
1459  }
1460  }
1461  else
1462  {
1463  if (url.right(4)==".svg")
1464  {
1465  m_t << "<object type=\"image/svg+xml\" data=\"" << correctURL(url,img->relPath())
1466  << "\"" << sizeAttribs << htmlAttribsToString(img->attribs()) << "></object>" << endl;
1467  }
1468  else
1469  {
1470  m_t << "<img src=\"" << correctURL(url,img->relPath()) << "\""
1471  << sizeAttribs << htmlAttribsToString(img->attribs())
1472  << "/>" << endl;
1473  }
1474  }
1475  if (img->hasCaption())
1476  {
1477  m_t << "<div class=\"caption\">" << endl;
1478  }
1479  }
1480  else // other format -> skip
1481  {
1482  pushEnabled();
1483  m_hide=TRUE;
1484  }
1485 }
1486 
1488 {
1489  if (img->type()==DocImage::Html)
1490  {
1491  if (m_hide) return;
1492  if (img->hasCaption())
1493  {
1494  m_t << "</div>";
1495  }
1496  m_t << "</div>" << endl;
1497  forceStartParagraph(img);
1498  }
1499  else // other format
1500  {
1501  popEnabled();
1502  }
1503 }
1504 
1506 {
1507  if (m_hide) return;
1508  m_t << "<div class=\"dotgraph\">" << endl;
1509  writeDotFile(df->file(),df->relPath(),df->context());
1510  if (df->hasCaption())
1511  {
1512  m_t << "<div class=\"caption\">" << endl;
1513  }
1514 }
1515 
1517 {
1518  if (m_hide) return;
1519  if (df->hasCaption())
1520  {
1521  m_t << "</div>" << endl;
1522  }
1523  m_t << "</div>" << endl;
1524 }
1525 
1527 {
1528  if (m_hide) return;
1529  m_t << "<div class=\"mscgraph\">" << endl;
1530  writeMscFile(df->file(),df->relPath(),df->context());
1531  if (df->hasCaption())
1532  {
1533  m_t << "<div class=\"caption\">" << endl;
1534  }
1535 }
1537 {
1538  if (m_hide) return;
1539  if (df->hasCaption())
1540  {
1541  m_t << "</div>" << endl;
1542  }
1543  m_t << "</div>" << endl;
1544 }
1545 
1547 {
1548  if (m_hide) return;
1549  m_t << "<div class=\"diagraph\">" << endl;
1550  writeDiaFile(df->file(),df->relPath(),df->context());
1551  if (df->hasCaption())
1552  {
1553  m_t << "<div class=\"caption\">" << endl;
1554  }
1555 }
1557 {
1558  if (m_hide) return;
1559  if (df->hasCaption())
1560  {
1561  m_t << "</div>" << endl;
1562  }
1563  m_t << "</div>" << endl;
1564 }
1565 
1567 {
1568  if (m_hide) return;
1569  startLink(lnk->ref(),lnk->file(),lnk->relPath(),lnk->anchor());
1570 }
1571 
1573 {
1574  if (m_hide) return;
1575  endLink();
1576 }
1577 
1579 {
1580  if (m_hide) return;
1581  if (!ref->file().isEmpty())
1582  {
1583  // when ref->isSubPage()==TRUE we use ref->file() for HTML and
1584  // ref->anchor() for LaTeX/RTF
1585  startLink(ref->ref(),ref->file(),ref->relPath(),ref->isSubPage() ? QCString() : ref->anchor());
1586  }
1587  if (!ref->hasLinkText()) filter(ref->targetTitle());
1588 }
1589 
1591 {
1592  if (m_hide) return;
1593  if (!ref->file().isEmpty()) endLink();
1594  //m_t << " ";
1595 }
1596 
1598 {
1599  if (m_hide) return;
1600  QString refName=ref->file();
1601  if (refName.right(Doxygen::htmlFileExtension.length())!=
1602  QString(Doxygen::htmlFileExtension))
1603  {
1604  refName+=Doxygen::htmlFileExtension;
1605  }
1606  m_t << "<li><a href=\"" << refName << "#" << ref->anchor() << "\">";
1607 
1608 }
1609 
1611 {
1612  if (m_hide) return;
1613  m_t << "</a></li>\n";
1614 }
1615 
1617 {
1618  if (m_hide) return;
1619  forceEndParagraph(s);
1620  m_t << "<div class=\"multicol\">" << endl;
1621  m_t << "<ul>" << endl;
1622 }
1623 
1625 {
1626  if (m_hide) return;
1627  m_t << "</ul>" << endl;
1628  m_t << "</div>" << endl;
1630 }
1631 
1632 //void HtmlDocVisitor::visitPre(DocLanguage *l)
1633 //{
1634 // QString langId = Config_getEnum(OUTPUT_LANGUAGE);
1635 // if (l->id().lower()!=langId.lower())
1636 // {
1637 // pushEnabled();
1638 // m_hide = TRUE;
1639 // }
1640 //}
1641 //
1642 //void HtmlDocVisitor::visitPost(DocLanguage *l)
1643 //{
1644 // QString langId = Config_getEnum(OUTPUT_LANGUAGE);
1645 // if (l->id().lower()!=langId.lower())
1646 // {
1647 // popEnabled();
1648 // }
1649 //}
1650 
1652 {
1653  if (m_hide) return;
1654  forceEndParagraph(s);
1655  QCString className;
1656  QCString heading;
1657  switch(s->type())
1658  {
1659  case DocParamSect::Param:
1660  heading=theTranslator->trParameters();
1661  className="params";
1662  break;
1663  case DocParamSect::RetVal:
1664  heading=theTranslator->trReturnValues();
1665  className="retval";
1666  break;
1668  heading=theTranslator->trExceptions();
1669  className="exception";
1670  break;
1673  className="tparams";
1674  break;
1675  default:
1676  ASSERT(0);
1677  }
1678  m_t << "<dl class=\"" << className << "\"><dt>";
1679  m_t << heading;
1680  m_t << "</dt><dd>" << endl;
1681  m_t << " <table class=\"" << className << "\">" << endl;
1682 }
1683 
1685 {
1686  if (m_hide) return;
1687  m_t << " </table>" << endl;
1688  m_t << " </dd>" << endl;
1689  m_t << "</dl>" << endl;
1691 }
1692 
1694 {
1695  //printf("DocParamList::visitPre\n");
1696  if (m_hide) return;
1697  m_t << " <tr>";
1698  DocParamSect *sect = 0;
1699  if (pl->parent()->kind()==DocNode::Kind_ParamSect)
1700  {
1701  sect=(DocParamSect*)pl->parent();
1702  }
1703  if (sect && sect->hasInOutSpecifier())
1704  {
1705  m_t << "<td class=\"paramdir\">";
1707  {
1708  m_t << "[";
1709  if (pl->direction()==DocParamSect::In)
1710  {
1711  m_t << "in";
1712  }
1713  else if (pl->direction()==DocParamSect::Out)
1714  {
1715  m_t << "out";
1716  }
1717  else if (pl->direction()==DocParamSect::InOut)
1718  {
1719  m_t << "in,out";
1720  }
1721  m_t << "]";
1722  }
1723  m_t << "</td>";
1724  }
1725  if (sect && sect->hasTypeSpecifier())
1726  {
1727  m_t << "<td class=\"paramtype\">";
1728  QListIterator<DocNode> li(pl->paramTypes());
1729  DocNode *type;
1730  bool first=TRUE;
1731  for (li.toFirst();(type=li.current());++li)
1732  {
1733  if (!first) m_t << "&#160;|&#160;"; else first=FALSE;
1734  if (type->kind()==DocNode::Kind_Word)
1735  {
1736  visit((DocWord*)type);
1737  }
1738  else if (type->kind()==DocNode::Kind_LinkedWord)
1739  {
1740  visit((DocLinkedWord*)type);
1741  }
1742  }
1743  m_t << "</td>";
1744  }
1745  m_t << "<td class=\"paramname\">";
1746  //QStrListIterator li(pl->parameters());
1747  //const char *s;
1748  QListIterator<DocNode> li(pl->parameters());
1749  DocNode *param;
1750  bool first=TRUE;
1751  for (li.toFirst();(param=li.current());++li)
1752  {
1753  if (!first) m_t << ","; else first=FALSE;
1754  if (param->kind()==DocNode::Kind_Word)
1755  {
1756  visit((DocWord*)param);
1757  }
1758  else if (param->kind()==DocNode::Kind_LinkedWord)
1759  {
1760  visit((DocLinkedWord*)param);
1761  }
1762  }
1763  m_t << "</td><td>";
1764 }
1765 
1767 {
1768  //printf("DocParamList::visitPost\n");
1769  if (m_hide) return;
1770  m_t << "</td></tr>" << endl;
1771 }
1772 
1774 {
1775  if (m_hide) return;
1776  if (x->title().isEmpty()) return;
1777 
1778  forceEndParagraph(x);
1779  bool anonymousEnum = x->file()=="@";
1780  if (!anonymousEnum)
1781  {
1782  m_t << "<dl class=\"" << x->key() << "\"><dt><b><a class=\"el\" href=\""
1783  << x->relPath() << x->file() << Doxygen::htmlFileExtension
1784  << "#" << x->anchor() << "\">";
1785  }
1786  else
1787  {
1788  m_t << "<dl class=\"" << x->key() << "\"><dt><b>";
1789  }
1790  filter(x->title());
1791  m_t << ":";
1792  if (!anonymousEnum) m_t << "</a>";
1793  m_t << "</b></dt><dd>";
1794 }
1795 
1797 {
1798  if (m_hide) return;
1799  if (x->title().isEmpty()) return;
1800  m_t << "</dd></dl>" << endl;
1802 }
1803 
1805 {
1806  if (m_hide) return;
1807  startLink(0,ref->file(),ref->relPath(),ref->anchor());
1808 }
1809 
1811 {
1812  if (m_hide) return;
1813  endLink();
1814  m_t << " ";
1815 }
1816 
1818 {
1819 }
1820 
1822 {
1823 }
1824 
1826 {
1827 }
1828 
1830 {
1831 }
1832 
1834 {
1835  if (m_hide) return;
1836  forceEndParagraph(b);
1837  QString attrs = htmlAttribsToString(b->attribs());
1838  if (attrs.isEmpty())
1839  {
1840  m_t << "<blockquote class=\"doxtable\">\n";
1841  }
1842  else
1843  {
1844  m_t << "<blockquote" << htmlAttribsToString(b->attribs()) << ">\n";
1845  }
1846 }
1847 
1849 {
1850  if (m_hide) return;
1851  m_t << "</blockquote>" << endl;
1853 }
1854 
1856 {
1857  if (m_hide) return;
1858  if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
1859  {
1860  forceEndParagraph(vf);
1861  QCString fname=FlowChart::convertNameToFileName();
1862  m_t << "<p>";
1863  m_t << "flowchart: " ; // TODO: translate me
1864  m_t << "<a href=\"";
1865  m_t << fname.data();
1866  m_t << ".svg\">";
1867  m_t << VhdlDocGen::getFlowMember()->name().data();
1868  m_t << "</a>";
1869  if (vf->hasCaption())
1870  {
1871  m_t << "<br />";
1872  }
1873  }
1874 }
1875 
1877 {
1878  if (m_hide) return;
1879  if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
1880  {
1881  m_t << "</p>";
1882  forceStartParagraph(vf);
1883  }
1884 }
1885 
1887 {
1888  if (m_hide) return;
1889 }
1890 
1892 {
1893  if (m_hide) return;
1894 }
1895 
1896 
1897 
1898 void HtmlDocVisitor::filter(const char *str)
1899 {
1900  if (str==0) return;
1901  const char *p=str;
1902  char c;
1903  while (*p)
1904  {
1905  c=*p++;
1906  switch(c)
1907  {
1908  case '<': m_t << "&lt;"; break;
1909  case '>': m_t << "&gt;"; break;
1910  case '&': m_t << "&amp;"; break;
1911  default: m_t << c;
1912  }
1913  }
1914 }
1915 
1919 {
1920  if (str==0) return;
1921  const char *p=str;
1922  char c;
1923  while (*p)
1924  {
1925  c=*p++;
1926  switch(c)
1927  {
1928  case '&': m_t << "&amp;"; break;
1929  case '"': m_t << "&quot;"; break;
1930  case '<': m_t << "&lt;"; break;
1931  case '>': m_t << "&gt;"; break;
1932  default: m_t << c;
1933  }
1934  }
1935 }
1936 
1937 void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file,
1938  const QCString &relPath,const QCString &anchor,
1939  const QCString &tooltip)
1940 {
1941  //printf("HtmlDocVisitor: file=%s anchor=%s\n",file.data(),anchor.data());
1942  if (!ref.isEmpty()) // link to entity imported via tag file
1943  {
1944  m_t << "<a class=\"elRef\" ";
1945  m_t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
1946  }
1947  else // local link
1948  {
1949  m_t << "<a class=\"el\" ";
1950  }
1951  m_t << "href=\"";
1952  m_t << externalRef(relPath,ref,TRUE);
1953  if (!file.isEmpty()) m_t << file << Doxygen::htmlFileExtension;
1954  if (!anchor.isEmpty()) m_t << "#" << anchor;
1955  m_t << "\"";
1956  if (!tooltip.isEmpty()) m_t << " title=\"" << convertToHtml(tooltip) << "\"";
1957  m_t << ">";
1958 }
1959 
1961 {
1962  m_t << "</a>";
1963 }
1964 
1966 {
1967  m_enabled.push(new bool(m_hide));
1968 }
1969 
1971 {
1972  bool *v=m_enabled.pop();
1973  ASSERT(v!=0);
1974  m_hide = *v;
1975  delete v;
1976 }
1977 
1978 void HtmlDocVisitor::writeDotFile(const QCString &fn,const QCString &relPath,
1979  const QCString &context)
1980 {
1981  QCString baseName=fn;
1982  int i;
1983  if ((i=baseName.findRev('/'))!=-1)
1984  {
1985  baseName=baseName.right(baseName.length()-i-1);
1986  }
1987  if ((i=baseName.find('.'))!=-1) // strip extension
1988  {
1989  baseName=baseName.left(i);
1990  }
1991  baseName.prepend("dot_");
1992  QCString outDir = Config_getString(HTML_OUTPUT);
1993  writeDotGraphFromFile(fn,outDir,baseName,GOF_BITMAP);
1994  writeDotImageMapFromFile(m_t,fn,outDir,relPath,baseName,context);
1995 }
1996 
1997 void HtmlDocVisitor::writeMscFile(const QCString &fileName,
1998  const QCString &relPath,
1999  const QCString &context)
2000 {
2001  QCString baseName=fileName;
2002  int i;
2003  if ((i=baseName.findRev('/'))!=-1) // strip path
2004  {
2005  baseName=baseName.right(baseName.length()-i-1);
2006  }
2007  if ((i=baseName.find('.'))!=-1) // strip extension
2008  {
2009  baseName=baseName.left(i);
2010  }
2011  baseName.prepend("msc_");
2012  QCString outDir = Config_getString(HTML_OUTPUT);
2013  QCString imgExt = getDotImageExtension();
2014  MscOutputFormat mscFormat = MSC_BITMAP;
2015  if ("svg" == imgExt)
2016  mscFormat = MSC_SVG;
2017  writeMscGraphFromFile(fileName,outDir,baseName,mscFormat);
2018  writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context,mscFormat);
2019 }
2020 
2021 void HtmlDocVisitor::writeDiaFile(const QCString &fileName,
2022  const QCString &relPath,
2023  const QCString &)
2024 {
2025  QCString baseName=fileName;
2026  int i;
2027  if ((i=baseName.findRev('/'))!=-1) // strip path
2028  {
2029  baseName=baseName.right(baseName.length()-i-1);
2030  }
2031  if ((i=baseName.find('.'))!=-1) // strip extension
2032  {
2033  baseName=baseName.left(i);
2034  }
2035  baseName.prepend("dia_");
2036  QCString outDir = Config_getString(HTML_OUTPUT);
2037  writeDiaGraphFromFile(fileName,outDir,baseName,DIA_BITMAP);
2038 
2039  m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />" << endl;
2040 }
2041 
2042 void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName,
2043  const QCString &relPath,
2044  const QCString &)
2045 {
2046  QCString baseName=fileName;
2047  int i;
2048  if ((i=baseName.findRev('/'))!=-1) // strip path
2049  {
2050  baseName=baseName.right(baseName.length()-i-1);
2051  }
2052  if ((i=baseName.findRev('.'))!=-1) // strip extension
2053  {
2054  baseName=baseName.left(i);
2055  }
2056  static QCString outDir = Config_getString(HTML_OUTPUT);
2057  QCString imgExt = getDotImageExtension();
2058  if (imgExt=="svg")
2059  {
2060  generatePlantUMLOutput(fileName,outDir,PUML_SVG);
2061  //m_t << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" << relPath << baseName << ".svg" << "\" />" << endl;
2062  //m_t << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
2063  //m_t << "</iframe>" << endl;
2064  m_t << "<object type=\"image/svg+xml\" data=\"" << relPath << baseName << ".svg\"></object>" << endl;
2065  }
2066  else
2067  {
2068  generatePlantUMLOutput(fileName,outDir,PUML_BITMAP);
2069  m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />" << endl;
2070  }
2071 }
2072 
2078 static bool insideStyleChangeThatIsOutsideParagraph(DocPara *para,int nodeIndex)
2079 {
2080  //printf("insideStyleChangeThatIsOutputParagraph(index=%d)\n",nodeIndex);
2081  int styleMask=0;
2082  bool styleOutsideParagraph=FALSE;
2083  while (nodeIndex>=0 && !styleOutsideParagraph)
2084  {
2085  DocNode *n = para->children().at(nodeIndex);
2086  if (n->kind()==DocNode::Kind_StyleChange)
2087  {
2088  DocStyleChange *sc = (DocStyleChange*)n;
2089  if (!sc->enable()) // remember styles that has been closed already
2090  {
2091  styleMask|=(int)sc->style();
2092  }
2093  bool paraStyle = sc->style()==DocStyleChange::Center ||
2094  sc->style()==DocStyleChange::Div ||
2096  //printf("Found style change %s enabled=%d\n",sc->styleString(),sc->enable());
2097  if (sc->enable() && (styleMask&(int)sc->style())==0 && // style change that is still active
2098  paraStyle
2099  )
2100  {
2101  styleOutsideParagraph=TRUE;
2102  }
2103  }
2104  nodeIndex--;
2105  }
2106  return styleOutsideParagraph;
2107 }
2108 
2114 {
2115  //printf("forceEndParagraph(%p) %d\n",n,n->kind());
2116  if (n->parent() && n->parent()->kind()==DocNode::Kind_Para)
2117  {
2118  DocPara *para = (DocPara*)n->parent();
2119  int nodeIndex = para->children().findRef(n);
2120  nodeIndex--;
2121  if (nodeIndex<0) return; // first node
2122  while (nodeIndex>=0 &&
2123  para->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace
2124  )
2125  {
2126  nodeIndex--;
2127  }
2128  if (nodeIndex>=0)
2129  {
2130  DocNode *n = para->children().at(nodeIndex);
2131  //printf("n=%p kind=%d outside=%d\n",n,n->kind(),mustBeOutsideParagraph(n));
2132  if (mustBeOutsideParagraph(n)) return;
2133  }
2134  nodeIndex--;
2135  bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,nodeIndex);
2136  bool isFirst;
2137  bool isLast;
2138  getParagraphContext(para,isFirst,isLast);
2139  //printf("forceEnd first=%d last=%d styleOutsideParagraph=%d\n",isFirst,isLast,styleOutsideParagraph);
2140  if (isFirst && isLast) return;
2141  if (styleOutsideParagraph) return;
2142 
2143  m_t << "</p>";
2144  }
2145 }
2146 
2152 {
2153  //printf("forceStartParagraph(%p) %d\n",n,n->kind());
2154  if (n->parent() && n->parent()->kind()==DocNode::Kind_Para) // if we are inside a paragraph
2155  {
2156  DocPara *para = (DocPara*)n->parent();
2157  int nodeIndex = para->children().findRef(n);
2158  int numNodes = para->children().count();
2159  bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,nodeIndex);
2160  if (styleOutsideParagraph) return;
2161  nodeIndex++;
2162  if (nodeIndex==numNodes) return; // last node
2163  while (nodeIndex<numNodes &&
2164  para->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace
2165  )
2166  {
2167  nodeIndex++;
2168  }
2169  if (nodeIndex<numNodes)
2170  {
2171  DocNode *n = para->children().at(nodeIndex);
2172  if (mustBeOutsideParagraph(n)) return;
2173  }
2174  else
2175  {
2176  return; // only whitespace at the end!
2177  }
2178 
2179  bool isFirst;
2180  bool isLast;
2181  getParagraphContext(para,isFirst,isLast);
2182  //printf("forceStart first=%d last=%d\n",isFirst,isLast);
2183  if (isFirst && isLast) return;
2184 
2185  m_t << "<p>";
2186  }
2187 }
2188