1 /******************************************************************************
6 * Copyright (C) 1997-2015 by Dimitri van Heesch.
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.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
20 #include "htmldocvisitor.h"
21 #include "docparser.h"
24 #include "outputgen.h"
29 #include "parserintf.h"
33 #include "vhdldocgen.h"
35 #include "memberdef.h"
36 #include "htmlentity.h"
40 static const int NUM_HTML_LIST_TYPES = 4;
41 static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
55 static const char *contexts[10] =
68 static QCString convertIndexWordToAnchor(const QString &word)
70 static char hex[] = "0123456789abcdef";
74 result += cntStr.setNum(cnt);
77 const char *str = word.data();
83 if ((c >= 'a' && c <= 'z') || // ALPHA
84 (c >= 'A' && c <= 'Z') || // ALPHA
85 (c >= '0' && c <= '9') || // DIGIT
97 enc[1] = hex[(c & 0xf0) >> 4];
98 enc[2] = hex[c & 0xf];
107 static bool mustBeOutsideParagraph(DocNode *n)
112 case DocNode::Kind_HtmlList:
113 case DocNode::Kind_SimpleList:
114 case DocNode::Kind_AutoList:
116 case DocNode::Kind_SimpleSect:
117 case DocNode::Kind_ParamSect:
118 case DocNode::Kind_HtmlDescList:
119 case DocNode::Kind_XRefItem:
121 case DocNode::Kind_HtmlTable:
123 case DocNode::Kind_Section:
124 case DocNode::Kind_HtmlHeader:
126 case DocNode::Kind_Internal:
128 case DocNode::Kind_Include:
129 case DocNode::Kind_Image:
130 case DocNode::Kind_SecRefList:
132 case DocNode::Kind_HorRuler:
133 /* CopyDoc gets paragraph markers from the wrapping DocPara node,
134 * but needs to insert them for all documentation being copied to
135 * preserve formatting.
137 case DocNode::Kind_Copy:
139 case DocNode::Kind_HtmlBlockQuote:
141 case DocNode::Kind_ParBlock:
142 case DocNode::Kind_IncOperator:
144 case DocNode::Kind_Verbatim:
146 DocVerbatim *dv = (DocVerbatim*)n;
147 return dv->type()!=DocVerbatim::HtmlOnly || dv->isBlock();
149 case DocNode::Kind_StyleChange:
150 return ((DocStyleChange*)n)->style()==DocStyleChange::Preformatted ||
151 ((DocStyleChange*)n)->style()==DocStyleChange::Div ||
152 ((DocStyleChange*)n)->style()==DocStyleChange::Center;
153 case DocNode::Kind_Formula:
154 return !((DocFormula*)n)->isInline();
161 static bool isDocVerbatimVisible(DocVerbatim *s)
165 case DocVerbatim::ManOnly:
166 case DocVerbatim::LatexOnly:
167 case DocVerbatim::XmlOnly:
168 case DocVerbatim::RtfOnly:
169 case DocVerbatim::DocbookOnly:
176 static bool isDocIncludeVisible(DocInclude *s)
180 case DocInclude::DontInclude:
181 case DocInclude::LatexInclude:
188 static bool isDocIncOperatorVisible(DocIncOperator *s)
192 case DocIncOperator::Skip:
199 static bool isInvisibleNode(DocNode *node)
201 return (node->kind()==DocNode::Kind_WhiteSpace)
202 || // skip over image nodes that are not for HTML output
203 (node->kind()==DocNode::Kind_Image && ((DocImage*)node)->type()!=DocImage::Html)
204 || // skip over verbatim nodes that are not visible in the HTML output
205 (node->kind()==DocNode::Kind_Verbatim && !isDocVerbatimVisible((DocVerbatim*)node))
206 || // skip over include nodes that are not visible in the HTML output
207 (node->kind()==DocNode::Kind_Include && !isDocIncludeVisible((DocInclude*)node))
208 || // skip over include operator nodes that are not visible in the HTML output
209 (node->kind()==DocNode::Kind_IncOperator && !isDocIncOperatorVisible((DocIncOperator*)node))
213 static QString htmlAttribsToString(const HtmlAttribList &attribs, bool img_tag = FALSE)
216 HtmlAttribListIterator li(attribs);
218 bool alt_set = FALSE;
220 for (li.toFirst();(att=li.current());++li)
222 if (!att->value.isEmpty()) // ignore attribute without values as they
223 // are not XHTML compliant, with the exception
224 // of the alt attribute with the img tag
228 result+="=\""+convertToXML(att->value)+"\"";
229 if (att->name == "alt") alt_set = TRUE;
232 if (!alt_set && img_tag)
239 //-------------------------------------------------------------------------
241 HtmlDocVisitor::HtmlDocVisitor(FTextStream &t,CodeOutputInterface &ci,
243 : DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE),
244 m_hide(FALSE), m_ctx(ctx)
246 if (ctx) m_langExt=ctx->getDefFileExtension();
249 //--------------------------------------
250 // visitor functions for leaf nodes
251 //--------------------------------------
253 void HtmlDocVisitor::visit(DocWord *w)
255 //printf("word: %s\n",w->word().data());
260 void HtmlDocVisitor::visit(DocLinkedWord *w)
263 //printf("linked word: %s\n",w->word().data());
264 startLink(w->ref(),w->file(),w->relPath(),w->anchor(),w->tooltip());
269 void HtmlDocVisitor::visit(DocWhiteSpace *w)
282 void HtmlDocVisitor::visit(DocSymbol *s)
285 const char *res = HtmlEntityMapper::instance()->html(s->symbol());
292 err("HTML: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
296 void HtmlDocVisitor::visit(DocEmoji *s)
299 const char *res = EmojiEntityMapper::instance()->unicode(s->index());
310 void HtmlDocVisitor::writeObfuscatedMailAddress(const QCString &url)
312 m_t << "<a href=\"#\" onclick=\"location.href='mai'+'lto:'";
315 for (i=0;i<url.length();)
317 m_t << "+'" << url.mid(i,size) << "'";
319 if (size==3) size=2; else size=3;
321 m_t << "; return false;\">";
324 void HtmlDocVisitor::visit(DocURL *u)
327 if (u->isEmail()) // mail address
329 QCString url = u->url();
330 writeObfuscatedMailAddress(url);
332 for (i=0;i<url.length();)
334 filter(url.mid(i,size));
335 if (i<url.length()-size) m_t << "<span style=\"display: none;\">.nosp@m.</span>";
337 if (size==5) size=4; else size=5;
344 m_t << u->url() << "\">";
350 void HtmlDocVisitor::visit(DocLineBreak *)
356 void HtmlDocVisitor::visit(DocHorRuler *hr)
359 forceEndParagraph(hr);
361 forceStartParagraph(hr);
364 void HtmlDocVisitor::visit(DocStyleChange *s)
369 case DocStyleChange::Bold:
370 if (s->enable()) m_t << "<b" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</b>";
372 case DocStyleChange::Strike:
373 if (s->enable()) m_t << "<strike" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</strike>";
375 case DocStyleChange::Underline:
376 if (s->enable()) m_t << "<u" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</u>";
378 case DocStyleChange::Italic:
379 if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>";
381 case DocStyleChange::Code:
382 if (s->enable()) m_t << "<code" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</code>";
384 case DocStyleChange::Subscript:
385 if (s->enable()) m_t << "<sub" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sub>";
387 case DocStyleChange::Superscript:
388 if (s->enable()) m_t << "<sup" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sup>";
390 case DocStyleChange::Center:
393 forceEndParagraph(s);
394 m_t << "<center" << htmlAttribsToString(s->attribs()) << ">";
399 forceStartParagraph(s);
402 case DocStyleChange::Small:
403 if (s->enable()) m_t << "<small" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</small>";
405 case DocStyleChange::Preformatted:
408 forceEndParagraph(s);
409 m_t << "<pre" << htmlAttribsToString(s->attribs()) << ">";
416 forceStartParagraph(s);
419 case DocStyleChange::Div:
422 forceEndParagraph(s);
423 m_t << "<div" << htmlAttribsToString(s->attribs()) << ">";
428 forceStartParagraph(s);
431 case DocStyleChange::Span:
432 if (s->enable()) m_t << "<span" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</span>";
439 static void visitPreCaption(FTextStream &t, DocVerbatim *s)
443 t << "<div class=\"caption\">" << endl;
448 static void visitPostCaption(FTextStream &t, DocVerbatim *s)
452 t << "</div>" << endl;
457 static void visitCaption(HtmlDocVisitor *parent, QList<DocNode> children)
459 QListIterator<DocNode> cli(children);
461 for (cli.toFirst();(n=cli.current());++cli) n->accept(parent);
464 void HtmlDocVisitor::visit(DocVerbatim *s)
467 QCString lang = m_langExt;
468 if (!s->language().isEmpty()) // explicit language setting
470 lang = s->language();
472 SrcLangExt langExt = getLanguageFromFileName(lang);
475 case DocVerbatim::Code:
476 forceEndParagraph(s);
477 m_t << PREFRAG_START;
478 Doxygen::parserManager->getParser(lang)
488 FALSE, // inlineFragment
490 TRUE, // show line numbers
491 m_ctx // search context
494 forceStartParagraph(s);
496 case DocVerbatim::Verbatim:
497 forceEndParagraph(s);
498 m_t << /*PREFRAG_START <<*/ "<pre class=\"fragment\">";
500 m_t << "</pre>" /*<< PREFRAG_END*/;
501 forceStartParagraph(s);
503 case DocVerbatim::HtmlOnly:
505 if (s->isBlock()) forceEndParagraph(s);
507 if (s->isBlock()) forceStartParagraph(s);
510 case DocVerbatim::ManOnly:
511 case DocVerbatim::LatexOnly:
512 case DocVerbatim::XmlOnly:
513 case DocVerbatim::RtfOnly:
514 case DocVerbatim::DocbookOnly:
518 case DocVerbatim::Dot:
520 static int dotindex = 1;
521 QCString fileName(4096);
523 forceEndParagraph(s);
524 fileName.sprintf("%s%d%s",
525 (Config_getString(HTML_OUTPUT)+"/inline_dotgraph_").data(),
529 QFile file(fileName);
530 if (!file.open(IO_WriteOnly))
532 err("Could not open file %s for writing\n",fileName.data());
536 file.writeBlock( s->text(), s->text().length() );
539 m_t << "<div class=\"dotgraph\">" << endl;
540 writeDotFile(fileName,s->relPath(),s->context());
541 visitPreCaption(m_t, s);
542 visitCaption(this, s->children());
543 visitPostCaption(m_t, s);
544 m_t << "</div>" << endl;
546 if (Config_getBool(DOT_CLEANUP)) file.remove();
548 forceStartParagraph(s);
551 case DocVerbatim::Msc:
553 forceEndParagraph(s);
555 static int mscindex = 1;
556 QCString baseName(4096);
558 baseName.sprintf("%s%d",
559 (Config_getString(HTML_OUTPUT)+"/inline_mscgraph_").data(),
562 QFile file(baseName+".msc");
563 if (!file.open(IO_WriteOnly))
565 err("Could not open file %s.msc for writing\n",baseName.data());
569 QCString text = "msc {";
573 file.writeBlock( text, text.length() );
576 m_t << "<div class=\"mscgraph\">" << endl;
577 writeMscFile(baseName+".msc",s->relPath(),s->context());
578 visitPreCaption(m_t, s);
579 visitCaption(this, s->children());
580 visitPostCaption(m_t, s);
581 m_t << "</div>" << endl;
583 if (Config_getBool(DOT_CLEANUP)) file.remove();
585 forceStartParagraph(s);
588 case DocVerbatim::PlantUML:
590 forceEndParagraph(s);
592 static QCString htmlOutput = Config_getString(HTML_OUTPUT);
593 QCString baseName = writePlantUMLSource(htmlOutput,s->exampleFile(),s->text());
594 m_t << "<div class=\"plantumlgraph\">" << endl;
595 writePlantUMLFile(baseName,s->relPath(),s->context());
596 visitPreCaption(m_t, s);
597 visitCaption(this, s->children());
598 visitPostCaption(m_t, s);
599 m_t << "</div>" << endl;
600 forceStartParagraph(s);
606 void HtmlDocVisitor::visit(DocAnchor *anc)
609 m_t << "<a class=\"anchor\" id=\"" << anc->anchor() << "\"></a>";
612 void HtmlDocVisitor::visit(DocInclude *inc)
615 SrcLangExt langExt = getLanguageFromFileName(inc->extension());
618 case DocInclude::Include:
619 forceEndParagraph(inc);
620 m_t << PREFRAG_START;
621 Doxygen::parserManager->getParser(inc->extension())
631 TRUE, // inlineFragment
633 FALSE, // show line numbers
634 m_ctx // search context
637 forceStartParagraph(inc);
639 case DocInclude::IncWithLines:
641 forceEndParagraph(inc);
642 m_t << PREFRAG_START;
643 QFileInfo cfi( inc->file() );
644 FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
645 Doxygen::parserManager->getParser(inc->extension())
655 FALSE, // inline fragment
657 TRUE, // show line numbers
658 m_ctx // search context
661 forceStartParagraph(inc);
664 case DocInclude::DontInclude:
666 case DocInclude::HtmlInclude:
668 if (inc->isBlock()) forceEndParagraph(inc);
670 if (inc->isBlock()) forceStartParagraph(inc);
673 case DocInclude::LatexInclude:
675 case DocInclude::VerbInclude:
676 forceEndParagraph(inc);
677 m_t << /*PREFRAG_START <<*/ "<pre class=\"fragment\">";
679 m_t << "</pre>" /*<< PREFRAG_END*/;
680 forceStartParagraph(inc);
682 case DocInclude::Snippet:
684 forceEndParagraph(inc);
685 m_t << PREFRAG_START;
686 Doxygen::parserManager->getParser(inc->extension())
689 extractBlock(inc->text(),inc->blockId()),
696 TRUE, // inlineFragment
698 FALSE, // show line number
699 m_ctx // search context
702 forceStartParagraph(inc);
705 case DocInclude::SnipWithLines:
707 forceEndParagraph(inc);
708 m_t << PREFRAG_START;
709 QFileInfo cfi( inc->file() );
710 FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
711 Doxygen::parserManager->getParser(inc->extension())
714 extractBlock(inc->text(),inc->blockId()),
719 lineBlock(inc->text(),inc->blockId()),
721 FALSE, // inlineFragment
723 TRUE, // show line number
724 m_ctx // search context
727 forceStartParagraph(inc);
730 case DocInclude::SnippetDoc:
731 case DocInclude::IncludeDoc:
732 err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
733 "Please create a bug report\n",__FILE__);
738 void HtmlDocVisitor::visit(DocIncOperator *op)
740 //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
741 // op->type(),op->isFirst(),op->isLast(),op->text().data());
744 forceEndParagraph(op);
745 if (!m_hide) m_t << PREFRAG_START;
749 SrcLangExt langExt = getLanguageFromFileName(m_langExt);
750 if (op->type()!=DocIncOperator::Skip)
755 Doxygen::parserManager->getParser(m_langExt)
766 FALSE, // inline fragment
768 TRUE, // show line numbers
769 m_ctx // search context
778 if (!m_hide) m_t << PREFRAG_END;
779 forceStartParagraph(op);
783 if (!m_hide) m_t << endl;
787 void HtmlDocVisitor::visit(DocFormula *f)
790 bool bDisplay = !f->isInline();
793 forceEndParagraph(f);
794 m_t << "<p class=\"formulaDsp\">" << endl;
797 if (Config_getBool(USE_MATHJAX))
799 QCString text = f->text();
800 bool closeInline = FALSE;
801 if (!bDisplay && !text.isEmpty() && text.at(0)=='$' &&
802 text.at(text.length()-1)=='$')
805 text = text.mid(1,text.length()-2);
808 m_t << convertToHtml(text);
816 m_t << "<img class=\"formula"
817 << (bDisplay ? "Dsp" : "Inl");
819 filterQuotedCdataAttr(f->text());
821 // TODO: cache image dimensions on formula generation and give height/width
822 // for faster preloading and better rendering of the page
823 m_t << " src=\"" << f->relPath() << f->name() << ".png\"/>";
828 m_t << endl << "</p>" << endl;
829 forceStartParagraph(f);
833 void HtmlDocVisitor::visit(DocIndexEntry *e)
835 QCString anchor = convertIndexWordToAnchor(e->entry());
838 anchor.prepend(e->member()->anchor()+"_");
840 m_t << "<a name=\"" << anchor << "\"></a>";
841 //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n",
842 // e->entry().data(),
843 // e->scope() ? e->scope()->name().data() : "<null>",
844 // e->member() ? e->member()->name().data() : "<null>"
846 Doxygen::indexList->addIndexItem(e->scope(),e->member(),anchor,e->entry());
849 void HtmlDocVisitor::visit(DocSimpleSectSep *)
851 m_t << "</dd>" << endl;
852 m_t << "<dd>" << endl;
855 void HtmlDocVisitor::visit(DocCite *cite)
858 if (!cite->file().isEmpty())
860 startLink(cite->ref(),cite->file(),cite->relPath(),cite->anchor());
866 filter(cite->text());
867 if (!cite->file().isEmpty())
878 //--------------------------------------
879 // visitor functions for compound nodes
880 //--------------------------------------
883 void HtmlDocVisitor::visitPre(DocAutoList *l)
885 //printf("DocAutoList::visitPre\n");
887 forceEndParagraph(l);
891 // Do list type based on depth:
898 m_t << "<ol type=\"" << types[l->depth() % NUM_HTML_LIST_TYPES] << "\"";
904 m_t << getDirHtmlClassOfNode(getTextDirByConfig(l)) << ">";
905 if (!l->isPreformatted()) m_t << "\n";
908 void HtmlDocVisitor::visitPost(DocAutoList *l)
910 //printf("DocAutoList::visitPost\n");
920 if (!l->isPreformatted()) m_t << "\n";
921 forceStartParagraph(l);
924 void HtmlDocVisitor::visitPre(DocAutoListItem *)
930 void HtmlDocVisitor::visitPost(DocAutoListItem *li)
934 if (!li->isPreformatted()) m_t << "\n";
938 bool isFirstChildNode(T *parent, DocNode *node)
940 return parent->children().getFirst()==node;
944 bool isLastChildNode(T *parent, DocNode *node)
946 return parent->children().getLast()==node;
949 bool isSeparatedParagraph(DocSimpleSect *parent,DocPara *par)
951 QList<DocNode> nodes = parent->children();
952 int i = nodes.findRef(par);
953 if (i==-1) return FALSE;
954 int count = parent->children().count();
955 if (count>1 && i==0) // first node
957 if (nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
962 else if (count>1 && i==count-1) // last node
964 if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep)
969 else if (count>2 && i>0 && i<count-1) // intermediate node
971 if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep &&
972 nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
980 static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
985 if (p && p->parent())
987 switch (p->parent()->kind())
989 case DocNode::Kind_ParBlock:
990 { // hierarchy: node N -> para -> parblock -> para
991 // adapt return value to kind of N
992 DocNode::Kind kind = DocNode::Kind_Para;
993 if ( p->parent()->parent() && p->parent()->parent()->parent() )
995 kind = p->parent()->parent()->parent()->kind();
997 isFirst=isFirstChildNode((DocParBlock*)p->parent(),p);
998 isLast =isLastChildNode ((DocParBlock*)p->parent(),p);
1002 if (kind==DocNode::Kind_HtmlListItem ||
1003 kind==DocNode::Kind_SecRefItem)
1007 else if (kind==DocNode::Kind_HtmlDescData ||
1008 kind==DocNode::Kind_XRefItem ||
1009 kind==DocNode::Kind_SimpleSect)
1013 else if (kind==DocNode::Kind_HtmlCell ||
1014 kind==DocNode::Kind_ParamList)
1021 if (kind==DocNode::Kind_HtmlListItem ||
1022 kind==DocNode::Kind_SecRefItem)
1026 else if (kind==DocNode::Kind_HtmlDescData ||
1027 kind==DocNode::Kind_XRefItem ||
1028 kind==DocNode::Kind_SimpleSect)
1032 else if (kind==DocNode::Kind_HtmlCell ||
1033 kind==DocNode::Kind_ParamList)
1038 if (!isFirst && !isLast)
1040 if (kind==DocNode::Kind_HtmlListItem ||
1041 kind==DocNode::Kind_SecRefItem)
1045 else if (kind==DocNode::Kind_HtmlDescData ||
1046 kind==DocNode::Kind_XRefItem ||
1047 kind==DocNode::Kind_SimpleSect)
1051 else if (kind==DocNode::Kind_HtmlCell ||
1052 kind==DocNode::Kind_ParamList)
1059 case DocNode::Kind_AutoListItem:
1060 isFirst=isFirstChildNode((DocAutoListItem*)p->parent(),p);
1061 isLast =isLastChildNode ((DocAutoListItem*)p->parent(),p);
1062 t=STARTLI; // not used
1064 case DocNode::Kind_SimpleListItem:
1067 t=STARTLI; // not used
1069 case DocNode::Kind_ParamList:
1072 t=STARTLI; // not used
1074 case DocNode::Kind_HtmlListItem:
1075 isFirst=isFirstChildNode((DocHtmlListItem*)p->parent(),p);
1076 isLast =isLastChildNode ((DocHtmlListItem*)p->parent(),p);
1077 if (isFirst) t=STARTLI;
1078 if (isLast) t=ENDLI;
1079 if (!isFirst && !isLast) t = INTERLI;
1081 case DocNode::Kind_SecRefItem:
1082 isFirst=isFirstChildNode((DocSecRefItem*)p->parent(),p);
1083 isLast =isLastChildNode ((DocSecRefItem*)p->parent(),p);
1084 if (isFirst) t=STARTLI;
1085 if (isLast) t=ENDLI;
1086 if (!isFirst && !isLast) t = INTERLI;
1088 case DocNode::Kind_HtmlDescData:
1089 isFirst=isFirstChildNode((DocHtmlDescData*)p->parent(),p);
1090 isLast =isLastChildNode ((DocHtmlDescData*)p->parent(),p);
1091 if (isFirst) t=STARTDD;
1092 if (isLast) t=ENDDD;
1093 if (!isFirst && !isLast) t = INTERDD;
1095 case DocNode::Kind_XRefItem:
1096 isFirst=isFirstChildNode((DocXRefItem*)p->parent(),p);
1097 isLast =isLastChildNode ((DocXRefItem*)p->parent(),p);
1098 if (isFirst) t=STARTDD;
1099 if (isLast) t=ENDDD;
1100 if (!isFirst && !isLast) t = INTERDD;
1102 case DocNode::Kind_SimpleSect:
1103 isFirst=isFirstChildNode((DocSimpleSect*)p->parent(),p);
1104 isLast =isLastChildNode ((DocSimpleSect*)p->parent(),p);
1105 if (isFirst) t=STARTDD;
1106 if (isLast) t=ENDDD;
1107 if (isSeparatedParagraph((DocSimpleSect*)p->parent(),p))
1108 // if the paragraph is enclosed with separators it will
1109 // be included in <dd>..</dd> so avoid addition paragraph
1112 isFirst=isLast=TRUE;
1114 if (!isFirst && !isLast) t = INTERDD;
1116 case DocNode::Kind_HtmlCell:
1117 isFirst=isFirstChildNode((DocHtmlCell*)p->parent(),p);
1118 isLast =isLastChildNode ((DocHtmlCell*)p->parent(),p);
1119 if (isFirst) t=STARTTD;
1120 if (isLast) t=ENDTD;
1121 if (!isFirst && !isLast) t = INTERTD;
1126 //printf("para=%p parent()->kind=%d isFirst=%d isLast=%d t=%d\n",
1127 // p,p->parent()->kind(),isFirst,isLast,t);
1132 void HtmlDocVisitor::visitPre(DocPara *p)
1136 //printf("DocPara::visitPre: parent of kind %d ",
1137 // p->parent() ? p->parent()->kind() : -1);
1139 bool needsTag = FALSE;
1140 if (p && p->parent())
1142 switch (p->parent()->kind())
1144 case DocNode::Kind_Section:
1145 case DocNode::Kind_Internal:
1146 case DocNode::Kind_HtmlListItem:
1147 case DocNode::Kind_HtmlDescData:
1148 case DocNode::Kind_HtmlCell:
1149 case DocNode::Kind_SimpleListItem:
1150 case DocNode::Kind_AutoListItem:
1151 case DocNode::Kind_SimpleSect:
1152 case DocNode::Kind_XRefItem:
1153 case DocNode::Kind_Copy:
1154 case DocNode::Kind_HtmlBlockQuote:
1155 case DocNode::Kind_ParBlock:
1158 case DocNode::Kind_Root:
1159 needsTag = !((DocRoot*)p->parent())->singleLine();
1166 // if the first element of a paragraph is something that should be outside of
1167 // the paragraph (<ul>,<dl>,<table>,..) then that will already started the
1168 // paragraph and we don't need to do it here
1169 bool paragraphAlreadyStarted = false;
1171 if (p && nodeIndex<p->children().count())
1173 while (nodeIndex<p->children().count() && isInvisibleNode(p->children().at(nodeIndex)))
1177 if (nodeIndex<p->children().count())
1179 DocNode *n = p->children().at(nodeIndex);
1180 if (mustBeOutsideParagraph(n))
1182 paragraphAlreadyStarted = true;
1188 // check if this paragraph is the first or last or intermediate child of a <li> or <dd>.
1189 // this allows us to mark the tag with a special class so we can
1190 // fix the otherwise ugly spacing.
1194 t = getParagraphContext(p,isFirst,isLast);
1195 //printf("startPara first=%d last=%d\n",isFirst,isLast);
1196 if (isFirst && isLast) needsTag=FALSE;
1198 //printf(" needsTag=%d\n",needsTag);
1199 // write the paragraph tag (if needed)
1201 m_t << "<p" << getDirHtmlClassOfNode(getTextDirByConfig(p), contexts[t]) << ">";
1202 else if(!paragraphAlreadyStarted)
1203 m_t << getHtmlDirEmbedingChar(getTextDirByConfig(p));
1206 void HtmlDocVisitor::visitPost(DocPara *p)
1208 bool needsTag = FALSE;
1211 switch (p->parent()->kind())
1213 case DocNode::Kind_Section:
1214 case DocNode::Kind_Internal:
1215 case DocNode::Kind_HtmlListItem:
1216 case DocNode::Kind_HtmlDescData:
1217 case DocNode::Kind_HtmlCell:
1218 case DocNode::Kind_SimpleListItem:
1219 case DocNode::Kind_AutoListItem:
1220 case DocNode::Kind_SimpleSect:
1221 case DocNode::Kind_XRefItem:
1222 case DocNode::Kind_Copy:
1223 case DocNode::Kind_HtmlBlockQuote:
1224 case DocNode::Kind_ParBlock:
1227 case DocNode::Kind_Root:
1228 needsTag = !((DocRoot*)p->parent())->singleLine();
1235 // if the last element of a paragraph is something that should be outside of
1236 // the paragraph (<ul>,<dl>,<table>) then that will already have ended the
1237 // paragraph and we don't need to do it here
1238 int nodeIndex = p->children().count()-1;
1241 while (nodeIndex>=0 && isInvisibleNode(p->children().at(nodeIndex)))
1247 DocNode *n = p->children().at(nodeIndex);
1248 if (mustBeOutsideParagraph(n))
1257 getParagraphContext(p,isFirst,isLast);
1258 //printf("endPara first=%d last=%d\n",isFirst,isLast);
1259 if (isFirst && isLast) needsTag=FALSE;
1261 //printf("DocPara::visitPost needsTag=%d\n",needsTag);
1263 if (needsTag) m_t << "</p>\n";
1267 void HtmlDocVisitor::visitPre(DocRoot *)
1271 void HtmlDocVisitor::visitPost(DocRoot *)
1275 void HtmlDocVisitor::visitPre(DocSimpleSect *s)
1278 forceEndParagraph(s);
1279 if (s->type() != DocSimpleSect::Return)
1280 m_t << "<dl" << getDirHtmlClassOfNode(getTextDirByConfig(s), "section " + s->typeString()) << "><dt>";
1282 m_t << "<dl class=\"section " << s->typeString() << "\"><dt>";
1285 case DocSimpleSect::See:
1286 m_t << theTranslator->trSeeAlso(); break;
1287 case DocSimpleSect::Return:
1288 m_t << theTranslator->trReturns(); break;
1289 case DocSimpleSect::Author:
1290 m_t << theTranslator->trAuthor(TRUE,TRUE); break;
1291 case DocSimpleSect::Authors:
1292 m_t << theTranslator->trAuthor(TRUE,FALSE); break;
1293 case DocSimpleSect::Version:
1294 m_t << theTranslator->trVersion(); break;
1295 case DocSimpleSect::Since:
1296 m_t << theTranslator->trSince(); break;
1297 case DocSimpleSect::Date:
1298 m_t << theTranslator->trDate(); break;
1299 case DocSimpleSect::Note:
1300 m_t << theTranslator->trNote(); break;
1301 case DocSimpleSect::Warning:
1302 m_t << theTranslator->trWarning(); break;
1303 case DocSimpleSect::Pre:
1304 m_t << theTranslator->trPrecondition(); break;
1305 case DocSimpleSect::Post:
1306 m_t << theTranslator->trPostcondition(); break;
1307 case DocSimpleSect::Copyright:
1308 m_t << theTranslator->trCopyright(); break;
1309 case DocSimpleSect::Invar:
1310 m_t << theTranslator->trInvariant(); break;
1311 case DocSimpleSect::Remark:
1312 m_t << theTranslator->trRemarks(); break;
1313 case DocSimpleSect::Attention:
1314 m_t << theTranslator->trAttention(); break;
1315 case DocSimpleSect::User: break;
1316 case DocSimpleSect::Rcs: break;
1317 case DocSimpleSect::Unknown: break;
1320 // special case 1: user defined title
1321 if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
1327 void HtmlDocVisitor::visitPost(DocSimpleSect *s)
1330 m_t << "</dd></dl>\n";
1331 forceStartParagraph(s);
1334 void HtmlDocVisitor::visitPre(DocTitle *)
1338 void HtmlDocVisitor::visitPost(DocTitle *)
1344 void HtmlDocVisitor::visitPre(DocSimpleList *sl)
1347 forceEndParagraph(sl);
1349 if (!sl->isPreformatted()) m_t << "\n";
1353 void HtmlDocVisitor::visitPost(DocSimpleList *sl)
1357 if (!sl->isPreformatted()) m_t << "\n";
1358 forceStartParagraph(sl);
1361 void HtmlDocVisitor::visitPre(DocSimpleListItem *)
1367 void HtmlDocVisitor::visitPost(DocSimpleListItem *li)
1371 if (!li->isPreformatted()) m_t << "\n";
1374 void HtmlDocVisitor::visitPre(DocSection *s)
1377 forceEndParagraph(s);
1378 m_t << "<h" << s->level() << getDirHtmlClassOfNode(getTextDirByConfig(s->title())) << ">";
1379 m_t << "<a class=\"anchor\" id=\"" << s->anchor();
1380 m_t << "\"></a>" << endl;
1381 filter(convertCharEntitiesToUTF8(s->title().data()));
1382 m_t << "</h" << s->level() << ">\n";
1385 void HtmlDocVisitor::visitPost(DocSection *s)
1387 forceStartParagraph(s);
1390 void HtmlDocVisitor::visitPre(DocHtmlList *s)
1393 forceEndParagraph(s);
1394 if (s->type()==DocHtmlList::Ordered)
1396 m_t << "<ol" << htmlAttribsToString(s->attribs());
1400 m_t << "<ul" << htmlAttribsToString(s->attribs());
1402 m_t << getDirHtmlClassOfNode(getTextDirByConfig(s)) << ">\n";
1405 void HtmlDocVisitor::visitPost(DocHtmlList *s)
1408 if (s->type()==DocHtmlList::Ordered)
1416 if (!s->isPreformatted()) m_t << "\n";
1417 forceStartParagraph(s);
1420 void HtmlDocVisitor::visitPre(DocHtmlListItem *i)
1423 m_t << "<li" << htmlAttribsToString(i->attribs()) << ">";
1424 if (!i->isPreformatted()) m_t << "\n";
1427 void HtmlDocVisitor::visitPost(DocHtmlListItem *)
1433 void HtmlDocVisitor::visitPre(DocHtmlDescList *dl)
1436 forceEndParagraph(dl);
1437 m_t << "<dl" << htmlAttribsToString(dl->attribs()) << ">\n";
1440 void HtmlDocVisitor::visitPost(DocHtmlDescList *dl)
1444 forceStartParagraph(dl);
1447 void HtmlDocVisitor::visitPre(DocHtmlDescTitle *dt)
1450 m_t << "<dt" << htmlAttribsToString(dt->attribs())
1451 << getDirHtmlClassOfNode(getTextDirByConfig(dt))
1455 void HtmlDocVisitor::visitPost(DocHtmlDescTitle *)
1461 void HtmlDocVisitor::visitPre(DocHtmlDescData *dd)
1464 m_t << "<dd" << htmlAttribsToString(dd->attribs())
1465 << getDirHtmlClassOfNode(getTextDirByConfig(dd))
1469 void HtmlDocVisitor::visitPost(DocHtmlDescData *)
1475 void HtmlDocVisitor::visitPre(DocHtmlTable *t)
1479 forceEndParagraph(t);
1481 if (t->hasCaption())
1483 m_t << "<a class=\"anchor\" id=\"" << t->caption()->anchor() << "\"></a>\n";
1486 QString attrs = htmlAttribsToString(t->attribs());
1487 if (attrs.isEmpty())
1491 m_t << getDirHtmlClassOfNode(getTextDirByConfig(t->caption()), "doxtable");
1493 m_t << getDirHtmlClassOfNode(getTextDirByConfig(t), "doxtable");
1499 if (t->hasCaption())
1500 m_t << getDirHtmlClassOfNode(getTextDirByConfig(t->caption()));
1502 m_t << getDirHtmlClassOfNode(getTextDirByConfig(t));
1503 m_t << htmlAttribsToString(t->attribs()) << ">\n";
1507 void HtmlDocVisitor::visitPost(DocHtmlTable *t)
1510 m_t << "</table>\n";
1511 forceStartParagraph(t);
1514 void HtmlDocVisitor::visitPre(DocHtmlRow *tr)
1517 m_t << "<tr" << htmlAttribsToString(tr->attribs()) << ">\n";
1520 void HtmlDocVisitor::visitPost(DocHtmlRow *)
1526 void HtmlDocVisitor::visitPre(DocHtmlCell *c)
1531 m_t << "<th" << htmlAttribsToString(c->attribs()) << ">";
1535 m_t << "<td" << htmlAttribsToString(c->attribs()) << ">";
1539 void HtmlDocVisitor::visitPost(DocHtmlCell *c)
1542 if (c->isHeading()) m_t << "</th>"; else m_t << "</td>";
1545 void HtmlDocVisitor::visitPre(DocHtmlCaption *c)
1548 m_t << "<caption" << htmlAttribsToString(c->attribs()) << ">";
1551 void HtmlDocVisitor::visitPost(DocHtmlCaption *)
1554 m_t << "</caption>\n";
1557 void HtmlDocVisitor::visitPre(DocInternal *)
1560 //forceEndParagraph(i);
1561 //m_t << "<p><b>" << theTranslator->trForInternalUseOnly() << "</b></p>" << endl;
1564 void HtmlDocVisitor::visitPost(DocInternal *)
1567 //forceStartParagraph(i);
1570 void HtmlDocVisitor::visitPre(DocHRef *href)
1573 if (href->url().left(7)=="mailto:")
1575 writeObfuscatedMailAddress(href->url().mid(7));
1579 QCString url = correctURL(href->url(),href->relPath());
1580 m_t << "<a href=\"" << convertToXML(url) << "\""
1581 << htmlAttribsToString(href->attribs()) << ">";
1585 void HtmlDocVisitor::visitPost(DocHRef *)
1591 void HtmlDocVisitor::visitPre(DocHtmlHeader *header)
1594 forceEndParagraph(header);
1595 m_t << "<h" << header->level()
1596 << htmlAttribsToString(header->attribs())
1597 << getDirHtmlClassOfNode(getTextDirByConfig(header))
1601 void HtmlDocVisitor::visitPost(DocHtmlHeader *header)
1604 m_t << "</h" << header->level() << ">\n";
1605 forceStartParagraph(header);
1608 void HtmlDocVisitor::visitPre(DocImage *img)
1610 if (img->type()==DocImage::Html)
1612 bool inlineImage = img->isInlineImage();
1613 bool typeSVG = FALSE;
1615 QCString url = img->url();
1618 typeSVG = (img->name().right(4)==".svg");
1622 typeSVG = (url.right(4)==".svg");
1626 forceEndParagraph(img);
1629 QString baseName=img->name();
1631 if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1)
1633 baseName=baseName.right(baseName.length()-i-1);
1635 if (!inlineImage) m_t << "<div class=\"image\">" << endl;
1636 QCString sizeAttribs;
1637 if (!img->width().isEmpty())
1639 sizeAttribs+=" width=\""+img->width()+"\"";
1641 if (!img->height().isEmpty()) // link to local file
1643 sizeAttribs+=" height=\""+img->height()+"\"";
1649 m_t << "<object type=\"image/svg+xml\" data=\"" << img->relPath() << img->name()
1650 << "\"" << sizeAttribs << htmlAttribsToString(img->attribs()) << ">" << baseName
1651 << "</object>" << endl;
1655 m_t << "<img src=\"" << img->relPath() << img->name() << "\" alt=\""
1656 << baseName << "\"" << sizeAttribs << htmlAttribsToString(img->attribs())
1657 << (inlineImage ? " class=\"inline\"" : "/>\n");
1664 m_t << "<object type=\"image/svg+xml\" data=\"" << correctURL(url,img->relPath())
1665 << "\"" << sizeAttribs << htmlAttribsToString(img->attribs())
1666 << "></object>" << endl;
1670 m_t << "<img src=\"" << correctURL(url,img->relPath()) << "\""
1671 << sizeAttribs << htmlAttribsToString(img->attribs(), TRUE)
1672 << (inlineImage ? " class=\"inline\"" : "/>\n");
1675 if (img->hasCaption())
1683 m_t << "<div class=\"caption\">" << endl;
1684 m_t << getHtmlDirEmbedingChar(getTextDirByConfig(img));
1687 else if (inlineImage)
1689 m_t << "/>" << endl;
1692 else // other format -> skip
1699 void HtmlDocVisitor::visitPost(DocImage *img)
1701 if (img->type()==DocImage::Html)
1704 bool inlineImage = img->isInlineImage();
1705 if (img->hasCaption())
1714 m_t << "</div>" << endl;
1715 forceStartParagraph(img);
1718 else // other format
1724 void HtmlDocVisitor::visitPre(DocDotFile *df)
1727 m_t << "<div class=\"dotgraph\">" << endl;
1728 writeDotFile(df->file(),df->relPath(),df->context());
1729 if (df->hasCaption())
1731 m_t << "<div class=\"caption\">" << endl;
1735 void HtmlDocVisitor::visitPost(DocDotFile *df)
1738 if (df->hasCaption())
1740 m_t << "</div>" << endl;
1742 m_t << "</div>" << endl;
1745 void HtmlDocVisitor::visitPre(DocMscFile *df)
1748 m_t << "<div class=\"mscgraph\">" << endl;
1749 writeMscFile(df->file(),df->relPath(),df->context());
1750 if (df->hasCaption())
1752 m_t << "<div class=\"caption\">" << endl;
1755 void HtmlDocVisitor::visitPost(DocMscFile *df)
1758 if (df->hasCaption())
1760 m_t << "</div>" << endl;
1762 m_t << "</div>" << endl;
1765 void HtmlDocVisitor::visitPre(DocDiaFile *df)
1768 m_t << "<div class=\"diagraph\">" << endl;
1769 writeDiaFile(df->file(),df->relPath(),df->context());
1770 if (df->hasCaption())
1772 m_t << "<div class=\"caption\">" << endl;
1775 void HtmlDocVisitor::visitPost(DocDiaFile *df)
1778 if (df->hasCaption())
1780 m_t << "</div>" << endl;
1782 m_t << "</div>" << endl;
1785 void HtmlDocVisitor::visitPre(DocLink *lnk)
1788 startLink(lnk->ref(),lnk->file(),lnk->relPath(),lnk->anchor());
1791 void HtmlDocVisitor::visitPost(DocLink *)
1797 void HtmlDocVisitor::visitPre(DocRef *ref)
1800 if (!ref->file().isEmpty())
1802 // when ref->isSubPage()==TRUE we use ref->file() for HTML and
1803 // ref->anchor() for LaTeX/RTF
1804 startLink(ref->ref(),ref->file(),ref->relPath(),ref->isSubPage() ? QCString() : ref->anchor());
1806 if (!ref->hasLinkText()) filter(ref->targetTitle());
1809 void HtmlDocVisitor::visitPost(DocRef *ref)
1812 if (!ref->file().isEmpty()) endLink();
1816 void HtmlDocVisitor::visitPre(DocSecRefItem *ref)
1819 QString refName=ref->file();
1820 if (refName.right(Doxygen::htmlFileExtension.length())!=
1821 QString(Doxygen::htmlFileExtension))
1823 refName+=Doxygen::htmlFileExtension;
1825 m_t << "<li><a href=\"" << refName << "#" << ref->anchor() << "\">";
1829 void HtmlDocVisitor::visitPost(DocSecRefItem *)
1832 m_t << "</a></li>\n";
1835 void HtmlDocVisitor::visitPre(DocSecRefList *s)
1838 forceEndParagraph(s);
1839 m_t << "<div class=\"multicol\">" << endl;
1840 m_t << "<ul>" << endl;
1843 void HtmlDocVisitor::visitPost(DocSecRefList *s)
1846 m_t << "</ul>" << endl;
1847 m_t << "</div>" << endl;
1848 forceStartParagraph(s);
1851 //void HtmlDocVisitor::visitPre(DocLanguage *l)
1853 // QString langId = Config_getEnum(OUTPUT_LANGUAGE);
1854 // if (l->id().lower()!=langId.lower())
1861 //void HtmlDocVisitor::visitPost(DocLanguage *l)
1863 // QString langId = Config_getEnum(OUTPUT_LANGUAGE);
1864 // if (l->id().lower()!=langId.lower())
1870 void HtmlDocVisitor::visitPre(DocParamSect *s)
1873 forceEndParagraph(s);
1878 case DocParamSect::Param:
1879 heading=theTranslator->trParameters();
1882 case DocParamSect::RetVal:
1883 heading=theTranslator->trReturnValues();
1886 case DocParamSect::Exception:
1887 heading=theTranslator->trExceptions();
1888 className="exception";
1890 case DocParamSect::TemplateParam:
1891 heading=theTranslator->trTemplateParameters();
1892 className="tparams";
1897 m_t << "<dl class=\"" << className << "\"><dt>";
1899 m_t << "</dt><dd>" << endl;
1900 m_t << " <table class=\"" << className << "\">" << endl;
1903 void HtmlDocVisitor::visitPost(DocParamSect *s)
1906 m_t << " </table>" << endl;
1907 m_t << " </dd>" << endl;
1908 m_t << "</dl>" << endl;
1909 forceStartParagraph(s);
1912 void HtmlDocVisitor::visitPre(DocParamList *pl)
1914 //printf("DocParamList::visitPre\n");
1917 DocParamSect *sect = 0;
1918 if (pl->parent()->kind()==DocNode::Kind_ParamSect)
1920 sect=(DocParamSect*)pl->parent();
1922 if (sect && sect->hasInOutSpecifier())
1924 m_t << "<td class=\"paramdir\">";
1925 if (pl->direction()!=DocParamSect::Unspecified)
1928 if (pl->direction()==DocParamSect::In)
1932 else if (pl->direction()==DocParamSect::Out)
1936 else if (pl->direction()==DocParamSect::InOut)
1944 if (sect && sect->hasTypeSpecifier())
1946 m_t << "<td class=\"paramtype\">";
1947 QListIterator<DocNode> li(pl->paramTypes());
1950 for (li.toFirst();(type=li.current());++li)
1952 if (!first) m_t << " | "; else first=FALSE;
1953 if (type->kind()==DocNode::Kind_Word)
1955 visit((DocWord*)type);
1957 else if (type->kind()==DocNode::Kind_LinkedWord)
1959 visit((DocLinkedWord*)type);
1964 m_t << "<td class=\"paramname\">";
1965 //QStrListIterator li(pl->parameters());
1967 QListIterator<DocNode> li(pl->parameters());
1970 for (li.toFirst();(param=li.current());++li)
1972 if (!first) m_t << ","; else first=FALSE;
1973 if (param->kind()==DocNode::Kind_Word)
1975 visit((DocWord*)param);
1977 else if (param->kind()==DocNode::Kind_LinkedWord)
1979 visit((DocLinkedWord*)param);
1985 void HtmlDocVisitor::visitPost(DocParamList *)
1987 //printf("DocParamList::visitPost\n");
1989 m_t << "</td></tr>" << endl;
1992 void HtmlDocVisitor::visitPre(DocXRefItem *x)
1995 if (x->title().isEmpty()) return;
1997 forceEndParagraph(x);
1998 bool anonymousEnum = x->file()=="@";
2001 m_t << "<dl" << getDirHtmlClassOfNode(getTextDirByConfig(x), x->key())
2002 << "><dt><b><a class=\"el\" href=\""
2003 << x->relPath() << x->file() << Doxygen::htmlFileExtension
2004 << "#" << x->anchor() << "\">";
2008 m_t << "<dl class=\"" << x->key() << "\"><dt><b>";
2012 if (!anonymousEnum) m_t << "</a>";
2013 m_t << "</b></dt><dd>";
2016 void HtmlDocVisitor::visitPost(DocXRefItem *x)
2019 if (x->title().isEmpty()) return;
2020 m_t << "</dd></dl>" << endl;
2021 forceStartParagraph(x);
2024 void HtmlDocVisitor::visitPre(DocInternalRef *ref)
2027 startLink(0,ref->file(),ref->relPath(),ref->anchor());
2030 void HtmlDocVisitor::visitPost(DocInternalRef *)
2037 void HtmlDocVisitor::visitPre(DocCopy *)
2041 void HtmlDocVisitor::visitPost(DocCopy *)
2045 void HtmlDocVisitor::visitPre(DocText *)
2049 void HtmlDocVisitor::visitPost(DocText *)
2053 void HtmlDocVisitor::visitPre(DocHtmlBlockQuote *b)
2056 forceEndParagraph(b);
2057 QString attrs = htmlAttribsToString(b->attribs());
2058 if (attrs.isEmpty())
2060 m_t << "<blockquote" << getDirHtmlClassOfNode(getTextDirByConfig(b), "doxtable")
2065 m_t << "<blockquote" << getDirHtmlClassOfNode(getTextDirByConfig(b))
2066 << htmlAttribsToString(b->attribs()) << ">\n";
2070 void HtmlDocVisitor::visitPost(DocHtmlBlockQuote *b)
2073 m_t << "</blockquote>" << endl;
2074 forceStartParagraph(b);
2077 void HtmlDocVisitor::visitPre(DocVhdlFlow *vf)
2080 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2082 forceEndParagraph(vf);
2083 QCString fname=FlowChart::convertNameToFileName();
2085 m_t << "flowchart: " ; // TODO: translate me
2086 m_t << "<a href=\"";
2087 m_t << fname.data();
2089 m_t << VhdlDocGen::getFlowMember()->name().data();
2091 if (vf->hasCaption())
2098 void HtmlDocVisitor::visitPost(DocVhdlFlow *vf)
2101 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2104 forceStartParagraph(vf);
2108 void HtmlDocVisitor::visitPre(DocParBlock *)
2113 void HtmlDocVisitor::visitPost(DocParBlock *)
2120 void HtmlDocVisitor::filter(const char *str)
2130 case '<': m_t << "<"; break;
2131 case '>': m_t << ">"; break;
2132 case '&': m_t << "&"; break;
2138 /// Escape basic entities to produce a valid CDATA attribute value,
2139 /// assume that the outer quoting will be using the double quote "
2140 void HtmlDocVisitor::filterQuotedCdataAttr(const char* str)
2150 case '&': m_t << "&"; break;
2151 case '"': m_t << """; break;
2152 case '<': m_t << "<"; break;
2153 case '>': m_t << ">"; break;
2159 void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file,
2160 const QCString &relPath,const QCString &anchor,
2161 const QCString &tooltip)
2163 //printf("HtmlDocVisitor: file=%s anchor=%s\n",file.data(),anchor.data());
2164 if (!ref.isEmpty()) // link to entity imported via tag file
2166 m_t << "<a class=\"elRef\" ";
2167 m_t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
2171 m_t << "<a class=\"el\" ";
2174 m_t << externalRef(relPath,ref,TRUE);
2175 if (!file.isEmpty()) m_t << file << Doxygen::htmlFileExtension;
2176 if (!anchor.isEmpty()) m_t << "#" << anchor;
2178 if (!tooltip.isEmpty()) m_t << " title=\"" << convertToHtml(tooltip) << "\"";
2182 void HtmlDocVisitor::endLink()
2187 void HtmlDocVisitor::pushEnabled()
2189 m_enabled.push(new bool(m_hide));
2192 void HtmlDocVisitor::popEnabled()
2194 bool *v=m_enabled.pop();
2200 void HtmlDocVisitor::writeDotFile(const QCString &fn,const QCString &relPath,
2201 const QCString &context)
2203 QCString baseName=fn;
2205 if ((i=baseName.findRev('/'))!=-1)
2207 baseName=baseName.right(baseName.length()-i-1);
2209 if ((i=baseName.find('.'))!=-1) // strip extension
2211 baseName=baseName.left(i);
2213 baseName.prepend("dot_");
2214 QCString outDir = Config_getString(HTML_OUTPUT);
2215 writeDotGraphFromFile(fn,outDir,baseName,GOF_BITMAP);
2216 writeDotImageMapFromFile(m_t,fn,outDir,relPath,baseName,context);
2219 void HtmlDocVisitor::writeMscFile(const QCString &fileName,
2220 const QCString &relPath,
2221 const QCString &context)
2223 QCString baseName=fileName;
2225 if ((i=baseName.findRev('/'))!=-1) // strip path
2227 baseName=baseName.right(baseName.length()-i-1);
2229 if ((i=baseName.find('.'))!=-1) // strip extension
2231 baseName=baseName.left(i);
2233 baseName.prepend("msc_");
2234 QCString outDir = Config_getString(HTML_OUTPUT);
2235 QCString imgExt = getDotImageExtension();
2236 MscOutputFormat mscFormat = MSC_BITMAP;
2237 if ("svg" == imgExt)
2238 mscFormat = MSC_SVG;
2239 writeMscGraphFromFile(fileName,outDir,baseName,mscFormat);
2240 writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context,mscFormat);
2243 void HtmlDocVisitor::writeDiaFile(const QCString &fileName,
2244 const QCString &relPath,
2247 QCString baseName=fileName;
2249 if ((i=baseName.findRev('/'))!=-1) // strip path
2251 baseName=baseName.right(baseName.length()-i-1);
2253 if ((i=baseName.find('.'))!=-1) // strip extension
2255 baseName=baseName.left(i);
2257 baseName.prepend("dia_");
2258 QCString outDir = Config_getString(HTML_OUTPUT);
2259 writeDiaGraphFromFile(fileName,outDir,baseName,DIA_BITMAP);
2261 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />" << endl;
2264 void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName,
2265 const QCString &relPath,
2268 QCString baseName=fileName;
2270 if ((i=baseName.findRev('/'))!=-1) // strip path
2272 baseName=baseName.right(baseName.length()-i-1);
2274 if ((i=baseName.findRev('.'))!=-1) // strip extension
2276 baseName=baseName.left(i);
2278 static QCString outDir = Config_getString(HTML_OUTPUT);
2279 QCString imgExt = getDotImageExtension();
2282 generatePlantUMLOutput(fileName,outDir,PUML_SVG);
2283 //m_t << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" << relPath << baseName << ".svg" << "\" />" << endl;
2284 //m_t << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
2285 //m_t << "</iframe>" << endl;
2286 m_t << "<object type=\"image/svg+xml\" data=\"" << relPath << baseName << ".svg\"></object>" << endl;
2290 generatePlantUMLOutput(fileName,outDir,PUML_BITMAP);
2291 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />" << endl;
2295 /** Returns TRUE if the child nodes in paragraph \a para until \a nodeIndex
2296 contain a style change node that is still active and that style change is one that
2297 must be located outside of a paragraph, i.e. it is a center, div, or pre tag.
2300 static bool insideStyleChangeThatIsOutsideParagraph(DocPara *para,int nodeIndex)
2302 //printf("insideStyleChangeThatIsOutputParagraph(index=%d)\n",nodeIndex);
2304 bool styleOutsideParagraph=FALSE;
2305 while (nodeIndex>=0 && !styleOutsideParagraph)
2307 DocNode *n = para->children().at(nodeIndex);
2308 if (n->kind()==DocNode::Kind_StyleChange)
2310 DocStyleChange *sc = (DocStyleChange*)n;
2311 if (!sc->enable()) // remember styles that has been closed already
2313 styleMask|=(int)sc->style();
2315 bool paraStyle = sc->style()==DocStyleChange::Center ||
2316 sc->style()==DocStyleChange::Div ||
2317 sc->style()==DocStyleChange::Preformatted;
2318 //printf("Found style change %s enabled=%d\n",sc->styleString(),sc->enable());
2319 if (sc->enable() && (styleMask&(int)sc->style())==0 && // style change that is still active
2323 styleOutsideParagraph=TRUE;
2328 return styleOutsideParagraph;
2331 /** Used for items found inside a paragraph, which due to XHTML restrictions
2332 * have to be outside of the paragraph. This method will forcefully end
2333 * the current paragraph and forceStartParagraph() will restart it.
2335 void HtmlDocVisitor::forceEndParagraph(DocNode *n)
2337 //printf("forceEndParagraph(%p) %d\n",n,n->kind());
2338 if (n->parent() && n->parent()->kind()==DocNode::Kind_Para)
2340 DocPara *para = (DocPara*)n->parent();
2341 int nodeIndex = para->children().findRef(n);
2343 if (nodeIndex<0) return; // first node
2344 while (nodeIndex>=0 && isInvisibleNode(para->children().at(nodeIndex)))
2350 DocNode *n = para->children().at(nodeIndex);
2351 if (mustBeOutsideParagraph(n)) return;
2354 bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,nodeIndex);
2357 getParagraphContext(para,isFirst,isLast);
2358 //printf("forceEnd first=%d last=%d styleOutsideParagraph=%d\n",isFirst,isLast,styleOutsideParagraph);
2359 if (isFirst && isLast) return;
2360 if (styleOutsideParagraph) return;
2366 /** Used for items found inside a paragraph, which due to XHTML restrictions
2367 * have to be outside of the paragraph. This method will forcefully start
2368 * the paragraph, that was previously ended by forceEndParagraph().
2370 void HtmlDocVisitor::forceStartParagraph(DocNode *n)
2372 //printf("forceStartParagraph(%p) %d\n",n,n->kind());
2373 if (n->parent() && n->parent()->kind()==DocNode::Kind_Para) // if we are inside a paragraph
2375 DocPara *para = (DocPara*)n->parent();
2376 int nodeIndex = para->children().findRef(n);
2377 int numNodes = para->children().count();
2378 bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,nodeIndex);
2379 if (styleOutsideParagraph) return;
2381 if (nodeIndex==numNodes) return; // last node
2382 while (nodeIndex<numNodes && isInvisibleNode(para->children().at(nodeIndex)))
2386 if (nodeIndex<numNodes)
2388 DocNode *n = para->children().at(nodeIndex);
2389 if (mustBeOutsideParagraph(n)) return; // next element also outside paragraph
2393 return; // only whitespace at the end!
2396 bool needsTag = TRUE;
2399 getParagraphContext(para,isFirst,isLast);
2400 if (isFirst && isLast) needsTag = FALSE;
2401 //printf("forceStart first=%d last=%d needsTag=%d\n",isFirst,isLast,needsTag);
2404 m_t << "<p" << getDirHtmlClassOfNode(getTextDirByConfig(para, nodeIndex)) << ">";
2406 m_t << getHtmlDirEmbedingChar(getTextDirByConfig(para, nodeIndex));