00001 /****************************************************************************** 00002 * 00003 * $Id: $ 00004 * 00005 * 00006 * Copyright (C) 1997-2008 by Dimitri van Heesch. 00007 * 00008 * Permission to use, copy, modify, and distribute this software and its 00009 * documentation under the terms of the GNU General Public License is hereby 00010 * granted. No representations are made about the suitability of this software 00011 * for any purpose. It is provided "as is" without express or implied warranty. 00012 * See the GNU General Public License for more details. 00013 * 00014 * Documents produced by Doxygen are derivative works derived from the 00015 * input used in their production; they are not affected by this license. 00016 * 00017 */ 00018 00019 #include <qdir.h> 00020 #include "htmldocvisitor.h" 00021 #include "docparser.h" 00022 #include "language.h" 00023 #include "doxygen.h" 00024 #include "outputgen.h" 00025 #include "dot.h" 00026 #include "message.h" 00027 #include "config.h" 00028 #include "htmlgen.h" 00029 #include "parserintf.h" 00030 #include "msc.h" 00031 #include "util.h" 00032 00033 00034 static const int NUM_HTML_LIST_TYPES = 4; 00035 static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"}; 00036 00037 00038 static QString htmlAttribsToString(const HtmlAttribList &attribs) 00039 { 00040 QString result; 00041 HtmlAttribListIterator li(attribs); 00042 HtmlAttrib *att; 00043 for (li.toFirst();(att=li.current());++li) 00044 { 00045 result+=" "; 00046 result+=att->name; 00047 if (!att->value.isEmpty()) result+="=\""+att->value+"\""; 00048 } 00049 return result; 00050 } 00051 00052 //------------------------------------------------------------------------- 00053 00054 HtmlDocVisitor::HtmlDocVisitor(QTextStream &t,CodeOutputInterface &ci, 00055 const char *langExt) 00056 : DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE), 00057 m_hide(FALSE), m_langExt(langExt) 00058 { 00059 } 00060 00061 //-------------------------------------- 00062 // visitor functions for leaf nodes 00063 //-------------------------------------- 00064 00065 void HtmlDocVisitor::visit(DocWord *w) 00066 { 00067 if (m_hide) return; 00068 filter(w->word()); 00069 } 00070 00071 void HtmlDocVisitor::visit(DocLinkedWord *w) 00072 { 00073 if (m_hide) return; 00074 startLink(w->ref(),w->file(),w->relPath(),w->anchor(),w->tooltip()); 00075 filter(w->word()); 00076 endLink(); 00077 } 00078 00079 void HtmlDocVisitor::visit(DocWhiteSpace *w) 00080 { 00081 if (m_hide) return; 00082 if (m_insidePre) 00083 { 00084 m_t << w->chars(); 00085 } 00086 else 00087 { 00088 m_t << " "; 00089 } 00090 } 00091 00092 void HtmlDocVisitor::visit(DocSymbol *s) 00093 { 00094 if (m_hide) return; 00095 switch(s->symbol()) 00096 { 00097 case DocSymbol::BSlash: m_t << "\\"; break; 00098 case DocSymbol::At: m_t << "@"; break; 00099 case DocSymbol::Less: m_t << "<"; break; 00100 case DocSymbol::Greater: m_t << ">"; break; 00101 case DocSymbol::Amp: m_t << "&"; break; 00102 case DocSymbol::Dollar: m_t << "$"; break; 00103 case DocSymbol::Hash: m_t << "#"; break; 00104 case DocSymbol::Percent: m_t << "%"; break; 00105 case DocSymbol::Copy: m_t << "©"; break; 00106 case DocSymbol::Tm: m_t << "™"; break; 00107 case DocSymbol::Reg: m_t << "®"; break; 00108 case DocSymbol::Apos: m_t << "'"; break; 00109 case DocSymbol::Quot: m_t << "\""; break; 00110 case DocSymbol::Lsquo: m_t << "‘"; break; 00111 case DocSymbol::Rsquo: m_t << "’"; break; 00112 case DocSymbol::Ldquo: m_t << "“"; break; 00113 case DocSymbol::Rdquo: m_t << "”"; break; 00114 case DocSymbol::Ndash: m_t << "–"; break; 00115 case DocSymbol::Mdash: m_t << "—"; break; 00116 case DocSymbol::Uml: m_t << "&" << s->letter() << "uml;"; break; 00117 case DocSymbol::Acute: m_t << "&" << s->letter() << "acute;"; break; 00118 case DocSymbol::Grave: m_t << "&" << s->letter() << "grave;"; break; 00119 case DocSymbol::Circ: m_t << "&" << s->letter() << "circ;"; break; 00120 case DocSymbol::Slash: m_t << "&" << s->letter() << "slash;"; break; 00121 case DocSymbol::Tilde: m_t << "&" << s->letter() << "tilde;"; break; 00122 case DocSymbol::Szlig: m_t << "ß"; break; 00123 case DocSymbol::Cedil: m_t << "&" << s->letter() << "cedil;"; break; 00124 case DocSymbol::Ring: m_t << "&" << s->letter() << "ring;"; break; 00125 case DocSymbol::Nbsp: m_t << " "; break; 00126 default: 00127 err("Error: unknown symbol found\n"); 00128 } 00129 } 00130 00131 void HtmlDocVisitor::visit(DocURL *u) 00132 { 00133 if (m_hide) return; 00134 m_t << "<a href=\""; 00135 if (u->isEmail()) m_t << "mailto:"; 00136 m_t << u->url() << "\">"; 00137 filter(u->url()); 00138 m_t << "</a>"; 00139 } 00140 00141 void HtmlDocVisitor::visit(DocLineBreak *) 00142 { 00143 if (m_hide) return; 00144 m_t << "<br>\n"; 00145 } 00146 00147 void HtmlDocVisitor::visit(DocHorRuler *) 00148 { 00149 if (m_hide) return; 00150 m_t << "<hr>\n"; 00151 } 00152 00153 void HtmlDocVisitor::visit(DocStyleChange *s) 00154 { 00155 if (m_hide) return; 00156 switch (s->style()) 00157 { 00158 case DocStyleChange::Bold: 00159 if (s->enable()) m_t << "<b" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</b>"; 00160 break; 00161 case DocStyleChange::Italic: 00162 if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>"; 00163 break; 00164 case DocStyleChange::Code: 00165 if (s->enable()) m_t << "<code" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</code>"; 00166 break; 00167 case DocStyleChange::Subscript: 00168 if (s->enable()) m_t << "<sub" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sub>"; 00169 break; 00170 case DocStyleChange::Superscript: 00171 if (s->enable()) m_t << "<sup" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sup>"; 00172 break; 00173 case DocStyleChange::Center: 00174 if (s->enable()) m_t << "<center" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</center>"; 00175 break; 00176 case DocStyleChange::Small: 00177 if (s->enable()) m_t << "<small" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</small>"; 00178 break; 00179 case DocStyleChange::Preformatted: 00180 if (s->enable()) 00181 { 00182 m_t << "<pre" << htmlAttribsToString(s->attribs()) << ">"; 00183 m_insidePre=TRUE; 00184 } 00185 else 00186 { 00187 m_insidePre=FALSE; 00188 m_t << "</pre>"; 00189 } 00190 break; 00191 case DocStyleChange::Div: 00192 if (s->enable()) m_t << "<div" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</div>"; 00193 break; 00194 case DocStyleChange::Span: 00195 if (s->enable()) m_t << "<span" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</span>"; 00196 break; 00197 00198 } 00199 } 00200 00201 00202 void HtmlDocVisitor::visit(DocVerbatim *s) 00203 { 00204 if (m_hide) return; 00205 switch(s->type()) 00206 { 00207 case DocVerbatim::Code: // fall though 00208 m_t << PREFRAG_START; 00209 Doxygen::parserManager->getParser(m_langExt) 00210 ->parseCode(m_ci,s->context(),s->text().latin1(), 00211 s->isExample(),s->exampleFile()); 00212 m_t << PREFRAG_END; 00213 break; 00214 case DocVerbatim::Verbatim: 00215 m_t << PREFRAG_START; 00216 filter(s->text()); 00217 m_t << PREFRAG_END; 00218 break; 00219 case DocVerbatim::HtmlOnly: 00220 m_t << s->text(); 00221 break; 00222 case DocVerbatim::ManOnly: 00223 case DocVerbatim::LatexOnly: 00224 case DocVerbatim::XmlOnly: 00225 /* nothing */ 00226 break; 00227 00228 case DocVerbatim::Dot: 00229 { 00230 static int dotindex = 1; 00231 QCString fileName(4096); 00232 00233 fileName.sprintf("%s%d%s", 00234 (Config_getString("HTML_OUTPUT")+"/inline_dotgraph_").data(), 00235 dotindex++, 00236 ".dot" 00237 ); 00238 QFile file(fileName); 00239 if (!file.open(IO_WriteOnly)) 00240 { 00241 err("Could not open file %s for writing\n",fileName.data()); 00242 } 00243 file.writeBlock( s->text(), s->text().length() ); 00244 file.close(); 00245 00246 m_t << "<div align=\"center\">" << endl; 00247 writeDotFile(fileName,s->relPath(),s->context()); 00248 m_t << "</div>" << endl; 00249 00250 if (Config_getBool("DOT_CLEANUP")) file.remove(); 00251 } 00252 break; 00253 case DocVerbatim::Msc: 00254 { 00255 static int mscindex = 1; 00256 QCString baseName(4096); 00257 00258 baseName.sprintf("%s%d", 00259 (Config_getString("HTML_OUTPUT")+"/inline_mscgraph_").data(), 00260 mscindex++ 00261 ); 00262 QFile file(baseName+".msc"); 00263 if (!file.open(IO_WriteOnly)) 00264 { 00265 err("Could not open file %s.msc for writing\n",baseName.data()); 00266 } 00267 QCString text = "msc {"; 00268 text+=s->text(); 00269 text+="}"; 00270 file.writeBlock( text, text.length() ); 00271 file.close(); 00272 00273 m_t << "<div align=\"center\">" << endl; 00274 writeMscFile(baseName,s->relPath(),s->context()); 00275 m_t << "</div>" << endl; 00276 00277 if (Config_getBool("DOT_CLEANUP")) file.remove(); 00278 } 00279 break; 00280 } 00281 } 00282 00283 void HtmlDocVisitor::visit(DocAnchor *anc) 00284 { 00285 if (m_hide) return; 00286 m_t << "<a class=\"anchor\" name=\"" << anc->anchor() << "\"></a>"; 00287 } 00288 00289 void HtmlDocVisitor::visit(DocInclude *inc) 00290 { 00291 if (m_hide) return; 00292 switch(inc->type()) 00293 { 00294 case DocInclude::Include: 00295 m_t << PREFRAG_START; 00296 Doxygen::parserManager->getParser(inc->extension()) 00297 ->parseCode(m_ci, 00298 inc->context(), 00299 inc->text().latin1(), 00300 inc->isExample(), 00301 inc->exampleFile(), 00302 0, // fd 00303 -1, // startLine 00304 -1, // endLine 00305 TRUE // inlineFragment 00306 ); 00307 m_t << PREFRAG_END; 00308 break; 00309 case DocInclude::IncWithLines: 00310 { 00311 m_t << PREFRAG_START; 00312 QFileInfo cfi( inc->file() ); 00313 FileDef fd( cfi.dirPath(), cfi.fileName() ); 00314 Doxygen::parserManager->getParser(inc->extension()) 00315 ->parseCode(m_ci, 00316 inc->context(), 00317 inc->text().latin1(), 00318 inc->isExample(), 00319 inc->exampleFile(), &fd); 00320 m_t << PREFRAG_END; 00321 } 00322 break; 00323 case DocInclude::DontInclude: 00324 break; 00325 case DocInclude::HtmlInclude: 00326 m_t << inc->text(); 00327 break; 00328 case DocInclude::VerbInclude: 00329 m_t << PREFRAG_START; 00330 filter(inc->text()); 00331 m_t << PREFRAG_END; 00332 break; 00333 } 00334 } 00335 00336 void HtmlDocVisitor::visit(DocIncOperator *op) 00337 { 00338 //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", 00339 // op->type(),op->isFirst(),op->isLast(),op->text().data()); 00340 if (op->isFirst()) 00341 { 00342 if (!m_hide) m_t << PREFRAG_START; 00343 pushEnabled(); 00344 m_hide=TRUE; 00345 } 00346 if (op->type()!=DocIncOperator::Skip) 00347 { 00348 popEnabled(); 00349 if (!m_hide) 00350 { 00351 Doxygen::parserManager->getParser(m_langExt) 00352 ->parseCode(m_ci,op->context(), 00353 op->text().latin1(),op->isExample(), 00354 op->exampleFile()); 00355 } 00356 pushEnabled(); 00357 m_hide=TRUE; 00358 } 00359 if (op->isLast()) 00360 { 00361 popEnabled(); 00362 if (!m_hide) m_t << PREFRAG_END; 00363 } 00364 else 00365 { 00366 if (!m_hide) m_t << endl; 00367 } 00368 } 00369 00370 void HtmlDocVisitor::visit(DocFormula *f) 00371 { 00372 if (m_hide) return; 00373 bool bDisplay = f->text().at(0)=='\\'; 00374 if (bDisplay) m_t << "<p class=\"formulaDsp\">" << endl; 00375 m_t << "<img class=\"formula" 00376 << (bDisplay ? "Dsp" : "Inl"); 00377 m_t << "\" alt=\""; 00378 filterQuotedCdataAttr(f->text()); 00379 m_t << "\""; 00382 m_t << " src=\"" << f->relPath() << f->name() << ".png\">"; 00383 if (bDisplay) 00384 m_t << endl << "<p>" << endl; 00385 } 00386 00387 void HtmlDocVisitor::visit(DocIndexEntry *) 00388 { 00389 } 00390 00391 //-------------------------------------- 00392 // visitor functions for compound nodes 00393 //-------------------------------------- 00394 00395 00396 void HtmlDocVisitor::visitPre(DocAutoList *l) 00397 { 00398 if (m_hide) return; 00399 if (l->isEnumList()) 00400 { 00401 // 00402 // Do list type based on depth: 00403 // 1. 00404 // a. 00405 // i. 00406 // A. 00407 // 1. (repeat)... 00408 // 00409 m_t << "<ol type=" << types[l->depth() % NUM_HTML_LIST_TYPES] << ">"; 00410 } 00411 else 00412 { 00413 m_t << "<ul>"; 00414 } 00415 if (!l->isPreformatted()) m_t << "\n"; 00416 } 00417 00418 void HtmlDocVisitor::visitPost(DocAutoList *l) 00419 { 00420 if (m_hide) return; 00421 if (l->isEnumList()) 00422 { 00423 m_t << "</ol>"; 00424 } 00425 else 00426 { 00427 m_t << "</ul>"; 00428 } 00429 if (!l->isPreformatted()) m_t << "\n"; 00430 } 00431 00432 void HtmlDocVisitor::visitPre(DocAutoListItem *) 00433 { 00434 if (m_hide) return; 00435 m_t << "<li>"; 00436 } 00437 00438 void HtmlDocVisitor::visitPost(DocAutoListItem *) 00439 { 00440 if (m_hide) return; 00441 m_t << "</li>"; 00442 } 00443 00444 void HtmlDocVisitor::visitPre(DocPara *) 00445 { 00446 if (m_hide) return; 00447 00448 // TODO: 00449 // Paragraph should be surrounded by <p>..</p>, but 00450 // 00451 // A list item (li), description data (dd), or table data (td) should 00452 // only have paragraph markers if there are multiple paragraphs (otherwise 00453 // the output looks ugly). 00454 // 00455 // A list or table should be placed outside the paragraph context, 00456 // so the current paragraph should be ended and restarted. To avoid 00457 // empty paragraphs, it has to be checked if the list or table is the 00458 // first or last child within the paragraph. 00459 00460 } 00461 00462 void HtmlDocVisitor::visitPost(DocPara *p) 00463 { 00464 if (m_hide) return; 00465 if (!p->isLast() && // omit <p> for last paragraph 00466 !(p->parent() && // and for parameter sections 00467 p->parent()->kind()==DocNode::Kind_ParamSect 00468 ) 00469 ) 00470 { 00471 m_t << "<p>\n"; 00472 } 00473 } 00474 00475 void HtmlDocVisitor::visitPre(DocRoot *) 00476 { 00477 } 00478 00479 void HtmlDocVisitor::visitPost(DocRoot *) 00480 { 00481 } 00482 00483 void HtmlDocVisitor::visitPre(DocSimpleSect *s) 00484 { 00485 if (m_hide) return; 00486 m_t << "<dl class=\"" << s->typeString() << "\" compact><dt><b>"; 00487 switch(s->type()) 00488 { 00489 case DocSimpleSect::See: 00490 m_t << theTranslator->trSeeAlso(); break; 00491 case DocSimpleSect::Return: 00492 m_t << theTranslator->trReturns(); break; 00493 case DocSimpleSect::Author: 00494 m_t << theTranslator->trAuthor(TRUE,TRUE); break; 00495 case DocSimpleSect::Authors: 00496 m_t << theTranslator->trAuthor(TRUE,FALSE); break; 00497 case DocSimpleSect::Version: 00498 m_t << theTranslator->trVersion(); break; 00499 case DocSimpleSect::Since: 00500 m_t << theTranslator->trSince(); break; 00501 case DocSimpleSect::Date: 00502 m_t << theTranslator->trDate(); break; 00503 case DocSimpleSect::Note: 00504 m_t << theTranslator->trNote(); break; 00505 case DocSimpleSect::Warning: 00506 m_t << theTranslator->trWarning(); break; 00507 case DocSimpleSect::Pre: 00508 m_t << theTranslator->trPrecondition(); break; 00509 case DocSimpleSect::Post: 00510 m_t << theTranslator->trPostcondition(); break; 00511 case DocSimpleSect::Invar: 00512 m_t << theTranslator->trInvariant(); break; 00513 case DocSimpleSect::Remark: 00514 m_t << theTranslator->trRemarks(); break; 00515 case DocSimpleSect::Attention: 00516 m_t << theTranslator->trAttention(); break; 00517 case DocSimpleSect::User: break; 00518 case DocSimpleSect::Rcs: break; 00519 case DocSimpleSect::Unknown: break; 00520 } 00521 00522 // special case 1: user defined title 00523 if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) 00524 { 00525 m_t << ":</b></dt><dd>"; 00526 } 00527 } 00528 00529 void HtmlDocVisitor::visitPost(DocSimpleSect *) 00530 { 00531 if (m_hide) return; 00532 m_t << "</dd></dl>\n"; 00533 } 00534 00535 void HtmlDocVisitor::visitPre(DocTitle *) 00536 { 00537 } 00538 00539 void HtmlDocVisitor::visitPost(DocTitle *) 00540 { 00541 if (m_hide) return; 00542 m_t << "</b></dt><dd>"; 00543 } 00544 00545 void HtmlDocVisitor::visitPre(DocSimpleList *sl) 00546 { 00547 if (m_hide) return; 00548 m_t << "<ul>"; 00549 if (!sl->isPreformatted()) m_t << "\n"; 00550 } 00551 00552 void HtmlDocVisitor::visitPost(DocSimpleList *sl) 00553 { 00554 if (m_hide) return; 00555 m_t << "</ul>"; 00556 if (!sl->isPreformatted()) m_t << "\n"; 00557 } 00558 00559 void HtmlDocVisitor::visitPre(DocSimpleListItem *) 00560 { 00561 if (m_hide) return; 00562 m_t << "<li>"; 00563 } 00564 00565 void HtmlDocVisitor::visitPost(DocSimpleListItem *li) 00566 { 00567 if (m_hide) return; 00568 m_t << "</li>"; 00569 if (!li->isPreformatted()) m_t << "\n"; 00570 } 00571 00572 void HtmlDocVisitor::visitPre(DocSection *s) 00573 { 00574 if (m_hide) return; 00575 m_t << "<h" << s->level()+1 << ">"; 00576 m_t << "<a class=\"anchor\" name=\"" << s->anchor(); 00577 m_t << "\">" << endl; 00578 filter(convertCharEntitiesToUTF8(s->title().data())); 00579 m_t << "</a></h" << s->level()+1 << ">\n"; 00580 } 00581 00582 void HtmlDocVisitor::visitPost(DocSection *) 00583 { 00584 } 00585 00586 void HtmlDocVisitor::visitPre(DocHtmlList *s) 00587 { 00588 if (m_hide) return; 00589 if (s->type()==DocHtmlList::Ordered) 00590 { 00591 m_t << "<ol" << htmlAttribsToString(s->attribs()) << ">\n"; 00592 } 00593 else 00594 { 00595 m_t << "<ul" << htmlAttribsToString(s->attribs()) << ">\n"; 00596 } 00597 } 00598 00599 void HtmlDocVisitor::visitPost(DocHtmlList *s) 00600 { 00601 if (m_hide) return; 00602 if (s->type()==DocHtmlList::Ordered) 00603 { 00604 m_t << "</ol>"; 00605 } 00606 else 00607 { 00608 m_t << "</ul>"; 00609 } 00610 if (!s->isPreformatted()) m_t << "\n"; 00611 } 00612 00613 void HtmlDocVisitor::visitPre(DocHtmlListItem *i) 00614 { 00615 if (m_hide) return; 00616 m_t << "<li" << htmlAttribsToString(i->attribs()) << ">"; 00617 if (!i->isPreformatted()) m_t << "\n"; 00618 } 00619 00620 void HtmlDocVisitor::visitPost(DocHtmlListItem *) 00621 { 00622 if (m_hide) return; 00623 m_t << "</li>\n"; 00624 } 00625 00626 void HtmlDocVisitor::visitPre(DocHtmlDescList *dl) 00627 { 00628 if (m_hide) return; 00629 m_t << "<dl" << htmlAttribsToString(dl->attribs()) << ">\n"; 00630 } 00631 00632 void HtmlDocVisitor::visitPost(DocHtmlDescList *) 00633 { 00634 if (m_hide) return; 00635 m_t << "</dl>\n"; 00636 } 00637 00638 void HtmlDocVisitor::visitPre(DocHtmlDescTitle *dt) 00639 { 00640 if (m_hide) return; 00641 m_t << "<dt" << htmlAttribsToString(dt->attribs()) << ">"; 00642 } 00643 00644 void HtmlDocVisitor::visitPost(DocHtmlDescTitle *) 00645 { 00646 if (m_hide) return; 00647 m_t << "</dt>\n"; 00648 } 00649 00650 void HtmlDocVisitor::visitPre(DocHtmlDescData *dd) 00651 { 00652 if (m_hide) return; 00653 m_t << "<dd" << htmlAttribsToString(dd->attribs()) << ">"; 00654 } 00655 00656 void HtmlDocVisitor::visitPost(DocHtmlDescData *) 00657 { 00658 if (m_hide) return; 00659 m_t << "</dd>\n"; 00660 } 00661 00662 void HtmlDocVisitor::visitPre(DocHtmlTable *t) 00663 { 00664 if (m_hide) return; 00665 bool hasBorder = FALSE; 00666 bool hasCellSpacing = FALSE; 00667 bool hasCellPadding = FALSE; 00668 00669 HtmlAttribListIterator li(t->attribs()); 00670 HtmlAttrib *att; 00671 for (li.toFirst();(att=li.current());++li) 00672 { 00673 if (att->name=="border") hasBorder=TRUE; 00674 else if (att->name=="cellspacing") hasCellSpacing=TRUE; 00675 else if (att->name=="cellpadding") hasCellPadding=TRUE; 00676 } 00677 m_t << "<table" << htmlAttribsToString(t->attribs()); 00678 if (!hasBorder) m_t << " border=\"1\""; 00679 if (!hasCellSpacing) m_t << " cellspacing=\"3\""; 00680 if (!hasCellPadding) m_t << " cellpadding=\"3\""; 00681 m_t << ">\n"; 00682 } 00683 00684 void HtmlDocVisitor::visitPost(DocHtmlTable *) 00685 { 00686 if (m_hide) return; 00687 m_t << "</table>\n"; 00688 } 00689 00690 void HtmlDocVisitor::visitPre(DocHtmlRow *tr) 00691 { 00692 if (m_hide) return; 00693 m_t << "<tr" << htmlAttribsToString(tr->attribs()) << ">\n"; 00694 } 00695 00696 void HtmlDocVisitor::visitPost(DocHtmlRow *) 00697 { 00698 if (m_hide) return; 00699 m_t << "</tr>\n"; 00700 } 00701 00702 void HtmlDocVisitor::visitPre(DocHtmlCell *c) 00703 { 00704 if (m_hide) return; 00705 if (c->isHeading()) 00706 { 00707 m_t << "<th" << htmlAttribsToString(c->attribs()) << ">"; 00708 } 00709 else 00710 { 00711 m_t << "<td" << htmlAttribsToString(c->attribs()) << ">"; 00712 } 00713 } 00714 00715 void HtmlDocVisitor::visitPost(DocHtmlCell *c) 00716 { 00717 if (m_hide) return; 00718 if (c->isHeading()) m_t << "</th>"; else m_t << "</td>"; 00719 } 00720 00721 void HtmlDocVisitor::visitPre(DocHtmlCaption *c) 00722 { 00723 if (m_hide) return; 00724 bool hasAlign = FALSE; 00725 HtmlAttribListIterator li(c->attribs()); 00726 HtmlAttrib *att; 00727 for (li.toFirst();(att=li.current());++li) 00728 { 00729 if (att->name=="align") hasAlign=TRUE; 00730 } 00731 m_t << "<caption" << htmlAttribsToString(c->attribs()); 00732 if (!hasAlign) m_t << " align=\"bottom\""; 00733 m_t << ">"; 00734 } 00735 00736 void HtmlDocVisitor::visitPost(DocHtmlCaption *) 00737 { 00738 if (m_hide) return; 00739 m_t << "</caption>\n"; 00740 } 00741 00742 void HtmlDocVisitor::visitPre(DocInternal *) 00743 { 00744 if (m_hide) return; 00745 m_t << "<p><b>" << theTranslator->trForInternalUseOnly() << "</b></p>" << endl; 00746 m_t << "<p>" << endl; 00747 } 00748 00749 void HtmlDocVisitor::visitPost(DocInternal *) 00750 { 00751 if (m_hide) return; 00752 m_t << "</p>" << endl; 00753 } 00754 00755 void HtmlDocVisitor::visitPre(DocHRef *href) 00756 { 00757 if (m_hide) return; 00758 m_t << "<a href=\"" << href->url() << "\"" 00759 << htmlAttribsToString(href->attribs()) << ">"; 00760 } 00761 00762 void HtmlDocVisitor::visitPost(DocHRef *) 00763 { 00764 if (m_hide) return; 00765 m_t << "</a>"; 00766 } 00767 00768 void HtmlDocVisitor::visitPre(DocHtmlHeader *header) 00769 { 00770 if (m_hide) return; 00771 m_t << "<h" << header->level() 00772 << htmlAttribsToString(header->attribs()) << ">"; 00773 } 00774 00775 void HtmlDocVisitor::visitPost(DocHtmlHeader *header) 00776 { 00777 if (m_hide) return; 00778 m_t << "</h" << header->level() << ">\n"; 00779 } 00780 00781 void HtmlDocVisitor::visitPre(DocImage *img) 00782 { 00783 if (img->type()==DocImage::Html) 00784 { 00785 if (m_hide) return; 00786 QString baseName=img->name(); 00787 int i; 00788 if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1) 00789 { 00790 baseName=baseName.right(baseName.length()-i-1); 00791 } 00792 m_t << "<div align=\"center\">" << endl; 00793 m_t << "<img src=\"" << img->relPath() << img->name() << "\" alt=\"" 00794 << baseName << "\"" << ">" << endl; 00795 if (img->hasCaption()) 00796 { 00797 m_t << "<p><strong>"; 00798 } 00799 } 00800 else // other format -> skip 00801 { 00802 pushEnabled(); 00803 m_hide=TRUE; 00804 } 00805 } 00806 00807 void HtmlDocVisitor::visitPost(DocImage *img) 00808 { 00809 if (img->type()==DocImage::Html) 00810 { 00811 if (m_hide) return; 00812 if (img->hasCaption()) 00813 { 00814 m_t << "</strong></p>"; 00815 } 00816 m_t << "</div>" << endl; 00817 } 00818 else // other format 00819 { 00820 popEnabled(); 00821 } 00822 } 00823 00824 void HtmlDocVisitor::visitPre(DocDotFile *df) 00825 { 00826 if (m_hide) return; 00827 writeDotFile(df->file(),df->relPath(),df->context()); 00828 m_t << "<div align=\"center\">" << endl; 00829 if (df->hasCaption()) 00830 { 00831 m_t << "<p><strong>"; 00832 } 00833 } 00834 00835 void HtmlDocVisitor::visitPost(DocDotFile *df) 00836 { 00837 if (m_hide) return; 00838 if (df->hasCaption()) 00839 { 00840 m_t << "</strong></p>" << endl; 00841 } 00842 m_t << "</div>" << endl; 00843 } 00844 00845 void HtmlDocVisitor::visitPre(DocLink *lnk) 00846 { 00847 if (m_hide) return; 00848 startLink(lnk->ref(),lnk->file(),lnk->relPath(),lnk->anchor()); 00849 } 00850 00851 void HtmlDocVisitor::visitPost(DocLink *) 00852 { 00853 if (m_hide) return; 00854 endLink(); 00855 } 00856 00857 void HtmlDocVisitor::visitPre(DocRef *ref) 00858 { 00859 if (m_hide) return; 00860 if (!ref->file().isEmpty()) 00861 { 00862 startLink(ref->ref(),ref->file(),ref->relPath(),ref->anchor()); 00863 } 00864 if (!ref->hasLinkText()) filter(ref->targetTitle()); 00865 } 00866 00867 void HtmlDocVisitor::visitPost(DocRef *ref) 00868 { 00869 if (m_hide) return; 00870 if (!ref->file().isEmpty()) endLink(); 00871 //m_t << " "; 00872 } 00873 00874 void HtmlDocVisitor::visitPre(DocSecRefItem *ref) 00875 { 00876 if (m_hide) return; 00877 QString refName=ref->file(); 00878 if (refName.right(Doxygen::htmlFileExtension.length())!= 00879 QString(Doxygen::htmlFileExtension)) 00880 { 00881 refName+=Doxygen::htmlFileExtension; 00882 } 00883 m_t << "<li><a href=\"" << refName << "#" << ref->anchor() << "\">"; 00884 00885 } 00886 00887 void HtmlDocVisitor::visitPost(DocSecRefItem *) 00888 { 00889 if (m_hide) return; 00890 m_t << "</a> "; 00891 } 00892 00893 void HtmlDocVisitor::visitPre(DocSecRefList *) 00894 { 00895 if (m_hide) return; 00896 m_t << "<multicol cols=3>" << endl; 00897 m_t << "<ul>" << endl; 00898 } 00899 00900 void HtmlDocVisitor::visitPost(DocSecRefList *) 00901 { 00902 if (m_hide) return; 00903 m_t << "</ul>" << endl; 00904 m_t << "</multicol>" << endl; 00905 } 00906 00907 //void HtmlDocVisitor::visitPre(DocLanguage *l) 00908 //{ 00909 // QString langId = Config_getEnum("OUTPUT_LANGUAGE"); 00910 // if (l->id().lower()!=langId.lower()) 00911 // { 00912 // pushEnabled(); 00913 // m_hide = TRUE; 00914 // } 00915 //} 00916 // 00917 //void HtmlDocVisitor::visitPost(DocLanguage *l) 00918 //{ 00919 // QString langId = Config_getEnum("OUTPUT_LANGUAGE"); 00920 // if (l->id().lower()!=langId.lower()) 00921 // { 00922 // popEnabled(); 00923 // } 00924 //} 00925 00926 void HtmlDocVisitor::visitPre(DocParamSect *s) 00927 { 00928 if (m_hide) return; 00929 m_t << "<dl compact><dt><b>"; 00930 switch(s->type()) 00931 { 00932 case DocParamSect::Param: 00933 m_t << theTranslator->trParameters(); break; 00934 case DocParamSect::RetVal: 00935 m_t << theTranslator->trReturnValues(); break; 00936 case DocParamSect::Exception: 00937 m_t << theTranslator->trExceptions(); break; 00938 case DocParamSect::TemplateParam: 00939 /* TODO: add this 00940 m_t << theTranslator->trTemplateParam(); break; 00941 */ 00942 m_t << "Template Parameters"; break; 00943 default: 00944 ASSERT(0); 00945 } 00946 m_t << ":"; 00947 m_t << "</b></dt><dd>" << endl; 00948 m_t << " <table border=\"0\" cellspacing=\"2\" cellpadding=\"0\">" << endl; 00949 } 00950 00951 void HtmlDocVisitor::visitPost(DocParamSect *) 00952 { 00953 if (m_hide) return; 00954 m_t << " </table>" << endl; 00955 m_t << "</dl>" << endl; 00956 } 00957 00958 void HtmlDocVisitor::visitPre(DocParamList *pl) 00959 { 00960 if (m_hide) return; 00961 m_t << " <tr><td valign=\"top\">"; 00962 if (pl->direction()!=DocParamSect::Unspecified) 00963 { 00964 m_t << "<tt>["; 00965 if (pl->direction()==DocParamSect::In) 00966 { 00967 m_t << "in"; 00968 } 00969 else if (pl->direction()==DocParamSect::Out) 00970 { 00971 m_t << "out"; 00972 } 00973 else if (pl->direction()==DocParamSect::InOut) 00974 { 00975 m_t << "in,out"; 00976 } 00977 m_t << "]</tt> "; 00978 } 00979 m_t << "</td><td valign=\"top\"><em>"; 00980 //QStrListIterator li(pl->parameters()); 00981 //const char *s; 00982 QListIterator<DocNode> li(pl->parameters()); 00983 DocNode *param; 00984 bool first=TRUE; 00985 for (li.toFirst();(param=li.current());++li) 00986 { 00987 if (!first) m_t << ","; else first=FALSE; 00988 if (param->kind()==DocNode::Kind_Word) 00989 { 00990 visit((DocWord*)param); 00991 } 00992 else if (param->kind()==DocNode::Kind_LinkedWord) 00993 { 00994 visit((DocLinkedWord*)param); 00995 } 00996 } 00997 m_t << "</em> </td><td>"; 00998 } 00999 01000 void HtmlDocVisitor::visitPost(DocParamList *) 01001 { 01002 if (m_hide) return; 01003 m_t << "</td></tr>" << endl; 01004 } 01005 01006 void HtmlDocVisitor::visitPre(DocXRefItem *x) 01007 { 01008 if (m_hide) return; 01009 bool anonymousEnum = x->file()=="@"; 01010 if (!anonymousEnum) 01011 { 01012 m_t << "<dl compact><dt><b><a class=\"el\" href=\"" 01013 << x->relPath() << x->file() << Doxygen::htmlFileExtension 01014 << "#" << x->anchor() << "\">"; 01015 } 01016 else 01017 { 01018 m_t << "<dl compact><dt><b>"; 01019 } 01020 filter(x->title()); 01021 m_t << ":"; 01022 if (!anonymousEnum) m_t << "</a>"; 01023 m_t << "</b></dt><dd>"; 01024 } 01025 01026 void HtmlDocVisitor::visitPost(DocXRefItem *) 01027 { 01028 if (m_hide) return; 01029 m_t << "</dd></dl>" << endl; 01030 } 01031 01032 void HtmlDocVisitor::visitPre(DocInternalRef *ref) 01033 { 01034 if (m_hide) return; 01035 startLink(0,ref->file(),ref->relPath(),ref->anchor()); 01036 } 01037 01038 void HtmlDocVisitor::visitPost(DocInternalRef *) 01039 { 01040 if (m_hide) return; 01041 endLink(); 01042 m_t << " "; 01043 } 01044 01045 void HtmlDocVisitor::visitPre(DocCopy *) 01046 { 01047 } 01048 01049 void HtmlDocVisitor::visitPost(DocCopy *) 01050 { 01051 } 01052 01053 void HtmlDocVisitor::visitPre(DocText *) 01054 { 01055 } 01056 01057 void HtmlDocVisitor::visitPost(DocText *) 01058 { 01059 } 01060 01061 void HtmlDocVisitor::filter(const char *str) 01062 { 01063 if (str==0) return; 01064 const char *p=str; 01065 char c; 01066 while (*p) 01067 { 01068 c=*p++; 01069 switch(c) 01070 { 01071 case '<': m_t << "<"; break; 01072 case '>': m_t << ">"; break; 01073 case '&': m_t << "&"; break; 01074 default: m_t << c; 01075 } 01076 } 01077 } 01078 01081 void HtmlDocVisitor::filterQuotedCdataAttr(const char* str) 01082 { 01083 if (str==0) return; 01084 const char *p=str; 01085 char c; 01086 while (*p) 01087 { 01088 c=*p++; 01089 switch(c) 01090 { 01091 case '&': m_t << "&"; break; 01092 case '"': m_t << """; break; 01093 // For SGML compliance, and given the SGML declaration for HTML syntax, 01094 // it's enough to replace these two, provided that the declaration 01095 // for the HTML version we generate (and as supported by the browser) 01096 // specifies that all the other symbols used in rawVal are 01097 // within the right charachter class (i.e., they're not 01098 // some multinational weird charachters not in the BASESET). 01099 // We assume that 1) the browser will support whatever is remaining 01100 // in the formula and 2) the TeX formulae are generally governed 01101 // by even stricter charachter restrictions so it should be enough. 01102 // 01103 // On some incompliant browsers, additional translation of 01104 // '>' and '<' into ">" and "<", respectively, might be needed; 01105 // but I'm unaware of particular modern (last 4 years) versions 01106 // with such problems, so let's not do it for performance. 01107 // Also, some brousers will (wrongly) not process the entity references 01108 // inside the attribute value and show the &...; form instead, 01109 // so we won't create entites unless necessary to minimize clutter there. 01110 // --vassilii 01111 default: m_t << c; 01112 } 01113 } 01114 } 01115 01116 void HtmlDocVisitor::startLink(const QString &ref,const QString &file, 01117 const QString &relPath,const QString &anchor, 01118 const QString &tooltip) 01119 { 01120 QCString *dest; 01121 if (!ref.isEmpty()) // link to entity imported via tag file 01122 { 01123 m_t << "<a class=\"elRef\" "; 01124 m_t << "doxygen=\"" << ref << ":"; 01125 if ((dest=Doxygen::tagDestinationDict[ref])) m_t << *dest << "/"; 01126 m_t << "\" "; 01127 } 01128 else // local link 01129 { 01130 m_t << "<a class=\"el\" "; 01131 } 01132 m_t << "href=\""; 01133 if (!ref.isEmpty()) 01134 { 01135 if ((dest=Doxygen::tagDestinationDict[ref])) m_t << *dest << "/"; 01136 } 01137 else 01138 { 01139 m_t << relPath; 01140 } 01141 if (!file.isEmpty()) m_t << file << Doxygen::htmlFileExtension; 01142 if (!anchor.isEmpty()) m_t << "#" << anchor; 01143 m_t << "\""; 01144 if (!tooltip.isEmpty()) m_t << " title=\"" << tooltip << "\""; 01145 m_t << ">"; 01146 } 01147 01148 void HtmlDocVisitor::endLink() 01149 { 01150 m_t << "</a>"; 01151 } 01152 01153 void HtmlDocVisitor::pushEnabled() 01154 { 01155 m_enabled.push(new bool(m_hide)); 01156 } 01157 01158 void HtmlDocVisitor::popEnabled() 01159 { 01160 bool *v=m_enabled.pop(); 01161 ASSERT(v!=0); 01162 m_hide = *v; 01163 delete v; 01164 } 01165 01166 void HtmlDocVisitor::writeDotFile(const QString &fileName,const QString &relPath, 01167 const QString &context) 01168 { 01169 QString baseName=fileName; 01170 int i; 01171 if ((i=baseName.findRev('/'))!=-1) 01172 { 01173 baseName=baseName.right(baseName.length()-i-1); 01174 } 01175 QString outDir = Config_getString("HTML_OUTPUT"); 01176 writeDotGraphFromFile(fileName,outDir,baseName,BITMAP); 01177 QString mapName = baseName+".map"; 01178 QString mapFile = fileName+".map"; 01179 m_t << "<img src=\"" << relPath << baseName << "." 01180 << Config_getEnum("DOT_IMAGE_FORMAT") << "\" alt=\"" 01181 << baseName << "\" border=\"0\" usemap=\"#" << mapName << "\">" << endl; 01182 QString imap = getDotImageMapFromFile(fileName,outDir,relPath.data(),context); 01183 m_t << "<map name=\"" << mapName << "\">" << imap << "</map>" << endl; 01184 } 01185 01186 void HtmlDocVisitor::writeMscFile(const QString &fileName,const QString &relPath, 01187 const QString &context) 01188 { 01189 QString baseName=fileName; 01190 int i; 01191 if ((i=baseName.findRev('/'))!=-1) 01192 { 01193 baseName=baseName.right(baseName.length()-i-1); 01194 } 01195 QString outDir = Config_getString("HTML_OUTPUT"); 01196 writeMscGraphFromFile(fileName,outDir,baseName,MSC_BITMAP); 01197 QString mapName = baseName+".map"; 01198 QString mapFile = fileName+".map"; 01199 m_t << "<img src=\"" << relPath << baseName << ".png\" alt=\"" 01200 << baseName << "\" border=\"0\" usemap=\"#" << mapName << "\">" << endl; 01201 QString imap = getMscImageMapFromFile(fileName,outDir,relPath.data(),context); 01202 m_t << "<map name=\"" << mapName << "\">" << imap << "</map>" << endl; 01203 } 01204