Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/htmldocvisitor.cpp

Source at commit 1322 created 9 years 5 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 * $Id: $
4 *
5 *
6 * Copyright (C) 1997-2011 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 "util.h"
32
33
34static const int NUM_HTML_LIST_TYPES = 4;
35static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
36
37static QCString convertIndexWordToAnchor(const QString &word)
38{
39 static char hex[] = "0123456789abcdef";
40 uint i;
41 QCString result;
42 for (i=0;i<word.length();i++)
43 {
44 int c = word.at(i);
45 if (isId(c))
46 {
47 result+=c;
48 }
49 else if (isspace(c))
50 {
51 result+="_";
52 }
53 else
54 {
55 char cs[3];
56 cs[0]=hex[c>>4];
57 cs[1]=hex[c&0xf];
58 cs[2]=0;
59 result+=cs;
60 }
61 }
62 return result;
63}
64
65static bool mustBeOutsideParagraph(DocNode *n)
66{
67 switch (n->kind())
68 {
69 /* <ul> */
70 case DocNode::Kind_HtmlList:
71 case DocNode::Kind_SimpleList:
72 case DocNode::Kind_AutoList:
73 /* <dl> */
74 case DocNode::Kind_SimpleSect:
75 case DocNode::Kind_ParamSect:
76 case DocNode::Kind_HtmlDescList:
77 case DocNode::Kind_XRefItem:
78 /* <table> */
79 case DocNode::Kind_HtmlTable:
80 /* <h?> */
81 case DocNode::Kind_Section:
82 case DocNode::Kind_HtmlHeader:
83 /* \internal */
84 case DocNode::Kind_Internal:
85 /* <div> */
86 case DocNode::Kind_Verbatim:
87 case DocNode::Kind_Include:
88 case DocNode::Kind_Image:
89 case DocNode::Kind_SecRefList:
90 /* <hr> */
91 case DocNode::Kind_HorRuler:
92 /* CopyDoc gets paragraph markers from the wrapping DocPara node,
93 * but needs to insert them for all documentation being copied to
94 * preserve formatting.
95 */
96 case DocNode::Kind_Copy:
97 return TRUE;
98 case DocNode::Kind_StyleChange:
99 return ((DocStyleChange*)n)->style()==DocStyleChange::Preformatted ||
100 ((DocStyleChange*)n)->style()==DocStyleChange::Div ||
101 ((DocStyleChange*)n)->style()==DocStyleChange::Center;
102 case DocNode::Kind_Formula:
103 return !((DocFormula*)n)->isInline();
104 default:
105 break;
106 }
107 return FALSE;
108}
109
110
111
112static QString htmlAttribsToString(const HtmlAttribList &attribs)
113{
114 QString result;
115 HtmlAttribListIterator li(attribs);
116 HtmlAttrib *att;
117 for (li.toFirst();(att=li.current());++li)
118 {
119 if (!att->value.isEmpty()) // ignore attribute without values as they
120 // are not XHTML compliant
121 {
122 result+=" ";
123 result+=att->name;
124 result+="=\""+convertToXML(att->value)+"\"";
125 }
126 }
127 return result;
128}
129
130//-------------------------------------------------------------------------
131
132HtmlDocVisitor::HtmlDocVisitor(FTextStream &t,CodeOutputInterface &ci,
133 const char *langExt)
134 : DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE),
135 m_hide(FALSE), m_langExt(langExt)
136{
137}
138
139 //--------------------------------------
140 // visitor functions for leaf nodes
141 //--------------------------------------
142
143void HtmlDocVisitor::visit(DocWord *w)
144{
145 //printf("word: %s\n",w->word().data());
146 if (m_hide) return;
147 filter(w->word());
148}
149
150void HtmlDocVisitor::visit(DocLinkedWord *w)
151{
152 if (m_hide) return;
153 startLink(w->ref(),w->file(),w->relPath(),w->anchor(),w->tooltip());
154 filter(w->word());
155 endLink();
156}
157
158void HtmlDocVisitor::visit(DocWhiteSpace *w)
159{
160 if (m_hide) return;
161 if (m_insidePre)
162 {
163 m_t << w->chars();
164 }
165 else
166 {
167 m_t << " ";
168 }
169}
170
171void HtmlDocVisitor::visit(DocSymbol *s)
172{
173 if (m_hide) return;
174 switch(s->symbol())
175 {
176 case DocSymbol::BSlash: m_t << "\\"; break;
177 case DocSymbol::At: m_t << "@"; break;
178 case DocSymbol::Less: m_t << "&lt;"; break;
179 case DocSymbol::Greater: m_t << "&gt;"; break;
180 case DocSymbol::Amp: m_t << "&amp;"; break;
181 case DocSymbol::Dollar: m_t << "$"; break;
182 case DocSymbol::Hash: m_t << "#"; break;
183 case DocSymbol::DoubleColon: m_t << "::"; break;
184 case DocSymbol::Percent: m_t << "%"; break;
185 case DocSymbol::Copy: m_t << "&copy;"; break;
186 case DocSymbol::Tm: m_t << "&trade;"; break;
187 case DocSymbol::Reg: m_t << "&reg;"; break;
188 case DocSymbol::Apos: m_t << "'"; break;
189 case DocSymbol::Quot: m_t << "\""; break;
190 case DocSymbol::Lsquo: m_t << "&lsquo;"; break;
191 case DocSymbol::Rsquo: m_t << "&rsquo;"; break;
192 case DocSymbol::Ldquo: m_t << "&ldquo;"; break;
193 case DocSymbol::Rdquo: m_t << "&rdquo;"; break;
194 case DocSymbol::Ndash: m_t << "&ndash;"; break;
195 case DocSymbol::Mdash: m_t << "&mdash;"; break;
196 case DocSymbol::Uml: m_t << "&" << s->letter() << "uml;"; break;
197 case DocSymbol::Acute: m_t << "&" << s->letter() << "acute;"; break;
198 case DocSymbol::Grave: m_t << "&" << s->letter() << "grave;"; break;
199 case DocSymbol::Circ: m_t << "&" << s->letter() << "circ;"; break;
200 case DocSymbol::Slash: m_t << "&" << s->letter() << "slash;"; break;
201 case DocSymbol::Tilde: m_t << "&" << s->letter() << "tilde;"; break;
202 case DocSymbol::Szlig: m_t << "&szlig;"; break;
203 case DocSymbol::Cedil: m_t << "&" << s->letter() << "cedil;"; break;
204 case DocSymbol::Ring: m_t << "&" << s->letter() << "ring;"; break;
205 case DocSymbol::Nbsp: m_t << "&#160;"; break;
206 case DocSymbol::AElig: m_t << "&AElig;"; break;
207 case DocSymbol::Aelig: m_t << "&aelig;"; break;
208 default:
209 err("error: unknown symbol found\n");
210 }
211}
212
213void HtmlDocVisitor::visit(DocURL *u)
214{
215 if (m_hide) return;
216 m_t << "<a href=\"";
217 if (u->isEmail()) m_t << "mailto:";
218 m_t << u->url() << "\">";
219 filter(u->url());
220 m_t << "</a>";
221}
222
223void HtmlDocVisitor::visit(DocLineBreak *)
224{
225 if (m_hide) return;
226 m_t << "<br/>\n";
227}
228
229void HtmlDocVisitor::visit(DocHorRuler *)
230{
231 if (m_hide) return;
232 m_t << "<hr/>\n";
233}
234
235void HtmlDocVisitor::visit(DocStyleChange *s)
236{
237 if (m_hide) return;
238 switch (s->style())
239 {
240 case DocStyleChange::Bold:
241 if (s->enable()) m_t << "<b" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</b>";
242 break;
243 case DocStyleChange::Italic:
244 if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>";
245 break;
246 case DocStyleChange::Code:
247 if (s->enable()) m_t << "<code" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</code>";
248 break;
249 case DocStyleChange::Subscript:
250 if (s->enable()) m_t << "<sub" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sub>";
251 break;
252 case DocStyleChange::Superscript:
253 if (s->enable()) m_t << "<sup" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</sup>";
254 break;
255 case DocStyleChange::Center:
256 if (s->enable())
257 {
258 forceEndParagraph(s);
259 m_t << "<center" << htmlAttribsToString(s->attribs()) << ">";
260 }
261 else
262 {
263 m_t << "</center>";
264 forceStartParagraph(s);
265 }
266 break;
267 case DocStyleChange::Small:
268 if (s->enable()) m_t << "<small" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</small>";
269 break;
270 case DocStyleChange::Preformatted:
271 if (s->enable())
272 {
273 forceEndParagraph(s);
274 m_t << "<pre" << htmlAttribsToString(s->attribs()) << ">";
275 m_insidePre=TRUE;
276 }
277 else
278 {
279 m_insidePre=FALSE;
280 m_t << "</pre>";
281 forceStartParagraph(s);
282 }
283 break;
284 case DocStyleChange::Div:
285 if (s->enable())
286 {
287 forceEndParagraph(s);
288 m_t << "<div" << htmlAttribsToString(s->attribs()) << ">";
289 }
290 else
291 {
292 m_t << "</div>";
293 forceStartParagraph(s);
294 }
295 break;
296 case DocStyleChange::Span:
297 if (s->enable()) m_t << "<span" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</span>";
298 break;
299
300 }
301}
302
303
304void HtmlDocVisitor::visit(DocVerbatim *s)
305{
306 if (m_hide) return;
307 switch(s->type())
308 {
309 case DocVerbatim::Code:
310 forceEndParagraph(s);
311 m_t << PREFRAG_START;
312 Doxygen::parserManager->getParser(m_langExt)
313 ->parseCode(m_ci,s->context(),s->text(),
314 s->isExample(),s->exampleFile());
315 m_t << PREFRAG_END;
316 forceStartParagraph(s);
317 break;
318 case DocVerbatim::Verbatim:
319 forceEndParagraph(s);
320 m_t << PREFRAG_START;
321 filter(s->text());
322 m_t << PREFRAG_END;
323 forceStartParagraph(s);
324 break;
325 case DocVerbatim::HtmlOnly:
326 m_t << s->text();
327 break;
328 case DocVerbatim::ManOnly:
329 case DocVerbatim::LatexOnly:
330 case DocVerbatim::XmlOnly:
331 /* nothing */
332 break;
333
334 case DocVerbatim::Dot:
335 {
336 static int dotindex = 1;
337 QCString fileName(4096);
338
339 fileName.sprintf("%s%d%s",
340 (Config_getString("HTML_OUTPUT")+"/inline_dotgraph_").data(),
341 dotindex++,
342 ".dot"
343 );
344 QFile file(fileName);
345 if (!file.open(IO_WriteOnly))
346 {
347 err("Could not open file %s for writing\n",fileName.data());
348 }
349 file.writeBlock( s->text(), s->text().length() );
350 file.close();
351
352 forceEndParagraph(s);
353 m_t << "<div align=\"center\">" << endl;
354 writeDotFile(fileName,s->relPath(),s->context());
355 m_t << "</div>" << endl;
356 forceStartParagraph(s);
357
358 if (Config_getBool("DOT_CLEANUP")) file.remove();
359 }
360 break;
361 case DocVerbatim::Msc:
362 {
363 static int mscindex = 1;
364 QCString baseName(4096);
365
366 baseName.sprintf("%s%d",
367 (Config_getString("HTML_OUTPUT")+"/inline_mscgraph_").data(),
368 mscindex++
369 );
370 QFile file(baseName+".msc");
371 if (!file.open(IO_WriteOnly))
372 {
373 err("Could not open file %s.msc for writing\n",baseName.data());
374 }
375 QCString text = "msc {";
376 text+=s->text();
377 text+="}";
378 file.writeBlock( text, text.length() );
379 file.close();
380
381 forceEndParagraph(s);
382 m_t << "<div align=\"center\">" << endl;
383 writeMscFile(baseName+".msc",s->relPath(),s->context());
384 m_t << "</div>" << endl;
385 forceStartParagraph(s);
386
387 if (Config_getBool("DOT_CLEANUP")) file.remove();
388 }
389 break;
390 }
391}
392
393void HtmlDocVisitor::visit(DocAnchor *anc)
394{
395 if (m_hide) return;
396 m_t << "<a class=\"anchor\" id=\"" << anc->anchor() << "\"></a>";
397}
398
399void HtmlDocVisitor::visit(DocInclude *inc)
400{
401 if (m_hide) return;
402 switch(inc->type())
403 {
404 case DocInclude::Include:
405 forceEndParagraph(inc);
406 m_t << PREFRAG_START;
407 Doxygen::parserManager->getParser(inc->extension())
408 ->parseCode(m_ci,
409 inc->context(),
410 inc->text(),
411 inc->isExample(),
412 inc->exampleFile(),
413 0, // fd
414 -1, // startLine
415 -1, // endLine
416 TRUE // inlineFragment
417 );
418 m_t << PREFRAG_END;
419 forceStartParagraph(inc);
420 break;
421 case DocInclude::IncWithLines:
422 {
423 forceEndParagraph(inc);
424 m_t << PREFRAG_START;
425 QFileInfo cfi( inc->file() );
426 FileDef fd( cfi.dirPath(), cfi.fileName() );
427 Doxygen::parserManager->getParser(inc->extension())
428 ->parseCode(m_ci,
429 inc->context(),
430 inc->text(),
431 inc->isExample(),
432 inc->exampleFile(), &fd);
433 m_t << PREFRAG_END;
434 forceStartParagraph(inc);
435 }
436 break;
437 case DocInclude::DontInclude:
438 break;
439 case DocInclude::HtmlInclude:
440 m_t << inc->text();
441 break;
442 case DocInclude::VerbInclude:
443 forceEndParagraph(inc);
444 m_t << PREFRAG_START;
445 filter(inc->text());
446 m_t << PREFRAG_END;
447 forceStartParagraph(inc);
448 break;
449 }
450}
451
452void HtmlDocVisitor::visit(DocIncOperator *op)
453{
454 //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
455 // op->type(),op->isFirst(),op->isLast(),op->text().data());
456 if (op->isFirst())
457 {
458 if (!m_hide) m_t << PREFRAG_START;
459 pushEnabled();
460 m_hide=TRUE;
461 }
462 if (op->type()!=DocIncOperator::Skip)
463 {
464 popEnabled();
465 if (!m_hide)
466 {
467 Doxygen::parserManager->getParser(m_langExt)
468 ->parseCode(m_ci,op->context(),
469 op->text(),op->isExample(),
470 op->exampleFile());
471 }
472 pushEnabled();
473 m_hide=TRUE;
474 }
475 if (op->isLast())
476 {
477 popEnabled();
478 if (!m_hide) m_t << PREFRAG_END;
479 }
480 else
481 {
482 if (!m_hide) m_t << endl;
483 }
484}
485
486void HtmlDocVisitor::visit(DocFormula *f)
487{
488 if (m_hide) return;
489 bool bDisplay = !f->isInline();
490 if (bDisplay)
491 {
492 forceEndParagraph(f);
493 m_t << "<p class=\"formulaDsp\">" << endl;
494 }
495
496 if (Config_getBool("USE_MATHJAX"))
497 {
498 QCString text = f->text();
499 bool closeInline = FALSE;
500 if (!bDisplay && !text.isEmpty() && text.at(0)=='$' &&
501 text.at(text.length()-1)=='$')
502 {
503 closeInline=TRUE;
504 text = text.mid(1,text.length()-2);
505 m_t << "\\(";
506 }
507 m_t << convertToHtml(text);
508 if (closeInline)
509 {
510 m_t << "\\)";
511 }
512 }
513 else
514 {
515 m_t << "<img class=\"formula"
516 << (bDisplay ? "Dsp" : "Inl");
517 m_t << "\" alt=\"";
518 filterQuotedCdataAttr(f->text());
519 m_t << "\"";
520 /// @todo cache image dimensions on formula generation and give height/width
521 /// for faster preloading and better rendering of the page
522 m_t << " src=\"" << f->relPath() << f->name() << ".png\"/>";
523
524 }
525 if (bDisplay)
526 {
527 m_t << endl << "</p>" << endl;
528 forceStartParagraph(f);
529 }
530}
531
532void HtmlDocVisitor::visit(DocIndexEntry *e)
533{
534 QCString anchor = convertIndexWordToAnchor(e->entry());
535 if (e->member())
536 {
537 anchor.prepend(e->member()->anchor()+"_");
538 }
539 m_t << "<a name=\"" << anchor << "\"></a>";
540 //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n",
541 // e->entry().data(),
542 // e->scope() ? e->scope()->name().data() : "<null>",
543 // e->member() ? e->member()->name().data() : "<null>"
544 // );
545 Doxygen::indexList.addIndexItem(e->scope(),e->member(),e->entry());
546}
547
548void HtmlDocVisitor::visit(DocSimpleSectSep *)
549{
550 m_t << "</dd>" << endl;
551 m_t << "<dd>" << endl;
552}
553
554//--------------------------------------
555// visitor functions for compound nodes
556//--------------------------------------
557
558
559void HtmlDocVisitor::visitPre(DocAutoList *l)
560{
561 //printf("DocAutoList::visitPre\n");
562 if (m_hide) return;
563 forceEndParagraph(l);
564 if (l->isEnumList())
565 {
566 //
567 // Do list type based on depth:
568 // 1.
569 // a.
570 // i.
571 // A.
572 // 1. (repeat)...
573 //
574 m_t << "<ol type=\"" << types[l->depth() % NUM_HTML_LIST_TYPES] << "\">";
575 }
576 else
577 {
578 m_t << "<ul>";
579 }
580 if (!l->isPreformatted()) m_t << "\n";
581}
582
583void HtmlDocVisitor::visitPost(DocAutoList *l)
584{
585 //printf("DocAutoList::visitPost\n");
586 if (m_hide) return;
587 if (l->isEnumList())
588 {
589 m_t << "</ol>";
590 }
591 else
592 {
593 m_t << "</ul>";
594 }
595 if (!l->isPreformatted()) m_t << "\n";
596 forceStartParagraph(l);
597}
598
599void HtmlDocVisitor::visitPre(DocAutoListItem *)
600{
601 if (m_hide) return;
602 m_t << "<li>";
603}
604
605void HtmlDocVisitor::visitPost(DocAutoListItem *li)
606{
607 if (m_hide) return;
608 m_t << "</li>";
609 if (!li->isPreformatted()) m_t << "\n";
610}
611
612template<class T>
613bool isFirstChildNode(T *parent, DocNode *node)
614{
615 return parent->children().getFirst()==node;
616}
617
618template<class T>
619bool isLastChildNode(T *parent, DocNode *node)
620{
621 return parent->children().getLast()==node;
622}
623
624bool isSeparatedParagraph(DocSimpleSect *parent,DocPara *par)
625{
626 QList<DocNode> nodes = parent->children();
627 int i = nodes.findRef(par);
628 if (i==-1) return FALSE;
629 int count = parent->children().count();
630 if (count>1 && i==0)
631 {
632 if (nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
633 {
634 return TRUE;
635 }
636 }
637 else if (count>1 && i==count-1)
638 {
639 if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep)
640 {
641 return TRUE;
642 }
643 }
644 else if (count>2 && i>0 && i<count-1)
645 {
646 if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep &&
647 nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep)
648 {
649 return TRUE;
650 }
651 }
652 return FALSE;
653}
654
655static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
656{
657 int t=0;
658 isFirst=FALSE;
659 isLast=FALSE;
660 if (p && p->parent())
661 {
662 switch (p->parent()->kind())
663 {
664 case DocNode::Kind_AutoListItem:
665 isFirst=TRUE;
666 isLast =TRUE;
667 t=1; // not used
668 break;
669 case DocNode::Kind_SimpleListItem:
670 isFirst=TRUE;
671 isLast =TRUE;
672 t=1; // not used
673 break;
674 case DocNode::Kind_ParamList:
675 isFirst=TRUE;
676 isLast =TRUE;
677 t=1; // not used
678 break;
679 case DocNode::Kind_HtmlListItem:
680 isFirst=isFirstChildNode((DocHtmlListItem*)p->parent(),p);
681 isLast =isLastChildNode ((DocHtmlListItem*)p->parent(),p);
682 if (isFirst) t=1;
683 if (isLast) t=3;
684 break;
685 case DocNode::Kind_SecRefItem:
686 isFirst=isFirstChildNode((DocSecRefItem*)p->parent(),p);
687 isLast =isLastChildNode ((DocSecRefItem*)p->parent(),p);
688 if (isFirst) t=1;
689 if (isLast) t=3;
690 break;
691 case DocNode::Kind_HtmlDescData:
692 isFirst=isFirstChildNode((DocHtmlDescData*)p->parent(),p);
693 isLast =isLastChildNode ((DocHtmlDescData*)p->parent(),p);
694 if (isFirst) t=2;
695 if (isLast) t=4;
696 break;
697 case DocNode::Kind_XRefItem:
698 isFirst=isFirstChildNode((DocXRefItem*)p->parent(),p);
699 isLast =isLastChildNode ((DocXRefItem*)p->parent(),p);
700 if (isFirst) t=2;
701 if (isLast) t=4;
702 break;
703 case DocNode::Kind_HtmlCell:
704 isFirst=isFirstChildNode((DocHtmlCell*)p->parent(),p);
705 isLast =isLastChildNode ((DocHtmlCell*)p->parent(),p);
706 if (isFirst) t=5;
707 if (isLast) t=6;
708 break;
709 case DocNode::Kind_SimpleSect:
710 isFirst=isFirstChildNode((DocSimpleSect*)p->parent(),p);
711 isLast =isLastChildNode ((DocSimpleSect*)p->parent(),p);
712 if (isFirst) t=2;
713 if (isLast) t=4;
714 if (isSeparatedParagraph((DocSimpleSect*)p->parent(),p))
715 // if the paragraph is enclosed with separators it will
716 // be included in <dd>..</dd> so avoid addition paragraph
717 // markers
718 {
719 isFirst=isLast=TRUE;
720 }
721 break;
722 default:
723 break;
724 }
725 //printf("para=%p parent()->kind=%d isFirst=%d isLast=%d t=%d\n",
726 // p,p->parent()->kind(),isFirst,isLast,t);
727 }
728 return t;
729}
730
731void HtmlDocVisitor::visitPre(DocPara *p)
732{
733 if (m_hide) return;
734
735 //printf("DocPara::visitPre: parent of kind %d ",
736 // p->parent() ? p->parent()->kind() : -1);
737
738 bool needsTag = FALSE;
739 if (p && p->parent())
740 {
741 switch (p->parent()->kind())
742 {
743 case DocNode::Kind_Section:
744 case DocNode::Kind_Internal:
745 case DocNode::Kind_HtmlListItem:
746 case DocNode::Kind_HtmlDescData:
747 case DocNode::Kind_HtmlCell:
748 case DocNode::Kind_SimpleListItem:
749 case DocNode::Kind_AutoListItem:
750 case DocNode::Kind_SimpleSect:
751 case DocNode::Kind_XRefItem:
752 case DocNode::Kind_Copy:
753 needsTag = TRUE;
754 break;
755 case DocNode::Kind_Root:
756 needsTag = !((DocRoot*)p->parent())->singleLine();
757 break;
758 default:
759 needsTag = FALSE;
760 }
761 }
762
763 // if the first element of a paragraph is something that should be outside of
764 // the paragraph (<ul>,<dl>,<table>,..) then that will already started the
765 // paragraph and we don't need to do it here
766 uint nodeIndex = 0;
767 if (p && nodeIndex<p->children().count())
768 {
769 while (nodeIndex<p->children().count() &&
770 p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace)
771 {
772 nodeIndex++;
773 }
774 if (nodeIndex<p->children().count())
775 {
776 DocNode *n = p->children().at(nodeIndex);
777 if (mustBeOutsideParagraph(n))
778 {
779 needsTag = FALSE;
780 }
781 }
782 }
783
784 // check if this paragraph is the first or last child of a <li> or <dd>.
785 // this allows us to mark the tag with a special class so we can
786 // fix the otherwise ugly spacing.
787 int t;
788 static const char *contexts[7] =
789 { "", // 0
790 " class=\"startli\"", // 1
791 " class=\"startdd\"", // 2
792 " class=\"endli\"", // 3
793 " class=\"enddd\"", // 4
794 " class=\"starttd\"", // 5
795 " class=\"endtd\"" // 6
796 };
797 bool isFirst;
798 bool isLast;
799 t = getParagraphContext(p,isFirst,isLast);
800 //printf("startPara first=%d last=%d\n",isFirst,isLast);
801 if (isFirst && isLast) needsTag=FALSE;
802
803 //printf(" needsTag=%d\n",needsTag);
804 // write the paragraph tag (if needed)
805 if (needsTag) m_t << "<p" << contexts[t] << ">";
806}
807
808void HtmlDocVisitor::visitPost(DocPara *p)
809{
810// if (m_hide) return;
811// if (!p->isLast() && // omit <p> for last paragraph
812// !(p->parent() && // and for parameter sections
813// p->parent()->kind()==DocNode::Kind_ParamSect
814// )
815// )
816// {
817// m_t << "<p>\n";
818// }
819
820 bool needsTag = FALSE;
821 if (p && p->parent())
822 {
823 switch (p->parent()->kind())
824 {
825 case DocNode::Kind_Section:
826 case DocNode::Kind_Internal:
827 case DocNode::Kind_HtmlListItem:
828 case DocNode::Kind_HtmlDescData:
829 case DocNode::Kind_HtmlCell:
830 case DocNode::Kind_SimpleListItem:
831 case DocNode::Kind_AutoListItem:
832 case DocNode::Kind_SimpleSect:
833 case DocNode::Kind_XRefItem:
834 case DocNode::Kind_Copy:
835 needsTag = TRUE;
836 break;
837 case DocNode::Kind_Root:
838 needsTag = !((DocRoot*)p->parent())->singleLine();
839 break;
840 default:
841 needsTag = FALSE;
842 }
843 }
844
845 QCString context;
846 // if the last element of a paragraph is something that should be outside of
847 // the paragraph (<ul>,<dl>,<table>) then that will already have ended the
848 // paragraph and we don't need to do it here
849 int nodeIndex = p->children().count()-1;
850 if (p && nodeIndex>=0)
851 {
852 while (nodeIndex>=0 && p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace)
853 {
854 nodeIndex--;
855 }
856 if (nodeIndex>=0)
857 {
858 DocNode *n = p->children().at(nodeIndex);
859 if (mustBeOutsideParagraph(n))
860 {
861 needsTag = FALSE;
862 }
863 }
864 }
865
866 bool isFirst;
867 bool isLast;
868 getParagraphContext(p,isFirst,isLast);
869 //printf("endPara first=%d last=%d\n",isFirst,isLast);
870 if (isFirst && isLast) needsTag=FALSE;
871
872 //printf("DocPara::visitPost needsTag=%d\n",needsTag);
873
874 if (needsTag) m_t << "</p>\n";
875
876}
877
878void HtmlDocVisitor::visitPre(DocRoot *)
879{
880}
881
882void HtmlDocVisitor::visitPost(DocRoot *)
883{
884}
885
886void HtmlDocVisitor::visitPre(DocSimpleSect *s)
887{
888 if (m_hide) return;
889 forceEndParagraph(s);
890 m_t << "<dl class=\"" << s->typeString() << "\"><dt><b>";
891 switch(s->type())
892 {
893 case DocSimpleSect::See:
894 m_t << theTranslator->trSeeAlso(); break;
895 case DocSimpleSect::Return:
896 m_t << theTranslator->trReturns(); break;
897 case DocSimpleSect::Author:
898 m_t << theTranslator->trAuthor(TRUE,TRUE); break;
899 case DocSimpleSect::Authors:
900 m_t << theTranslator->trAuthor(TRUE,FALSE); break;
901 case DocSimpleSect::Version:
902 m_t << theTranslator->trVersion(); break;
903 case DocSimpleSect::Since:
904 m_t << theTranslator->trSince(); break;
905 case DocSimpleSect::Date:
906 m_t << theTranslator->trDate(); break;
907 case DocSimpleSect::Note:
908 m_t << theTranslator->trNote(); break;
909 case DocSimpleSect::Warning:
910 m_t << theTranslator->trWarning(); break;
911 case DocSimpleSect::Pre:
912 m_t << theTranslator->trPrecondition(); break;
913 case DocSimpleSect::Post:
914 m_t << theTranslator->trPostcondition(); break;
915 case DocSimpleSect::Invar:
916 m_t << theTranslator->trInvariant(); break;
917 case DocSimpleSect::Remark:
918 m_t << theTranslator->trRemarks(); break;
919 case DocSimpleSect::Attention:
920 m_t << theTranslator->trAttention(); break;
921 case DocSimpleSect::User: break;
922 case DocSimpleSect::Rcs: break;
923 case DocSimpleSect::Unknown: break;
924 }
925
926 // special case 1: user defined title
927 if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
928 {
929 m_t << ":</b></dt><dd>";
930 }
931}
932
933void HtmlDocVisitor::visitPost(DocSimpleSect *s)
934{
935 if (m_hide) return;
936 m_t << "</dd></dl>\n";
937 forceStartParagraph(s);
938}
939
940void HtmlDocVisitor::visitPre(DocTitle *)
941{
942}
943
944void HtmlDocVisitor::visitPost(DocTitle *)
945{
946 if (m_hide) return;
947 m_t << "</b></dt><dd>";
948}
949
950void HtmlDocVisitor::visitPre(DocSimpleList *sl)
951{
952 if (m_hide) return;
953 forceEndParagraph(sl);
954 m_t << "<ul>";
955 if (!sl->isPreformatted()) m_t << "\n";
956
957}
958
959void HtmlDocVisitor::visitPost(DocSimpleList *sl)
960{
961 if (m_hide) return;
962 m_t << "</ul>";
963 if (!sl->isPreformatted()) m_t << "\n";
964 forceStartParagraph(sl);
965}
966
967void HtmlDocVisitor::visitPre(DocSimpleListItem *)
968{
969 if (m_hide) return;
970 m_t << "<li>";
971}
972
973void HtmlDocVisitor::visitPost(DocSimpleListItem *li)
974{
975 if (m_hide) return;
976 m_t << "</li>";
977 if (!li->isPreformatted()) m_t << "\n";
978}
979
980void HtmlDocVisitor::visitPre(DocSection *s)
981{
982 if (m_hide) return;
983 forceEndParagraph(s);
984 m_t << "<h" << s->level()+1 << ">";
985 m_t << "<a class=\"anchor\" id=\"" << s->anchor();
986 m_t << "\"></a>" << endl;
987 filter(convertCharEntitiesToUTF8(s->title().data()));
988 m_t << "</h" << s->level()+1 << ">\n";
989}
990
991void HtmlDocVisitor::visitPost(DocSection *s)
992{
993 forceStartParagraph(s);
994}
995
996void HtmlDocVisitor::visitPre(DocHtmlList *s)
997{
998 if (m_hide) return;
999 forceEndParagraph(s);
1000 if (s->type()==DocHtmlList::Ordered)
1001 {
1002 m_t << "<ol" << htmlAttribsToString(s->attribs()) << ">\n";
1003 }
1004 else
1005 {
1006 m_t << "<ul" << htmlAttribsToString(s->attribs()) << ">\n";
1007 }
1008}
1009
1010void HtmlDocVisitor::visitPost(DocHtmlList *s)
1011{
1012 if (m_hide) return;
1013 if (s->type()==DocHtmlList::Ordered)
1014 {
1015 m_t << "</ol>";
1016 }
1017 else
1018 {
1019 m_t << "</ul>";
1020 }
1021 if (!s->isPreformatted()) m_t << "\n";
1022 forceStartParagraph(s);
1023}
1024
1025void HtmlDocVisitor::visitPre(DocHtmlListItem *i)
1026{
1027 if (m_hide) return;
1028 m_t << "<li" << htmlAttribsToString(i->attribs()) << ">";
1029 if (!i->isPreformatted()) m_t << "\n";
1030}
1031
1032void HtmlDocVisitor::visitPost(DocHtmlListItem *)
1033{
1034 if (m_hide) return;
1035 m_t << "</li>\n";
1036}
1037
1038void HtmlDocVisitor::visitPre(DocHtmlDescList *dl)
1039{
1040 if (m_hide) return;
1041 forceEndParagraph(dl);
1042 m_t << "<dl" << htmlAttribsToString(dl->attribs()) << ">\n";
1043}
1044
1045void HtmlDocVisitor::visitPost(DocHtmlDescList *dl)
1046{
1047 if (m_hide) return;
1048 m_t << "</dl>\n";
1049 forceStartParagraph(dl);
1050}
1051
1052void HtmlDocVisitor::visitPre(DocHtmlDescTitle *dt)
1053{
1054 if (m_hide) return;
1055 m_t << "<dt" << htmlAttribsToString(dt->attribs()) << ">";
1056}
1057
1058void HtmlDocVisitor::visitPost(DocHtmlDescTitle *)
1059{
1060 if (m_hide) return;
1061 m_t << "</dt>\n";
1062}
1063
1064void HtmlDocVisitor::visitPre(DocHtmlDescData *dd)
1065{
1066 if (m_hide) return;
1067 m_t << "<dd" << htmlAttribsToString(dd->attribs()) << ">";
1068}
1069
1070void HtmlDocVisitor::visitPost(DocHtmlDescData *)
1071{
1072 if (m_hide) return;
1073 m_t << "</dd>\n";
1074}
1075
1076void HtmlDocVisitor::visitPre(DocHtmlTable *t)
1077{
1078 if (m_hide) return;
1079
1080 forceEndParagraph(t);
1081
1082 QString attrs = htmlAttribsToString(t->attribs());
1083 if (attrs.isEmpty())
1084 {
1085 m_t << "<table class=\"doxtable\">\n";
1086 }
1087 else
1088 {
1089 m_t << "<table " << htmlAttribsToString(t->attribs()) << ">\n";
1090 }
1091}
1092
1093void HtmlDocVisitor::visitPost(DocHtmlTable *t)
1094{
1095 if (m_hide) return;
1096 m_t << "</table>\n";
1097 forceStartParagraph(t);
1098}
1099
1100void HtmlDocVisitor::visitPre(DocHtmlRow *tr)
1101{
1102 if (m_hide) return;
1103 m_t << "<tr" << htmlAttribsToString(tr->attribs()) << ">\n";
1104}
1105
1106void HtmlDocVisitor::visitPost(DocHtmlRow *)
1107{
1108 if (m_hide) return;
1109 m_t << "</tr>\n";
1110}
1111
1112void HtmlDocVisitor::visitPre(DocHtmlCell *c)
1113{
1114 if (m_hide) return;
1115 if (c->isHeading())
1116 {
1117 m_t << "<th" << htmlAttribsToString(c->attribs()) << ">";
1118 }
1119 else
1120 {
1121 m_t << "<td" << htmlAttribsToString(c->attribs()) << ">";
1122 }
1123}
1124
1125void HtmlDocVisitor::visitPost(DocHtmlCell *c)
1126{
1127 if (m_hide) return;
1128 if (c->isHeading()) m_t << "</th>"; else m_t << "</td>";
1129}
1130
1131void HtmlDocVisitor::visitPre(DocHtmlCaption *c)
1132{
1133 if (m_hide) return;
1134 bool hasAlign = FALSE;
1135 HtmlAttribListIterator li(c->attribs());
1136 HtmlAttrib *att;
1137 for (li.toFirst();(att=li.current());++li)
1138 {
1139 if (att->name=="align") hasAlign=TRUE;
1140 }
1141 m_t << "<caption" << htmlAttribsToString(c->attribs());
1142 if (!hasAlign) m_t << " align=\"bottom\"";
1143 m_t << ">";
1144}
1145
1146void HtmlDocVisitor::visitPost(DocHtmlCaption *)
1147{
1148 if (m_hide) return;
1149 m_t << "</caption>\n";
1150}
1151
1152void HtmlDocVisitor::visitPre(DocInternal *)
1153{
1154 if (m_hide) return;
1155 //forceEndParagraph(i);
1156 //m_t << "<p><b>" << theTranslator->trForInternalUseOnly() << "</b></p>" << endl;
1157}
1158
1159void HtmlDocVisitor::visitPost(DocInternal *)
1160{
1161 if (m_hide) return;
1162 //forceStartParagraph(i);
1163}
1164
1165void HtmlDocVisitor::visitPre(DocHRef *href)
1166{
1167 if (m_hide) return;
1168 m_t << "<a href=\"" << convertToXML(href->url()) << "\""
1169 << htmlAttribsToString(href->attribs()) << ">";
1170}
1171
1172void HtmlDocVisitor::visitPost(DocHRef *)
1173{
1174 if (m_hide) return;
1175 m_t << "</a>";
1176}
1177
1178void HtmlDocVisitor::visitPre(DocHtmlHeader *header)
1179{
1180 if (m_hide) return;
1181 forceEndParagraph(header);
1182 m_t << "<h" << header->level()
1183 << htmlAttribsToString(header->attribs()) << ">";
1184}
1185
1186void HtmlDocVisitor::visitPost(DocHtmlHeader *header)
1187{
1188 if (m_hide) return;
1189 m_t << "</h" << header->level() << ">\n";
1190 forceStartParagraph(header);
1191}
1192
1193void HtmlDocVisitor::visitPre(DocImage *img)
1194{
1195 if (img->type()==DocImage::Html)
1196 {
1197 forceEndParagraph(img);
1198 if (m_hide) return;
1199 QString baseName=img->name();
1200 int i;
1201 if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1)
1202 {
1203 baseName=baseName.right(baseName.length()-i-1);
1204 }
1205 m_t << "<div class=\"image\">" << endl;
1206 m_t << "<img src=\"" << img->relPath() << img->name() << "\" alt=\""
1207 << baseName << "\"" << htmlAttribsToString(img->attribs())
1208 << "/>" << endl;
1209 if (img->hasCaption())
1210 {
1211 m_t << "<div class=\"caption\">" << endl;
1212 }
1213 }
1214 else // other format -> skip
1215 {
1216 pushEnabled();
1217 m_hide=TRUE;
1218 }
1219}
1220
1221void HtmlDocVisitor::visitPost(DocImage *img)
1222{
1223 if (img->type()==DocImage::Html)
1224 {
1225 if (m_hide) return;
1226 if (img->hasCaption())
1227 {
1228 m_t << "</div>";
1229 }
1230 m_t << "</div>" << endl;
1231 forceStartParagraph(img);
1232 }
1233 else // other format
1234 {
1235 popEnabled();
1236 }
1237}
1238
1239void HtmlDocVisitor::visitPre(DocDotFile *df)
1240{
1241 if (m_hide) return;
1242 m_t << "<div class=\"dotgraph\">" << endl;
1243 writeDotFile(df->file(),df->relPath(),df->context());
1244 if (df->hasCaption())
1245 {
1246 m_t << "<div class=\"caption\">" << endl;
1247 }
1248}
1249
1250void HtmlDocVisitor::visitPost(DocDotFile *df)
1251{
1252 if (m_hide) return;
1253 if (df->hasCaption())
1254 {
1255 m_t << "</div>" << endl;
1256 }
1257 m_t << "</div>" << endl;
1258}
1259
1260void HtmlDocVisitor::visitPre(DocMscFile *df)
1261{
1262 if (m_hide) return;
1263 m_t << "<div class=\"mscgraph\">" << endl;
1264 writeMscFile(df->file(),df->relPath(),df->context());
1265 if (df->hasCaption())
1266 {
1267 m_t << "<div class=\"caption\">" << endl;
1268 }
1269}
1270void HtmlDocVisitor::visitPost(DocMscFile *df)
1271{
1272 if (m_hide) return;
1273 if (df->hasCaption())
1274 {
1275 m_t << "</div>" << endl;
1276 }
1277 m_t << "</div>" << endl;
1278}
1279
1280void HtmlDocVisitor::visitPre(DocLink *lnk)
1281{
1282 if (m_hide) return;
1283 startLink(lnk->ref(),lnk->file(),lnk->relPath(),lnk->anchor());
1284}
1285
1286void HtmlDocVisitor::visitPost(DocLink *)
1287{
1288 if (m_hide) return;
1289 endLink();
1290}
1291
1292void HtmlDocVisitor::visitPre(DocRef *ref)
1293{
1294 if (m_hide) return;
1295 if (!ref->file().isEmpty())
1296 {
1297 startLink(ref->ref(),ref->file(),ref->relPath(),ref->anchor());
1298 }
1299 if (!ref->hasLinkText()) filter(ref->targetTitle());
1300}
1301
1302void HtmlDocVisitor::visitPost(DocRef *ref)
1303{
1304 if (m_hide) return;
1305 if (!ref->file().isEmpty()) endLink();
1306 //m_t << " ";
1307}
1308
1309void HtmlDocVisitor::visitPre(DocSecRefItem *ref)
1310{
1311 if (m_hide) return;
1312 QString refName=ref->file();
1313 if (refName.right(Doxygen::htmlFileExtension.length())!=
1314 QString(Doxygen::htmlFileExtension))
1315 {
1316 refName+=Doxygen::htmlFileExtension;
1317 }
1318 m_t << "<li><a href=\"" << refName << "#" << ref->anchor() << "\">";
1319
1320}
1321
1322void HtmlDocVisitor::visitPost(DocSecRefItem *)
1323{
1324 if (m_hide) return;
1325 m_t << "</a></li>\n";
1326}
1327
1328void HtmlDocVisitor::visitPre(DocSecRefList *s)
1329{
1330 if (m_hide) return;
1331 forceEndParagraph(s);
1332 m_t << "<div class=\"multicol\">" << endl;
1333 m_t << "<ul>" << endl;
1334}
1335
1336void HtmlDocVisitor::visitPost(DocSecRefList *s)
1337{
1338 if (m_hide) return;
1339 m_t << "</ul>" << endl;
1340 m_t << "</div>" << endl;
1341 forceStartParagraph(s);
1342}
1343
1344//void HtmlDocVisitor::visitPre(DocLanguage *l)
1345//{
1346// QString langId = Config_getEnum("OUTPUT_LANGUAGE");
1347// if (l->id().lower()!=langId.lower())
1348// {
1349// pushEnabled();
1350// m_hide = TRUE;
1351// }
1352//}
1353//
1354//void HtmlDocVisitor::visitPost(DocLanguage *l)
1355//{
1356// QString langId = Config_getEnum("OUTPUT_LANGUAGE");
1357// if (l->id().lower()!=langId.lower())
1358// {
1359// popEnabled();
1360// }
1361//}
1362
1363void HtmlDocVisitor::visitPre(DocParamSect *s)
1364{
1365 if (m_hide) return;
1366 forceEndParagraph(s);
1367 m_t << "<dl><dt><b>";
1368 QCString className;
1369 switch(s->type())
1370 {
1371 case DocParamSect::Param:
1372 m_t << theTranslator->trParameters();
1373 className="params";
1374 break;
1375 case DocParamSect::RetVal:
1376 m_t << theTranslator->trReturnValues();
1377 className="retval";
1378 break;
1379 case DocParamSect::Exception:
1380 m_t << theTranslator->trExceptions();
1381 className="exception";
1382 break;
1383 case DocParamSect::TemplateParam:
1384 /* TODO: add this
1385 m_t << theTranslator->trTemplateParam(); break;
1386 */
1387 m_t << "Template Parameters"; break;
1388 className="tparams";
1389 default:
1390 ASSERT(0);
1391 }
1392 m_t << ":";
1393 m_t << "</b></dt><dd>" << endl;
1394 m_t << " <table class=\"" << className << "\">" << endl;
1395}
1396
1397void HtmlDocVisitor::visitPost(DocParamSect *s)
1398{
1399 if (m_hide) return;
1400 m_t << " </table>" << endl;
1401 m_t << " </dd>" << endl;
1402 m_t << "</dl>" << endl;
1403 forceStartParagraph(s);
1404}
1405
1406void HtmlDocVisitor::visitPre(DocParamList *pl)
1407{
1408 //printf("DocParamList::visitPre\n");
1409 if (m_hide) return;
1410 m_t << " <tr>";
1411 DocParamSect *sect = 0;
1412 if (pl->parent()->kind()==DocNode::Kind_ParamSect)
1413 {
1414 sect=(DocParamSect*)pl->parent();
1415 }
1416 if (sect && sect->hasInOutSpecifier())
1417 {
1418 m_t << "<td class=\"paramdir\">";
1419 if (pl->direction()!=DocParamSect::Unspecified)
1420 {
1421 m_t << "[";
1422 if (pl->direction()==DocParamSect::In)
1423 {
1424 m_t << "in";
1425 }
1426 else if (pl->direction()==DocParamSect::Out)
1427 {
1428 m_t << "out";
1429 }
1430 else if (pl->direction()==DocParamSect::InOut)
1431 {
1432 m_t << "in,out";
1433 }
1434 m_t << "]";
1435 }
1436 m_t << "</td>";
1437 }
1438 if (sect && sect->hasTypeSpecifier())
1439 {
1440 m_t << "<td class=\"paramtype\">";
1441 QListIterator<DocNode> li(pl->paramTypes());
1442 DocNode *type;
1443 bool first=TRUE;
1444 for (li.toFirst();(type=li.current());++li)
1445 {
1446 if (!first) m_t << "&#160;|&#160;"; else first=FALSE;
1447 if (type->kind()==DocNode::Kind_Word)
1448 {
1449 visit((DocWord*)type);
1450 }
1451 else if (type->kind()==DocNode::Kind_LinkedWord)
1452 {
1453 visit((DocLinkedWord*)type);
1454 }
1455 }
1456 m_t << "</td>";
1457 }
1458 m_t << "<td class=\"paramname\">";
1459 //QStrListIterator li(pl->parameters());
1460 //const char *s;
1461 QListIterator<DocNode> li(pl->parameters());
1462 DocNode *param;
1463 bool first=TRUE;
1464 for (li.toFirst();(param=li.current());++li)
1465 {
1466 if (!first) m_t << ","; else first=FALSE;
1467 if (param->kind()==DocNode::Kind_Word)
1468 {
1469 visit((DocWord*)param);
1470 }
1471 else if (param->kind()==DocNode::Kind_LinkedWord)
1472 {
1473 visit((DocLinkedWord*)param);
1474 }
1475 }
1476 m_t << "</td><td>";
1477}
1478
1479void HtmlDocVisitor::visitPost(DocParamList *)
1480{
1481 //printf("DocParamList::visitPost\n");
1482 if (m_hide) return;
1483 m_t << "</td></tr>" << endl;
1484}
1485
1486void HtmlDocVisitor::visitPre(DocXRefItem *x)
1487{
1488 if (m_hide) return;
1489 forceEndParagraph(x);
1490 bool anonymousEnum = x->file()=="@";
1491 if (!anonymousEnum)
1492 {
1493 m_t << "<dl class=\"" << x->key() << "\"><dt><b><a class=\"el\" href=\""
1494 << x->relPath() << x->file() << Doxygen::htmlFileExtension
1495 << "#" << x->anchor() << "\">";
1496 }
1497 else
1498 {
1499 m_t << "<dl class=\"" << x->key() << "\"><dt><b>";
1500 }
1501 filter(x->title());
1502 m_t << ":";
1503 if (!anonymousEnum) m_t << "</a>";
1504 m_t << "</b></dt><dd>";
1505}
1506
1507void HtmlDocVisitor::visitPost(DocXRefItem *x)
1508{
1509 if (m_hide) return;
1510 m_t << "</dd></dl>" << endl;
1511 forceStartParagraph(x);
1512}
1513
1514void HtmlDocVisitor::visitPre(DocInternalRef *ref)
1515{
1516 if (m_hide) return;
1517 startLink(0,ref->file(),ref->relPath(),ref->anchor());
1518}
1519
1520void HtmlDocVisitor::visitPost(DocInternalRef *)
1521{
1522 if (m_hide) return;
1523 endLink();
1524 m_t << " ";
1525}
1526
1527void HtmlDocVisitor::visitPre(DocCopy *)
1528{
1529}
1530
1531void HtmlDocVisitor::visitPost(DocCopy *)
1532{
1533}
1534
1535void HtmlDocVisitor::visitPre(DocText *)
1536{
1537}
1538
1539void HtmlDocVisitor::visitPost(DocText *)
1540{
1541}
1542
1543void HtmlDocVisitor::filter(const char *str)
1544{
1545 if (str==0) return;
1546 const char *p=str;
1547 char c;
1548 while (*p)
1549 {
1550 c=*p++;
1551 switch(c)
1552 {
1553 case '<': m_t << "&lt;"; break;
1554 case '>': m_t << "&gt;"; break;
1555 case '&': m_t << "&amp;"; break;
1556 default: m_t << c;
1557 }
1558 }
1559}
1560
1561/// Escape basic entities to produce a valid CDATA attribute value,
1562/// assume that the outer quoting will be using the double quote &quot;
1563void HtmlDocVisitor::filterQuotedCdataAttr(const char* str)
1564{
1565 if (str==0) return;
1566 const char *p=str;
1567 char c;
1568 while (*p)
1569 {
1570 c=*p++;
1571 switch(c)
1572 {
1573 case '&': m_t << "&amp;"; break;
1574 case '"': m_t << "&quot;"; break;
1575 // For SGML compliance, and given the SGML declaration for HTML syntax,
1576 // it's enough to replace these two, provided that the declaration
1577 // for the HTML version we generate (and as supported by the browser)
1578 // specifies that all the other symbols used in rawVal are
1579 // within the right charachter class (i.e., they're not
1580 // some multinational weird charachters not in the BASESET).
1581 // We assume that 1) the browser will support whatever is remaining
1582 // in the formula and 2) the TeX formulae are generally governed
1583 // by even stricter charachter restrictions so it should be enough.
1584 //
1585 // On some incompliant browsers, additional translation of
1586 // '>' and '<' into "&gt;" and "&lt;", respectively, might be needed;
1587 // but I'm unaware of particular modern (last 4 years) versions
1588 // with such problems, so let's not do it for performance.
1589 // Also, some brousers will (wrongly) not process the entity references
1590 // inside the attribute value and show the &...; form instead,
1591 // so we won't create entites unless necessary to minimize clutter there.
1592 // --vassilii
1593 default: m_t << c;
1594 }
1595 }
1596}
1597
1598void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file,
1599 const QCString &relPath,const QCString &anchor,
1600 const QCString &tooltip)
1601{
1602 if (!ref.isEmpty()) // link to entity imported via tag file
1603 {
1604 m_t << "<a class=\"elRef\" ";
1605 m_t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
1606 }
1607 else // local link
1608 {
1609 m_t << "<a class=\"el\" ";
1610 }
1611 m_t << "href=\"";
1612 m_t << externalRef(relPath,ref,TRUE);
1613 if (!file.isEmpty()) m_t << file << Doxygen::htmlFileExtension;
1614 if (!anchor.isEmpty()) m_t << "#" << anchor;
1615 m_t << "\"";
1616 if (!tooltip.isEmpty()) m_t << " title=\"" << tooltip << "\"";
1617 m_t << ">";
1618}
1619
1620void HtmlDocVisitor::endLink()
1621{
1622 m_t << "</a>";
1623}
1624
1625void HtmlDocVisitor::pushEnabled()
1626{
1627 m_enabled.push(new bool(m_hide));
1628}
1629
1630void HtmlDocVisitor::popEnabled()
1631{
1632 bool *v=m_enabled.pop();
1633 ASSERT(v!=0);
1634 m_hide = *v;
1635 delete v;
1636}
1637
1638void HtmlDocVisitor::writeDotFile(const QCString &fn,const QCString &relPath,
1639 const QCString &context)
1640{
1641 QCString baseName=fn;
1642 int i;
1643 if ((i=baseName.findRev('/'))!=-1)
1644 {
1645 baseName=baseName.right(baseName.length()-i-1);
1646 }
1647 if ((i=baseName.find('.'))!=-1) // strip extension
1648 {
1649 baseName=baseName.left(i);
1650 }
1651 baseName.prepend("dot_");
1652 QCString outDir = Config_getString("HTML_OUTPUT");
1653 writeDotGraphFromFile(fn,outDir,baseName,BITMAP);
1654 writeDotImageMapFromFile(m_t,fn,outDir,relPath,baseName,context);
1655}
1656
1657void HtmlDocVisitor::writeMscFile(const QCString &fileName,const QCString &relPath,
1658 const QCString &context)
1659{
1660 QCString baseName=fileName;
1661 int i;
1662 if ((i=baseName.findRev('/'))!=-1) // strip path
1663 {
1664 baseName=baseName.right(baseName.length()-i-1);
1665 }
1666 if ((i=baseName.find('.'))!=-1) // strip extension
1667 {
1668 baseName=baseName.left(i);
1669 }
1670 baseName.prepend("msc_");
1671 QCString outDir = Config_getString("HTML_OUTPUT");
1672 writeMscGraphFromFile(fileName,outDir,baseName,MSC_BITMAP);
1673 writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context);
1674}
1675
1676/** Used for items found inside a paragraph, which due to XHTML restrictions
1677 * have to be outside of the paragraph. This method will forcefully end
1678 * the current paragraph and forceStartParagraph() will restart it.
1679 */
1680void HtmlDocVisitor::forceEndParagraph(DocNode *n)
1681{
1682 //printf("forceEndParagraph(%p) %d\n",n,n->kind());
1683 if (n->parent() && n->parent()->kind()==DocNode::Kind_Para)
1684 {
1685 DocPara *para = (DocPara*)n->parent();
1686 int nodeIndex = para->children().findRef(n);
1687 nodeIndex--;
1688 if (nodeIndex<0) return; // first node
1689 while (nodeIndex>=0 &&
1690 para->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace
1691 )
1692 {
1693 nodeIndex--;
1694 }
1695 if (nodeIndex>=0)
1696 {
1697 DocNode *n = para->children().at(nodeIndex);
1698 //printf("n=%p kind=%d outside=%d\n",n,n->kind(),mustBeOutsideParagraph(n));
1699 if (mustBeOutsideParagraph(n)) return;
1700 }
1701
1702 bool isFirst;
1703 bool isLast;
1704 getParagraphContext(para,isFirst,isLast);
1705 //printf("forceEnd first=%d last=%d\n",isFirst,isLast);
1706 if (isFirst && isLast) return;
1707
1708 m_t << "</p>" << endl;
1709 }
1710}
1711
1712/** Used for items found inside a paragraph, which due to XHTML restrictions
1713 * have to be outside of the paragraph. This method will forcefully start
1714 * the paragraph, that was previously ended by forceEndParagraph().
1715 */
1716void HtmlDocVisitor::forceStartParagraph(DocNode *n)
1717{
1718 //printf("forceStartParagraph(%p) %d\n",n,n->kind());
1719 if (n->parent() && n->parent()->kind()==DocNode::Kind_Para) // if we are inside a paragraph
1720 {
1721 DocPara *para = (DocPara*)n->parent();
1722 int nodeIndex = para->children().findRef(n);
1723 int numNodes = para->children().count();
1724 nodeIndex++;
1725 if (nodeIndex==numNodes) return; // last node
1726 while (nodeIndex<numNodes &&
1727 para->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace
1728 )
1729 {
1730 nodeIndex++;
1731 }
1732 if (nodeIndex<numNodes)
1733 {
1734 DocNode *n = para->children().at(nodeIndex);
1735 if (mustBeOutsideParagraph(n)) return;
1736 }
1737 else
1738 {
1739 return; // only whitespace at the end!
1740 }
1741
1742 bool isFirst;
1743 bool isLast;
1744 getParagraphContext(para,isFirst,isLast);
1745 //printf("forceStart first=%d last=%d\n",isFirst,isLast);
1746 if (isFirst && isLast) return;
1747
1748 m_t << "<p>";
1749 }
1750}
1751
1752

Archive Download this file

Revision: 1322