Changeset 561 for trunk/tools/qdoc3/htmlgenerator.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/tools/qdoc3/htmlgenerator.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the tools applications of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 60 60 #define COMMAND_VERSION Doc::alias("version") 61 61 62 QString HtmlGenerator::sinceTitles[] = 63 { 64 " New Namespaces", 65 " New Classes", 66 " New Member Functions", 67 " New Functions in Namespaces", 68 " New Global Functions", 69 " New Macros", 70 " New Enum Types", 71 " New Typedefs", 72 " New Properties", 73 " New Variables", 74 " New Qml Properties", 75 " New Qml Signals", 76 " New Qml Methods", 77 "" 78 }; 79 62 80 static bool showBrokenLinks = false; 63 64 HtmlGenerator::HtmlGenerator()65 : helpProjectWriter(0), inLink(false), inContents(false),66 inSectionHeading(false), inTableHeader(false), numTableRows(0),67 threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"),68 tre(0), slow(false)69 {70 }71 72 HtmlGenerator::~HtmlGenerator()73 {74 if (helpProjectWriter)75 delete helpProjectWriter;76 }77 78 void HtmlGenerator::initializeGenerator(const Config &config)79 {80 static const struct {81 const char *key;82 const char *left;83 const char *right;84 } defaults[] = {85 { ATOM_FORMATTING_BOLD, "<b>", "</b>" },86 { ATOM_FORMATTING_INDEX, "<!--", "-->" },87 { ATOM_FORMATTING_ITALIC, "<i>", "</i>" },88 { ATOM_FORMATTING_PARAMETER, "<i>", "</i>" },89 { ATOM_FORMATTING_SUBSCRIPT, "<sub>", "</sub>" },90 { ATOM_FORMATTING_SUPERSCRIPT, "<sup>", "</sup>" },91 { ATOM_FORMATTING_TELETYPE, "<tt>", "</tt>" },92 { ATOM_FORMATTING_UNDERLINE, "<u>", "</u>" },93 { 0, 0, 0 }94 };95 96 Generator::initializeGenerator(config);97 setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");98 int i = 0;99 while (defaults[i].key) {100 formattingLeftMap().insert(defaults[i].key, defaults[i].left);101 formattingRightMap().insert(defaults[i].key, defaults[i].right);102 i++;103 }104 105 style = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLE);106 postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER);107 footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER);108 address = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS);109 pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS);110 111 project = config.getString(CONFIG_PROJECT);112 113 projectDescription = config.getString(CONFIG_DESCRIPTION);114 if (projectDescription.isEmpty() && !project.isEmpty())115 projectDescription = project + " Reference Documentation";116 117 projectUrl = config.getString(CONFIG_URL);118 119 QSet<QString> editionNames = config.subVars(CONFIG_EDITION);120 QSet<QString>::ConstIterator edition = editionNames.begin();121 while (edition != editionNames.end()) {122 QString editionName = *edition;123 QStringList editionModules = config.getStringList(124 CONFIG_EDITION + Config::dot + editionName + Config::dot + "modules");125 QStringList editionGroups = config.getStringList(126 CONFIG_EDITION + Config::dot + editionName + Config::dot + "groups");127 128 if (!editionModules.isEmpty())129 editionModuleMap[editionName] = editionModules;130 if (!editionGroups.isEmpty())131 editionGroupMap[editionName] = editionGroups;132 133 ++edition;134 }135 136 slow = config.getBool(CONFIG_SLOW);137 138 stylesheets = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLESHEETS);139 customHeadElements = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_CUSTOMHEADELEMENTS);140 codeIndent = config.getInt(CONFIG_CODEINDENT);141 142 helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp");143 }144 145 void HtmlGenerator::terminateGenerator()146 {147 Generator::terminateGenerator();148 }149 150 QString HtmlGenerator::format()151 {152 return "HTML";153 }154 155 /*!156 This is where the html files and dcf files are written.157 \note The html file generation is done in the base class,158 PageGenerator::generateTree().159 */160 void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker)161 {162 // Copy the stylesheets from the directory containing the qdocconf file.163 // ### This should be changed to use a special directory in doc/src.164 QStringList::ConstIterator styleIter = stylesheets.begin();165 QDir configPath = QDir::current();166 while (styleIter != stylesheets.end()) {167 QString filePath = configPath.absoluteFilePath(*styleIter);168 Config::copyFile(Location(), filePath, filePath, outputDir());169 ++styleIter;170 }171 172 tre = tree;173 nonCompatClasses.clear();174 mainClasses.clear();175 compatClasses.clear();176 moduleClassMap.clear();177 moduleNamespaceMap.clear();178 funcIndex.clear();179 legaleseTexts.clear();180 serviceClasses.clear();181 findAllClasses(tree->root());182 findAllFunctions(tree->root());183 findAllLegaleseTexts(tree->root());184 findAllNamespaces(tree->root());185 #ifdef ZZZ_QDOC_QML186 findAllQmlClasses(tree->root());187 #endif188 189 PageGenerator::generateTree(tree, marker);190 191 dcfClassesRoot.ref = "classes.html";192 dcfClassesRoot.title = "Classes";193 qSort(dcfClassesRoot.subsections);194 195 dcfOverviewsRoot.ref = "overviews.html";196 dcfOverviewsRoot.title = "Overviews";197 qSort(dcfOverviewsRoot.subsections);198 199 dcfExamplesRoot.ref = "examples.html";200 dcfExamplesRoot.title = "Tutorial & Examples";201 qSort(dcfExamplesRoot.subsections);202 203 DcfSection qtRoot;204 appendDcfSubSection(&qtRoot, dcfClassesRoot);205 appendDcfSubSection(&qtRoot, dcfOverviewsRoot);206 appendDcfSubSection(&qtRoot, dcfExamplesRoot);207 208 generateDcf(project.toLower().simplified().replace(" ", "-"),209 "index.html",210 projectDescription, qtRoot);211 generateDcf("designer",212 "designer-manual.html",213 "Qt Designer Manual",214 dcfDesignerRoot);215 generateDcf("linguist",216 "linguist-manual.html",217 "Qt Linguist Manual",218 dcfLinguistRoot);219 generateDcf("assistant",220 "assistant-manual.html",221 "Qt Assistant Manual",222 dcfAssistantRoot);223 generateDcf("qmake",224 "qmake-manual.html",225 "qmake Manual",226 dcfQmakeRoot);227 228 generateIndex(project.toLower().simplified().replace(" ", "-"),229 projectUrl,230 projectDescription);231 232 helpProjectWriter->generate(tre);233 }234 235 void HtmlGenerator::startText(const Node * /* relative */,236 CodeMarker * /* marker */)237 {238 inLink = false;239 inContents = false;240 inSectionHeading = false;241 inTableHeader = false;242 numTableRows = 0;243 threeColumnEnumValueTable = true;244 link.clear();245 sectionNumber.clear();246 }247 248 int HtmlGenerator::generateAtom(const Atom *atom,249 const Node *relative,250 CodeMarker *marker)251 {252 int skipAhead = 0;253 static bool in_para = false;254 255 switch (atom->type()) {256 case Atom::AbstractLeft:257 break;258 case Atom::AbstractRight:259 break;260 case Atom::AutoLink:261 if (!inLink && !inContents && !inSectionHeading) {262 const Node *node = 0;263 QString link = getLink(atom, relative, marker, node);264 if (!link.isEmpty()) {265 beginLink(link, node, relative, marker);266 generateLink(atom, relative, marker);267 endLink();268 }269 else {270 out() << protect(atom->string());271 }272 }273 else {274 out() << protect(atom->string());275 }276 break;277 case Atom::BaseName:278 break;279 case Atom::BriefLeft:280 if (relative->type() == Node::Fake) {281 skipAhead = skipAtoms(atom, Atom::BriefRight);282 break;283 }284 285 out() << "<p>";286 if (relative->type() == Node::Property ||287 relative->type() == Node::Variable) {288 QString str;289 atom = atom->next();290 while (atom != 0 && atom->type() != Atom::BriefRight) {291 if (atom->type() == Atom::String || atom->type() == Atom::AutoLink)292 str += atom->string();293 skipAhead++;294 atom = atom->next();295 }296 str[0] = str[0].toLower();297 if (str.right(1) == ".")298 str.truncate(str.length() - 1);299 out() << "This ";300 if (relative->type() == Node::Property)301 out() << "property";302 else303 out() << "variable";304 QStringList words = str.split(" ");305 if (!(words.first() == "contains" || words.first() == "specifies"306 || words.first() == "describes" || words.first() == "defines"307 || words.first() == "holds" || words.first() == "determines"))308 out() << " holds ";309 else310 out() << " ";311 out() << str << ".";312 }313 break;314 case Atom::BriefRight:315 if (relative->type() != Node::Fake)316 out() << "</p>\n";317 break;318 case Atom::C:319 out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE];320 if (inLink) {321 out() << protect(plainCode(atom->string()));322 }323 else {324 out() << highlightedCode(atom->string(), marker, relative);325 }326 out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE];327 break;328 case Atom::Code:329 out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()),330 marker, relative))331 << "</pre>\n";332 break;333 #ifdef QDOC_QML334 case Atom::Qml:335 out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()),336 marker, relative))337 << "</pre>\n";338 break;339 #endif340 case Atom::CodeNew:341 out() << "<p>you can rewrite it as</p>\n"342 << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()),343 marker, relative))344 << "</pre>\n";345 break;346 case Atom::CodeOld:347 out() << "<p>For example, if you have code like</p>\n";348 // fallthrough349 case Atom::CodeBad:350 out() << "<pre><font color=\"#404040\">"351 << trimmedTrailing(protect(plainCode(indent(codeIndent, atom->string()))))352 << "</font></pre>\n";353 break;354 case Atom::FootnoteLeft:355 // ### For now356 if (in_para) {357 out() << "</p>\n";358 in_para = false;359 }360 out() << "<!-- ";361 break;362 case Atom::FootnoteRight:363 // ### For now364 out() << "-->";365 break;366 case Atom::FormatElse:367 case Atom::FormatEndif:368 case Atom::FormatIf:369 break;370 case Atom::FormattingLeft:371 out() << formattingLeftMap()[atom->string()];372 if (atom->string() == ATOM_FORMATTING_PARAMETER) {373 if (atom->next() != 0 && atom->next()->type() == Atom::String) {374 QRegExp subscriptRegExp("([a-z]+)_([0-9n])");375 if (subscriptRegExp.exactMatch(atom->next()->string())) {376 out() << subscriptRegExp.cap(1) << "<sub>"377 << subscriptRegExp.cap(2) << "</sub>";378 skipAhead = 1;379 }380 }381 }382 break;383 case Atom::FormattingRight:384 if (atom->string() == ATOM_FORMATTING_LINK) {385 endLink();386 }387 else {388 out() << formattingRightMap()[atom->string()];389 }390 break;391 case Atom::GeneratedList:392 if (atom->string() == "annotatedclasses") {393 generateAnnotatedList(relative, marker, nonCompatClasses);394 }395 else if (atom->string() == "classes") {396 generateCompactList(relative, marker, nonCompatClasses);397 }398 else if (atom->string().contains("classesbymodule")) {399 QString arg = atom->string().trimmed();400 QString moduleName = atom->string().mid(atom->string().indexOf(401 "classesbymodule") + 15).trimmed();402 if (moduleClassMap.contains(moduleName))403 generateAnnotatedList(relative, marker, moduleClassMap[moduleName]);404 }405 else if (atom->string().contains("classesbyedition")) {406 407 QString arg = atom->string().trimmed();408 QString editionName = atom->string().mid(atom->string().indexOf(409 "classesbyedition") + 16).trimmed();410 411 if (editionModuleMap.contains(editionName)) {412 413 // Add all classes in the modules listed for that edition.414 QMap<QString, const Node *> editionClasses;415 foreach (const QString &moduleName, editionModuleMap[editionName]) {416 if (moduleClassMap.contains(moduleName))417 editionClasses.unite(moduleClassMap[moduleName]);418 }419 420 // Add additional groups and remove groups of classes that421 // should be excluded from the edition.422 423 QMultiMap <QString, Node *> groups = tre->groups();424 foreach (const QString &groupName, editionGroupMap[editionName]) {425 QList<Node *> groupClasses;426 if (groupName.startsWith("-")) {427 groupClasses = groups.values(groupName.mid(1));428 foreach (const Node *node, groupClasses)429 editionClasses.remove(node->name());430 }431 else {432 groupClasses = groups.values(groupName);433 foreach (const Node *node, groupClasses)434 editionClasses.insert(node->name(), node);435 }436 }437 generateAnnotatedList(relative, marker, editionClasses);438 }439 }440 else if (atom->string() == "classhierarchy") {441 generateClassHierarchy(relative, marker, nonCompatClasses);442 }443 else if (atom->string() == "compatclasses") {444 generateCompactList(relative, marker, compatClasses);445 }446 else if (atom->string() == "functionindex") {447 generateFunctionIndex(relative, marker);448 }449 else if (atom->string() == "legalese") {450 generateLegaleseList(relative, marker);451 }452 else if (atom->string() == "mainclasses") {453 generateCompactList(relative, marker, mainClasses);454 }455 else if (atom->string() == "services") {456 generateCompactList(relative, marker, serviceClasses);457 }458 else if (atom->string() == "overviews") {459 generateOverviewList(relative, marker);460 }461 else if (atom->string() == "namespaces") {462 generateAnnotatedList(relative, marker, namespaceIndex);463 }464 else if (atom->string() == "related") {465 const FakeNode *fake = static_cast<const FakeNode *>(relative);466 if (fake && !fake->groupMembers().isEmpty()) {467 QMap<QString, const Node *> groupMembersMap;468 foreach (const Node *node, fake->groupMembers()) {469 if (node->type() == Node::Fake)470 groupMembersMap[fullName(node, relative, marker)] = node;471 }472 generateAnnotatedList(fake, marker, groupMembersMap);473 }474 }475 else if (atom->string() == "relatedinline") {476 const FakeNode *fake = static_cast<const FakeNode *>(relative);477 if (fake && !fake->groupMembers().isEmpty()) {478 // Reverse the list into the original scan order.479 // Should be sorted. But on what? It may not be a480 // regular class or page definition.481 QList<const Node *> list;482 foreach (const Node *node, fake->groupMembers())483 list.prepend(node);484 foreach (const Node *node, list)485 generateBody(node, marker);486 }487 }488 break;489 case Atom::Image:490 case Atom::InlineImage:491 {492 QString fileName = imageFileName(relative, atom->string());493 QString text;494 if (atom->next() != 0)495 text = atom->next()->string();496 if (atom->type() == Atom::Image)497 out() << "<p align=\"center\">";498 if (fileName.isEmpty()) {499 out() << "<font color=\"red\">[Missing image "500 << protect(atom->string()) << "]</font>";501 }502 else {503 out() << "<img src=\"" << protect(fileName) << "\"";504 if (!text.isEmpty())505 out() << " alt=\"" << protect(text) << "\"";506 out() << " />";507 helpProjectWriter->addExtraFile(fileName);508 }509 if (atom->type() == Atom::Image)510 out() << "</p>";511 }512 break;513 case Atom::ImageText:514 break;515 case Atom::LegaleseLeft:516 out() << "<div style=\"padding: 0.5em; background: #e0e0e0; color: black\">";517 break;518 case Atom::LegaleseRight:519 out() << "</div>";520 break;521 case Atom::LineBreak:522 out() << "<br />";523 break;524 case Atom::Link:525 {526 const Node *node = 0;527 QString myLink = getLink(atom, relative, marker, node);528 if (myLink.isEmpty())529 relative->doc().location().warning(tr("Cannot link to '%1' in %2")530 .arg(atom->string())531 .arg(marker->plainFullName(relative)));532 beginLink(myLink, node, relative, marker);533 skipAhead = 1;534 }535 break;536 case Atom::LinkNode:537 {538 const Node *node = CodeMarker::nodeForString(atom->string());539 beginLink(linkForNode(node, relative), node, relative, marker);540 skipAhead = 1;541 }542 break;543 case Atom::ListLeft:544 if (in_para) {545 out() << "</p>\n";546 in_para = false;547 }548 if (atom->string() == ATOM_LIST_BULLET) {549 out() << "<ul>\n";550 }551 else if (atom->string() == ATOM_LIST_TAG) {552 out() << "<dl>\n";553 }554 else if (atom->string() == ATOM_LIST_VALUE) {555 threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);556 if (threeColumnEnumValueTable) {557 out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"100%\">\n"558 "<tr><th width=\"25%\">Constant</th><th width=\"15%\">Value</th>"559 "<th width=\"60%\">Description</th></tr>\n";560 }561 else {562 out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"40%\">\n"563 << "<tr><th width=\"60%\">Constant</th><th width=\"40%\">Value</th></tr>\n";564 }565 }566 else {567 out() << "<ol type=";568 if (atom->string() == ATOM_LIST_UPPERALPHA) {569 out() << "\"A\"";570 }571 else if (atom->string() == ATOM_LIST_LOWERALPHA) {572 out() << "\"a\"";573 }574 else if (atom->string() == ATOM_LIST_UPPERROMAN) {575 out() << "\"I\"";576 }577 else if (atom->string() == ATOM_LIST_LOWERROMAN) {578 out() << "\"i\"";579 }580 else { // (atom->string() == ATOM_LIST_NUMERIC)581 out() << "\"1\"";582 }583 if (atom->next() != 0 && atom->next()->string().toInt() != 1)584 out() << " start=\"" << atom->next()->string() << "\"";585 out() << ">\n";586 }587 break;588 case Atom::ListItemNumber:589 break;590 case Atom::ListTagLeft:591 if (atom->string() == ATOM_LIST_TAG) {592 out() << "<dt>";593 }594 else { // (atom->string() == ATOM_LIST_VALUE)595 // ### Trenton596 597 out() << "<tr><td valign=\"top\"><tt>"598 << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(),599 relative)))600 << "</tt></td><td align=\"center\" valign=\"top\">";601 602 QString itemValue;603 if (relative->type() == Node::Enum) {604 const EnumNode *enume = static_cast<const EnumNode *>(relative);605 itemValue = enume->itemValue(atom->next()->string());606 }607 608 if (itemValue.isEmpty())609 out() << "?";610 else611 out() << "<tt>" << protect(itemValue) << "</tt>";612 613 skipAhead = 1;614 }615 break;616 case Atom::ListTagRight:617 if (atom->string() == ATOM_LIST_TAG)618 out() << "</dt>\n";619 break;620 case Atom::ListItemLeft:621 if (atom->string() == ATOM_LIST_TAG) {622 out() << "<dd>";623 }624 else if (atom->string() == ATOM_LIST_VALUE) {625 if (threeColumnEnumValueTable) {626 out() << "</td><td valign=\"top\">";627 if (matchAhead(atom, Atom::ListItemRight))628 out() << " ";629 }630 }631 else {632 out() << "<li>";633 }634 if (matchAhead(atom, Atom::ParaLeft))635 skipAhead = 1;636 break;637 case Atom::ListItemRight:638 if (atom->string() == ATOM_LIST_TAG) {639 out() << "</dd>\n";640 }641 else if (atom->string() == ATOM_LIST_VALUE) {642 out() << "</td></tr>\n";643 }644 else {645 out() << "</li>\n";646 }647 break;648 case Atom::ListRight:649 if (atom->string() == ATOM_LIST_BULLET) {650 out() << "</ul>\n";651 }652 else if (atom->string() == ATOM_LIST_TAG) {653 out() << "</dl>\n";654 }655 else if (atom->string() == ATOM_LIST_VALUE) {656 out() << "</table></p>\n";657 }658 else {659 out() << "</ol>\n";660 }661 break;662 case Atom::Nop:663 break;664 case Atom::ParaLeft:665 out() << "<p>";666 in_para = true;667 break;668 case Atom::ParaRight:669 endLink();670 if (in_para) {671 out() << "</p>\n";672 in_para = false;673 }674 //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight))675 // out() << "</p>\n";676 break;677 case Atom::QuotationLeft:678 out() << "<blockquote>";679 break;680 case Atom::QuotationRight:681 out() << "</blockquote>\n";682 break;683 case Atom::RawString:684 out() << atom->string();685 break;686 case Atom::SectionLeft:687 #if 0688 {689 int nextLevel = atom->string().toInt();690 if (sectionNumber.size() < nextLevel) {691 do {692 sectionNumber.append("1");693 } while (sectionNumber.size() < nextLevel);694 }695 else {696 while (sectionNumber.size() > nextLevel) {697 sectionNumber.removeLast();698 }699 sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);700 }701 out() << "<a name=\"sec-" << sectionNumber.join("-") << "\"></a>\n";702 }703 #else704 out() << "<a name=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString())705 << "\"></a>\n";706 #endif707 break;708 case Atom::SectionRight:709 break;710 case Atom::SectionHeadingLeft:711 out() << "<h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">";712 inSectionHeading = true;713 break;714 case Atom::SectionHeadingRight:715 out() << "</h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">\n";716 inSectionHeading = false;717 break;718 case Atom::SidebarLeft:719 break;720 case Atom::SidebarRight:721 break;722 case Atom::String:723 if (inLink && !inContents && !inSectionHeading) {724 generateLink(atom, relative, marker);725 }726 else {727 out() << protect(atom->string());728 }729 break;730 case Atom::TableLeft:731 if (in_para) {732 out() << "</p>\n";733 in_para = false;734 }735 if (!atom->string().isEmpty()) {736 if (atom->string().contains("%"))737 out() << "<p><table width=\"" << atom->string() << "\" "738 << "align=\"center\" cellpadding=\"2\" "739 << "cellspacing=\"1\" border=\"0\">\n";740 else741 out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n";742 }743 else {744 out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n";745 }746 numTableRows = 0;747 break;748 case Atom::TableRight:749 out() << "</table></p>\n";750 break;751 case Atom::TableHeaderLeft:752 out() << "<thead><tr valign=\"top\" class=\"qt-style\">";753 inTableHeader = true;754 break;755 case Atom::TableHeaderRight:756 out() << "</tr>";757 if (matchAhead(atom, Atom::TableHeaderLeft)) {758 skipAhead = 1;759 out() << "\n<tr valign=\"top\" class=\"qt-style\">";760 }761 else {762 out() << "</thead>\n";763 inTableHeader = false;764 }765 break;766 case Atom::TableRowLeft:767 if (++numTableRows % 2 == 1)768 out() << "<tr valign=\"top\" class=\"odd\">";769 else770 out() << "<tr valign=\"top\" class=\"even\">";771 break;772 case Atom::TableRowRight:773 out() << "</tr>\n";774 break;775 case Atom::TableItemLeft:776 {777 if (inTableHeader)778 out() << "<th";779 else780 out() << "<td";781 782 QStringList spans = atom->string().split(",");783 if (spans.size() == 2) {784 if (spans.at(0) != "1")785 out() << " colspan=\"" << spans.at(0) << "\"";786 if (spans.at(1) != "1")787 out() << " rowspan=\"" << spans.at(1) << "\"";788 out() << ">";789 }790 if (matchAhead(atom, Atom::ParaLeft))791 skipAhead = 1;792 }793 break;794 case Atom::TableItemRight:795 if (inTableHeader)796 out() << "</th>";797 else798 out() << "</td>";799 if (matchAhead(atom, Atom::ParaLeft))800 skipAhead = 1;801 break;802 case Atom::TableOfContents:803 {804 int numColumns = 1;805 const Node *node = relative;806 807 Doc::SectioningUnit sectioningUnit = Doc::Section4;808 QStringList params = atom->string().split(",");809 QString columnText = params.at(0);810 QStringList pieces = columnText.split(" ", QString::SkipEmptyParts);811 if (pieces.size() >= 2) {812 columnText = pieces.at(0);813 pieces.pop_front();814 QString path = pieces.join(" ").trimmed();815 node = findNodeForTarget(path, relative, marker, atom);816 }817 818 if (params.size() == 2) {819 numColumns = qMax(columnText.toInt(), numColumns);820 sectioningUnit = (Doc::SectioningUnit)params.at(1).toInt();821 }822 823 if (node)824 generateTableOfContents(node, marker, sectioningUnit, numColumns,825 relative);826 }827 break;828 case Atom::Target:829 out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>";830 break;831 case Atom::UnhandledFormat:832 out() << "<font color=\"red\"><b><Missing HTML></b></font>";833 break;834 case Atom::UnknownCommand:835 out() << "<font color=\"red\"><b><code>\\" << protect(atom->string())836 << "</code></b></font>";837 break;838 #ifdef QDOC_QML839 case Atom::QmlText:840 case Atom::EndQmlText:841 // don't do anything with these. They are just tags.842 break;843 #endif844 default:845 unknownAtom(atom);846 }847 return skipAhead;848 }849 850 void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,851 CodeMarker *marker)852 {853 QList<Section> sections;854 QList<Section>::ConstIterator s;855 856 const ClassNode *classe = 0;857 const NamespaceNode *namespasse = 0;858 859 QString title;860 QString rawTitle;861 QString fullTitle;862 if (inner->type() == Node::Namespace) {863 namespasse = static_cast<const NamespaceNode *>(inner);864 rawTitle = marker->plainName(inner);865 fullTitle = marker->plainFullName(inner);866 title = rawTitle + " Namespace Reference";867 }868 else if (inner->type() == Node::Class) {869 classe = static_cast<const ClassNode *>(inner);870 rawTitle = marker->plainName(inner);871 fullTitle = marker->plainFullName(inner);872 title = rawTitle + " Class Reference";873 }874 875 DcfSection classSection;876 classSection.title = title;877 classSection.ref = linkForNode(inner, 0);878 classSection.keywords += qMakePair(inner->name(), classSection.ref);879 880 Text subtitleText;881 if (rawTitle != fullTitle)882 subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")"883 << Atom(Atom::LineBreak);884 885 QString fixedModule = inner->moduleName();886 if (fixedModule == "Qt3SupportLight")887 fixedModule = "Qt3Support";888 if (!fixedModule.isEmpty())889 subtitleText << "[" << Atom(Atom::AutoLink, fixedModule) << " module]";890 891 if (fixedModule.isEmpty()) {892 QMultiMap<QString, QString> publicGroups = tre->publicGroups();893 QList<QString> groupNames = publicGroups.values(inner->name());894 if (!groupNames.isEmpty()) {895 qSort(groupNames.begin(), groupNames.end());896 subtitleText << "[";897 for (int j=0; j<groupNames.count(); j++) {898 subtitleText << Atom(Atom::AutoLink, groupNames[j]);899 if (j<groupNames.count()-1)900 subtitleText <<", ";901 }902 subtitleText << "]";903 }904 }905 906 generateHeader(title, inner, marker, true);907 generateTitle(title, subtitleText, SmallSubTitle, inner, marker);908 909 generateBrief(inner, marker);910 generateIncludes(inner, marker);911 generateStatus(inner, marker);912 if (classe) {913 generateModuleWarning(classe, marker);914 generateInherits(classe, marker);915 generateInheritedBy(classe, marker);916 }917 generateThreadSafeness(inner, marker);918 generateSince(inner, marker);919 920 out() << "<ul>\n";921 922 QString membersLink = generateListOfAllMemberFile(inner, marker);923 if (!membersLink.isEmpty())924 out() << "<li><a href=\"" << membersLink << "\">"925 << "List of all members, including inherited members</a></li>\n";926 927 QString obsoleteLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Obsolete);928 if (!obsoleteLink.isEmpty())929 out() << "<li><a href=\"" << obsoleteLink << "\">"930 << "Obsolete members</a></li>\n";931 932 QString compatLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Compat);933 if (!compatLink.isEmpty())934 out() << "<li><a href=\"" << compatLink << "\">"935 << "Qt 3 support members</a></li>\n";936 937 out() << "</ul>\n";938 939 bool needOtherSection = false;940 941 sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);942 s = sections.begin();943 while (s != sections.end()) {944 if (s->members.isEmpty()) {945 if (!s->inherited.isEmpty())946 needOtherSection = true;947 } else {948 out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n";949 out() << "<h3>" << protect((*s).name) << "</h3>\n";950 951 generateSectionList(*s, inner, marker, CodeMarker::Summary);952 }953 ++s;954 }955 956 if (needOtherSection) {957 out() << "<h3>Additional Inherited Members</h3>\n"958 "<ul>\n";959 960 s = sections.begin();961 while (s != sections.end()) {962 if (s->members.isEmpty() && !s->inherited.isEmpty())963 generateSectionInheritedList(*s, inner, marker);964 ++s;965 }966 out() << "</ul>\n";967 }968 969 out() << "<a name=\"" << registerRef("details") << "\"></a>\n";970 971 if (!inner->doc().isEmpty()) {972 out() << "<hr />\n"973 << "<h2>" << "Detailed Description" << "</h2>\n";974 generateBody(inner, marker);975 generateAlsoList(inner, marker);976 }977 978 sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);979 s = sections.begin();980 while (s != sections.end()) {981 out() << "<hr />\n";982 out() << "<h2>" << protect((*s).name) << "</h2>\n";983 984 NodeList::ConstIterator m = (*s).members.begin();985 while (m != (*s).members.end()) {986 if ((*m)->access() != Node::Private) { // ### check necessary?987 if ((*m)->type() != Node::Class)988 generateDetailedMember(*m, inner, marker);989 else {990 out() << "<h3> class ";991 generateFullName(*m, inner, marker);992 out() << "</h3>";993 generateBrief(*m, marker, inner);994 }995 996 QStringList names;997 names << (*m)->name();998 if ((*m)->type() == Node::Function) {999 const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m);1000 if (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor1001 || func->overloadNumber() != 1)1002 names.clear();1003 } else if ((*m)->type() == Node::Property) {1004 const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m);1005 if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name()))1006 names << prop->getters().first()->name();1007 if (!prop->setters().isEmpty())1008 names << prop->setters().first()->name();1009 if (!prop->resetters().isEmpty())1010 names << prop->resetters().first()->name();1011 } else if ((*m)->type() == Node::Enum) {1012 const EnumNode *enume = reinterpret_cast<const EnumNode *>(*m);1013 if (enume->flagsType())1014 names << enume->flagsType()->name();1015 1016 foreach (const QString &enumName,1017 enume->doc().enumItemNames().toSet()1018 - enume->doc().omitEnumItemNames().toSet())1019 names << plainCode(marker->markedUpEnumValue(enumName, enume));1020 }1021 foreach (const QString &name, names)1022 classSection.keywords += qMakePair(name, linkForNode(*m, 0));1023 }1024 ++m;1025 }1026 ++s;1027 }1028 generateFooter(inner);1029 1030 if (!membersLink.isEmpty()) {1031 DcfSection membersSection;1032 membersSection.title = "List of all members";1033 membersSection.ref = membersLink;1034 appendDcfSubSection(&classSection, membersSection);1035 }1036 if (!obsoleteLink.isEmpty()) {1037 DcfSection obsoleteSection;1038 obsoleteSection.title = "Obsolete members";1039 obsoleteSection.ref = obsoleteLink;1040 appendDcfSubSection(&classSection, obsoleteSection);1041 }1042 if (!compatLink.isEmpty()) {1043 DcfSection compatSection;1044 compatSection.title = "Qt 3 support members";1045 compatSection.ref = compatLink;1046 appendDcfSubSection(&classSection, compatSection);1047 }1048 1049 appendDcfSubSection(&dcfClassesRoot, classSection);1050 }1051 1052 void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)1053 {1054 SubTitleSize subTitleSize = LargeSubTitle;1055 DcfSection fakeSection;1056 fakeSection.title = fake->fullTitle();1057 fakeSection.ref = linkForNode(fake, 0);1058 1059 QList<Section> sections;1060 QList<Section>::const_iterator s;1061 1062 QString htmlTitle = fake->fullTitle();1063 if (fake->subType() == FakeNode::File && !fake->subTitle().isEmpty()) {1064 subTitleSize = SmallSubTitle;1065 htmlTitle += " (" + fake->subTitle() + ")";1066 }1067 1068 generateHeader(htmlTitle, fake, marker, true);1069 generateTitle(fake->fullTitle(), Text() << fake->subTitle(), subTitleSize,1070 fake, marker);1071 1072 if (fake->subType() == FakeNode::Module) {1073 // Generate brief text and status for modules.1074 generateBrief(fake, marker);1075 generateStatus(fake, marker);1076 1077 if (moduleNamespaceMap.contains(fake->name())) {1078 out() << "<h2>Namespaces</h2>\n";1079 generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]);1080 }1081 if (moduleClassMap.contains(fake->name())) {1082 out() << "<h2>Classes</h2>\n";1083 generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);1084 }1085 }1086 else if (fake->subType() == FakeNode::HeaderFile) {1087 // Generate brief text and status for modules.1088 generateBrief(fake, marker);1089 generateStatus(fake, marker);1090 1091 out() << "<ul>\n";1092 1093 QString membersLink = generateListOfAllMemberFile(fake, marker);1094 if (!membersLink.isEmpty())1095 out() << "<li><a href=\"" << membersLink << "\">"1096 << "List of all members, including inherited members</a></li>\n";1097 1098 QString obsoleteLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Obsolete);1099 if (!obsoleteLink.isEmpty())1100 out() << "<li><a href=\"" << obsoleteLink << "\">"1101 << "Obsolete members</a></li>\n";1102 1103 QString compatLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Compat);1104 if (!compatLink.isEmpty())1105 out() << "<li><a href=\"" << compatLink << "\">"1106 << "Qt 3 support members</a></li>\n";1107 1108 out() << "</ul>\n";1109 1110 if (!membersLink.isEmpty()) {1111 DcfSection membersSection;1112 membersSection.title = "List of all members";1113 membersSection.ref = membersLink;1114 appendDcfSubSection(&fakeSection, membersSection);1115 }1116 if (!obsoleteLink.isEmpty()) {1117 DcfSection obsoleteSection;1118 obsoleteSection.title = "Obsolete members";1119 obsoleteSection.ref = obsoleteLink;1120 appendDcfSubSection(&fakeSection, obsoleteSection);1121 }1122 if (!compatLink.isEmpty()) {1123 DcfSection compatSection;1124 compatSection.title = "Qt 3 support members";1125 compatSection.ref = compatLink;1126 appendDcfSubSection(&fakeSection, compatSection);1127 }1128 }1129 1130 sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay);1131 s = sections.begin();1132 while (s != sections.end()) {1133 out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n";1134 out() << "<h3>" << protect((*s).name) << "</h3>\n";1135 generateSectionList(*s, fake, marker, CodeMarker::Summary);1136 ++s;1137 }1138 1139 Text brief = fake->doc().briefText();1140 if (fake->subType() == FakeNode::Module && !brief.isEmpty()) {1141 out() << "<a name=\"" << registerRef("details") << "\"></a>\n";1142 out() << "<h2>" << "Detailed Description" << "</h2>\n";1143 }1144 1145 generateBody(fake, marker);1146 #ifdef QDOC_QML1147 if (fake->subType() == FakeNode::QmlClass) {1148 //qDebug() << "generateFakeNode(): QML CLASS" << fake->name();1149 const QmlNode* qmlNode = static_cast<const QmlNode*>(fake);1150 const ClassNode* cn = qmlNode->classNode();1151 if (cn) {1152 //qDebug() << " CPP CLASS" << cn->name();1153 generateQmlText(cn->doc().body(), cn, marker);1154 }1155 }1156 #endif1157 1158 generateAlsoList(fake, marker);1159 1160 if (!fake->groupMembers().isEmpty()) {1161 QMap<QString, const Node *> groupMembersMap;1162 foreach (const Node *node, fake->groupMembers()) {1163 if (node->type() == Node::Class || node->type() == Node::Namespace)1164 groupMembersMap[node->name()] = node;1165 }1166 generateAnnotatedList(fake, marker, groupMembersMap);1167 }1168 1169 fakeSection.keywords += qMakePair(fakeSection.title, fakeSection.ref);1170 1171 sections = marker->sections(fake, CodeMarker::Detailed, CodeMarker::Okay);1172 s = sections.begin();1173 while (s != sections.end()) {1174 out() << "<hr />\n";1175 out() << "<h2>" << protect((*s).name) << "</h2>\n";1176 1177 NodeList::ConstIterator m = (*s).members.begin();1178 while (m != (*s).members.end()) {1179 generateDetailedMember(*m, fake, marker);1180 fakeSection.keywords += qMakePair((*m)->name(), linkForNode(*m, 0));1181 ++m;1182 }1183 ++s;1184 }1185 generateFooter(fake);1186 1187 if (fake->subType() == FakeNode::Example) {1188 appendDcfSubSection(&dcfExamplesRoot, fakeSection);1189 }1190 else if (fake->subType() != FakeNode::File) {1191 QString contentsPage = fake->links().value(Node::ContentsLink).first;1192 1193 if (contentsPage == "Qt Designer Manual") {1194 appendDcfSubSection(&dcfDesignerRoot, fakeSection);1195 }1196 else if (contentsPage == "Qt Linguist Manual") {1197 appendDcfSubSection(&dcfLinguistRoot, fakeSection);1198 }1199 else if (contentsPage == "Qt Assistant Manual") {1200 appendDcfSubSection(&dcfAssistantRoot, fakeSection);1201 }1202 else if (contentsPage == "qmake Manual") {1203 appendDcfSubSection(&dcfQmakeRoot, fakeSection);1204 }1205 else {1206 appendDcfSubSection(&dcfOverviewsRoot, fakeSection);1207 }1208 }1209 }1210 1211 QString HtmlGenerator::fileExtension(const Node * /* node */)1212 {1213 return "html";1214 }1215 1216 void HtmlGenerator::generateHeader(const QString& title,1217 const Node *node,1218 CodeMarker *marker,1219 bool mainPage)1220 {1221 out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";1222 1223 out() << "<!DOCTYPE html\n"1224 " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"1225 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n";1226 1227 QString shortVersion;1228 if ((project != "Qtopia") && (project != "Qt Extended")) {1229 shortVersion = project + " " + shortVersion + ": ";1230 if (node && !node->doc().location().isEmpty())1231 out() << "<!-- " << node->doc().location().filePath() << " -->\n";1232 1233 shortVersion = tre->version();1234 if (shortVersion.count(QChar('.')) == 2)1235 shortVersion.truncate(shortVersion.lastIndexOf(QChar('.')));1236 if (!shortVersion.isEmpty()) {1237 if (project == "QSA")1238 shortVersion = "QSA " + shortVersion + ": ";1239 else1240 shortVersion = "Qt " + shortVersion + ": ";1241 }1242 }1243 1244 out() << "<head>\n"1245 " <title>" << shortVersion << protect(title) << "</title>\n";1246 if (!style.isEmpty())1247 out() << " <style type=\"text/css\">" << style << "</style>\n";1248 1249 const QMap<QString, QString> &metaMap = node->doc().metaTagMap();1250 if (!metaMap.isEmpty()) {1251 QMapIterator<QString, QString> i(metaMap);1252 while (i.hasNext()) {1253 i.next();1254 out() << " <meta name=\"" << protect(i.key()) << "\" contents=\""1255 << protect(i.value()) << "\" />\n";1256 }1257 }1258 1259 navigationLinks.clear();1260 1261 if (node && !node->links().empty()) {1262 QPair<QString,QString> linkPair;1263 QPair<QString,QString> anchorPair;1264 const Node *linkNode;1265 1266 if (node->links().contains(Node::PreviousLink)) {1267 linkPair = node->links()[Node::PreviousLink];1268 linkNode = findNodeForTarget(linkPair.first, node, marker);1269 if (!linkNode || linkNode == node)1270 anchorPair = linkPair;1271 else1272 anchorPair = anchorForNode(linkNode);1273 1274 out() << " <link rel=\"prev\" href=\""1275 << anchorPair.first << "\" />\n";1276 1277 navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">";1278 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())1279 navigationLinks += protect(anchorPair.second);1280 else1281 navigationLinks += protect(linkPair.second);1282 navigationLinks += "</a>]\n";1283 }1284 if (node->links().contains(Node::ContentsLink)) {1285 linkPair = node->links()[Node::ContentsLink];1286 linkNode = findNodeForTarget(linkPair.first, node, marker);1287 if (!linkNode || linkNode == node)1288 anchorPair = linkPair;1289 else1290 anchorPair = anchorForNode(linkNode);1291 1292 out() << " <link rel=\"contents\" href=\""1293 << anchorPair.first << "\" />\n";1294 1295 navigationLinks += "[<a href=\"" + anchorPair.first + "\">";1296 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())1297 navigationLinks += protect(anchorPair.second);1298 else1299 navigationLinks += protect(linkPair.second);1300 navigationLinks += "</a>]\n";1301 }1302 if (node->links().contains(Node::NextLink)) {1303 linkPair = node->links()[Node::NextLink];1304 linkNode = findNodeForTarget(linkPair.first, node, marker);1305 if (!linkNode || linkNode == node)1306 anchorPair = linkPair;1307 else1308 anchorPair = anchorForNode(linkNode);1309 1310 out() << " <link rel=\"next\" href=\""1311 << anchorPair.first << "\" />\n";1312 1313 navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">";1314 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())1315 navigationLinks += protect(anchorPair.second);1316 else1317 navigationLinks += protect(linkPair.second);1318 navigationLinks += "</a>]\n";1319 }1320 if (node->links().contains(Node::IndexLink)) {1321 linkPair = node->links()[Node::IndexLink];1322 linkNode = findNodeForTarget(linkPair.first, node, marker);1323 if (!linkNode || linkNode == node)1324 anchorPair = linkPair;1325 else1326 anchorPair = anchorForNode(linkNode);1327 out() << " <link rel=\"index\" href=\""1328 << anchorPair.first << "\" />\n";1329 }1330 if (node->links().contains(Node::StartLink)) {1331 linkPair = node->links()[Node::StartLink];1332 linkNode = findNodeForTarget(linkPair.first, node, marker);1333 if (!linkNode || linkNode == node)1334 anchorPair = linkPair;1335 else1336 anchorPair = anchorForNode(linkNode);1337 out() << " <link rel=\"start\" href=\""1338 << anchorPair.first << "\" />\n";1339 }1340 }1341 1342 foreach (const QString &stylesheet, stylesheets) {1343 out() << " <link href=\"" << stylesheet << "\" rel=\"stylesheet\" "1344 << "type=\"text/css\" />\n";1345 }1346 1347 foreach (const QString &customHeadElement, customHeadElements) {1348 out() << " " << customHeadElement << "\n";1349 }1350 1351 out() << "</head>\n"1352 "<body>\n";1353 if (mainPage)1354 generateMacRef(node, marker);1355 out() << QString(postHeader).replace("\\" + COMMAND_VERSION, tre->version());1356 1357 1358 if (node && !node->links().empty())1359 out() << "<p>\n" << navigationLinks << "</p>\n";1360 }1361 1362 void HtmlGenerator::generateTitle(const QString& title,1363 const Text &subTitle,1364 SubTitleSize subTitleSize,1365 const Node *relative,1366 CodeMarker *marker)1367 {1368 out() << "<h1 class=\"title\">" << protect(title);1369 if (!subTitle.isEmpty()) {1370 out() << "<br />";1371 if (subTitleSize == SmallSubTitle)1372 out() << "<span class=\"small-subtitle\">";1373 else1374 out() << "<span class=\"subtitle\">";1375 generateText(subTitle, relative, marker);1376 out() << "</span>\n";1377 }1378 out() << "</h1>\n";1379 }1380 1381 void HtmlGenerator::generateFooter(const Node *node)1382 {1383 if (node && !node->links().empty())1384 out() << "<p>\n" << navigationLinks << "</p>\n";1385 1386 out() << QString(footer).replace("\\" + COMMAND_VERSION, tre->version())1387 << QString(address).replace("\\" + COMMAND_VERSION, tre->version())1388 << "</body>\n"1389 "</html>\n";1390 }1391 1392 void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,1393 const Node *relative)1394 {1395 Text brief = node->doc().briefText();1396 if (!brief.isEmpty()) {1397 out() << "<p>";1398 generateText(brief, node, marker);1399 if (!relative || node == relative)1400 out() << " <a href=\"#";1401 else1402 out() << " <a href=\"" << linkForNode(node, relative) << "#";1403 out() << registerRef("details") << "\">More...</a></p>\n";1404 }1405 }1406 1407 void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker)1408 {1409 if (!inner->includes().isEmpty()) {1410 out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent,1411 marker->markedUpIncludes(1412 inner->includes())),1413 marker, inner))1414 << "</pre>";1415 }1416 }1417 1418 void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker,1419 Doc::SectioningUnit sectioningUnit,1420 int numColumns, const Node *relative)1421 1422 {1423 if (!node->doc().hasTableOfContents())1424 return;1425 QList<Atom *> toc = node->doc().tableOfContents();1426 if (toc.isEmpty())1427 return;1428 1429 QString nodeName = "";1430 if (node != relative)1431 nodeName = node->name();1432 1433 QStringList sectionNumber;1434 int columnSize = 0;1435 1436 QString tdTag;1437 if (numColumns > 1) {1438 tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">";1439 out() << "<p><table width=\"100%\">\n<tr valign=\"top\">" << tdTag << "\n";1440 }1441 1442 // disable nested links in table of contents1443 inContents = true;1444 inLink = true;1445 1446 for (int i = 0; i < toc.size(); ++i) {1447 Atom *atom = toc.at(i);1448 1449 int nextLevel = atom->string().toInt();1450 if (nextLevel > (int)sectioningUnit)1451 continue;1452 1453 if (sectionNumber.size() < nextLevel) {1454 do {1455 out() << "<ul>";1456 sectionNumber.append("1");1457 } while (sectionNumber.size() < nextLevel);1458 } else {1459 while (sectionNumber.size() > nextLevel) {1460 out() << "</ul>\n";1461 sectionNumber.removeLast();1462 }1463 sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);1464 }1465 int numAtoms;1466 Text headingText = Text::sectionHeading(atom);1467 1468 if (sectionNumber.size() == 1 && columnSize > toc.size() / numColumns) {1469 out() << "</ul></td>" << tdTag << "<ul>\n";1470 columnSize = 0;1471 }1472 out() << "<li>";1473 out() << "<a href=\"" << nodeName << "#" << Doc::canonicalTitle(headingText.toString())1474 << "\">";1475 generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);1476 out() << "</a></li>\n";1477 1478 ++columnSize;1479 }1480 while (!sectionNumber.isEmpty()) {1481 out() << "</ul>\n";1482 sectionNumber.removeLast();1483 }1484 1485 if (numColumns > 1)1486 out() << "</td></tr></table></p>\n";1487 1488 inContents = false;1489 inLink = false;1490 }1491 1492 #if 01493 void HtmlGenerator::generateNavigationBar(const NavigationBar& bar,1494 const Node *node,1495 CodeMarker *marker)1496 {1497 if (bar.prev.begin() != 0 || bar.current.begin() != 0 ||1498 bar.next.begin() != 0) {1499 out() << "<p align=\"right\">";1500 if (bar.prev.begin() != 0) {1501 #if 01502 out() << "[<a href=\"" << section.previousBaseName()1503 << ".html\">Prev: ";1504 generateText(section.previousHeading(), node, marker);1505 out() << "</a>]\n";1506 #endif1507 }1508 if (bar.current.begin() != 0) {1509 out() << "[<a href=\"" << "home"1510 << ".html\">Home</a>]\n";1511 }1512 if (bar.next.begin() != 0) {1513 out() << "[<a href=\"" << fileBase(node, bar.next)1514 << ".html\">Next: ";1515 generateText(Text::sectionHeading(bar.next.begin()), node, marker);1516 out() << "</a>]\n";1517 }1518 out() << "</p>\n";1519 }1520 }1521 #endif1522 1523 QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker)1524 {1525 QList<Section> sections;1526 QList<Section>::ConstIterator s;1527 1528 sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay);1529 if (sections.isEmpty())1530 return QString();1531 1532 QString fileName = fileBase(inner) + "-members." + fileExtension(inner);1533 beginSubPage(inner->location(), fileName);1534 QString title = "List of All Members for " + inner->name();1535 generateHeader(title, inner, marker, false);1536 generateTitle(title, Text(), SmallSubTitle, inner, marker);1537 out() << "<p>This is the complete list of members for ";1538 generateFullName(inner, 0, marker);1539 out() << ", including inherited members.</p>\n";1540 1541 Section section = sections.first();1542 generateSectionList(section, 0, marker, CodeMarker::SeparateList);1543 1544 generateFooter();1545 endSubPage();1546 return fileName;1547 }1548 1549 QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker,1550 CodeMarker::Status status)1551 {1552 QList<Section> sections = marker->sections(inner, CodeMarker::Summary, status);1553 QMutableListIterator<Section> j(sections);1554 while (j.hasNext()) {1555 if (j.next().members.size() == 0)1556 j.remove();1557 }1558 if (sections.isEmpty())1559 return QString();1560 1561 int i;1562 1563 QString title;1564 QString fileName;1565 1566 if (status == CodeMarker::Compat) {1567 title = "Qt 3 Support Members for " + inner->name();1568 fileName = fileBase(inner) + "-qt3." + fileExtension(inner);1569 } else {1570 title = "Obsolete Members for " + inner->name();1571 fileName = fileBase(inner) + "-obsolete." + fileExtension(inner);1572 }1573 1574 beginSubPage(inner->location(), fileName);1575 generateHeader(title, inner, marker, false);1576 generateTitle(title, Text(), SmallSubTitle, inner, marker);1577 1578 if (status == CodeMarker::Compat) {1579 out() << "<p><b>The following class members are part of the "1580 "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> "1581 "They are provided to help you port old code to Qt 4. We advise against "1582 "using them in new code.</p>\n";1583 } else {1584 out() << "<p><b>The following class members are obsolete.</b> They are provided to keep "1585 "old source code working. We strongly advise against using them in new "1586 "code.</p>\n";1587 }1588 1589 out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" << protect(inner->name())1590 << " class reference</a></li></ul></p>\n";1591 1592 for (i = 0; i < sections.size(); ++i) {1593 out() << "<h3>" << protect(sections.at(i).name) << "</h3>\n";1594 1595 generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);1596 }1597 1598 sections = marker->sections(inner, CodeMarker::Detailed, status);1599 for (i = 0; i < sections.size(); ++i) {1600 out() << "<hr />\n";1601 out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n";1602 1603 NodeList::ConstIterator m = sections.at(i).members.begin();1604 while (m != sections.at(i).members.end()) {1605 if ((*m)->access() != Node::Private)1606 generateDetailedMember(*m, inner, marker);1607 ++m;1608 }1609 }1610 1611 generateFooter();1612 endSubPage();1613 return fileName;1614 }1615 1616 void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker,1617 const QMap<QString, const Node *> &classMap)1618 {1619 if (classMap.isEmpty())1620 return;1621 1622 QMap<QString, const Node *> topLevel;1623 QMap<QString, const Node *>::ConstIterator c = classMap.begin();1624 while (c != classMap.end()) {1625 const ClassNode *classe = static_cast<const ClassNode *>(*c);1626 if (classe->baseClasses().isEmpty())1627 topLevel.insert(classe->name(), classe);1628 ++c;1629 }1630 1631 QStack<QMap<QString, const Node *> > stack;1632 stack.push(topLevel);1633 1634 out() << "<ul>\n";1635 while (!stack.isEmpty()) {1636 if (stack.top().isEmpty()) {1637 stack.pop();1638 out() << "</ul>\n";1639 } else {1640 const ClassNode *child = static_cast<const ClassNode *>(*stack.top().begin());1641 out() << "<li>";1642 generateFullName(child, relative, marker);1643 out() << "</li>\n";1644 stack.top().erase(stack.top().begin());1645 1646 QMap<QString, const Node *> newTop;1647 foreach (const RelatedClass &d, child->derivedClasses()) {1648 if (d.access != Node::Private)1649 newTop.insert(d.node->name(), d.node);1650 }1651 if (!newTop.isEmpty()) {1652 stack.push(newTop);1653 out() << "<ul>\n";1654 }1655 }1656 }1657 }1658 1659 void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker,1660 const QMap<QString, const Node *> &nodeMap)1661 {1662 out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n";1663 1664 int row = 0;1665 foreach (const QString &name, nodeMap.keys()) {1666 const Node *node = nodeMap[name];1667 1668 if (++row % 2 == 1)1669 out() << "<tr valign=\"top\" class=\"odd\">";1670 else1671 out() << "<tr valign=\"top\" class=\"even\">";1672 out() << "<th>";1673 generateFullName(node, relative, marker);1674 out() << "</th>";1675 1676 if (!(node->type() == Node::Fake)) {1677 Text brief = node->doc().trimmedBriefText(name);1678 if (!brief.isEmpty()) {1679 out() << "<td>";1680 generateText(brief, node, marker);1681 out() << "</td>";1682 }1683 } else {1684 out() << "<td>";1685 out() << protect(node->doc().briefText().toString());1686 out() << "</td>";1687 }1688 out() << "</tr>\n";1689 }1690 out() << "</table></p>\n";1691 }1692 1693 void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker,1694 const QMap<QString, const Node *> &classMap)1695 {1696 const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'1697 const int NumColumns = 4; // number of columns in the result1698 1699 if (classMap.isEmpty())1700 return;1701 1702 /*1703 First, find out the common prefix of all non-namespaced classes.1704 For Qt, the prefix is Q. It can easily be derived from the first1705 and last classes in alphabetical order (QAccel and QXtWidget in Qt 2.1).1706 */1707 int commonPrefixLen = 0;1708 QString commonPrefix;1709 QString first;1710 QString last;1711 1712 QMap<QString, const Node *>::const_iterator iter = classMap.begin();1713 while (iter != classMap.end()) {1714 if (!iter.key().contains("::")) {1715 first = iter.key();1716 break;1717 }1718 ++iter;1719 }1720 1721 if (first.isEmpty())1722 first = classMap.begin().key();1723 1724 iter = classMap.end();1725 while (iter != classMap.begin()) {1726 --iter;1727 if (!iter.key().contains("::")) {1728 last = iter.key();1729 break;1730 }1731 }1732 1733 if (last.isEmpty())1734 last = classMap.begin().key();1735 1736 if (classMap.size() > 1) {1737 while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 11738 && first[commonPrefixLen] == last[commonPrefixLen])1739 ++commonPrefixLen;1740 }1741 1742 commonPrefix = first.left(commonPrefixLen);1743 1744 /*1745 Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z,1746 underscore (_). QAccel will fall in paragraph 10 (A) and1747 QXtWidget in paragraph 33 (X). This is the only place where we1748 assume that NumParagraphs is 37. Each paragraph is a1749 QMap<QString, const Node *>.1750 */1751 QMap<QString, const Node *> paragraph[NumParagraphs];1752 QString paragraphName[NumParagraphs];1753 1754 QMap<QString, const Node *>::ConstIterator c = classMap.begin();1755 while (c != classMap.end()) {1756 QStringList pieces = c.key().split("::");1757 QString key;1758 if (pieces.size() == 1)1759 key = pieces.last().mid(commonPrefixLen).toLower();1760 else1761 key = pieces.last().toLower();1762 1763 int paragraphNo = NumParagraphs - 1;1764 1765 if (key[0].digitValue() != -1) {1766 paragraphNo = key[0].digitValue();1767 } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {1768 paragraphNo = 10 + key[0].unicode() - 'a';1769 }1770 1771 paragraphName[paragraphNo] = key[0].toUpper();1772 paragraph[paragraphNo].insert(key, c.value());1773 ++c;1774 }1775 1776 /*1777 Each paragraph j has a size: paragraph[j].count(). In the1778 discussion, we will assume paragraphs 0 to 5 will have sizes1779 3, 1, 4, 1, 5, 9.1780 1781 We now want to compute the paragraph offset. Paragraphs 0 to 61782 start at offsets 0, 3, 4, 8, 9, 14, 23.1783 */1784 int paragraphOffset[NumParagraphs + 1];1785 int i, j, k;1786 1787 paragraphOffset[0] = 0;1788 for (j = 0; j < NumParagraphs; j++)1789 paragraphOffset[j + 1] = paragraphOffset[j] + paragraph[j].count();1790 1791 int firstOffset[NumColumns + 1];1792 int currentOffset[NumColumns];1793 int currentParagraphNo[NumColumns];1794 int currentOffsetInParagraph[NumColumns];1795 1796 int numRows = (classMap.count() + NumColumns - 1) / NumColumns;1797 int curParagNo = 0;1798 1799 for (i = 0; i < NumColumns; i++) {1800 firstOffset[i] = qMin(i * numRows, classMap.size());1801 currentOffset[i] = firstOffset[i];1802 1803 for (j = curParagNo; j < NumParagraphs; j++) {1804 if (paragraphOffset[j] > firstOffset[i])1805 break;1806 if (paragraphOffset[j] <= firstOffset[i])1807 curParagNo = j;1808 }1809 currentParagraphNo[i] = curParagNo;1810 currentOffsetInParagraph[i] = firstOffset[i] -1811 paragraphOffset[curParagNo];1812 }1813 firstOffset[NumColumns] = classMap.count();1814 1815 out() << "<p><table width=\"100%\">\n";1816 for (k = 0; k < numRows; k++) {1817 out() << "<tr>\n";1818 for (i = 0; i < NumColumns; i++) {1819 if (currentOffset[i] >= firstOffset[i + 1]) {1820 // this column is finished1821 out() << "<td>\n</td>\n";1822 } else {1823 while (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count()) {1824 ++currentParagraphNo[i];1825 currentOffsetInParagraph[i] = 0;1826 }1827 1828 out() << "<td align=\"right\">";1829 if (currentOffsetInParagraph[i] == 0) {1830 // start a new paragraph1831 out() << "<b>" << paragraphName[currentParagraphNo[i]] << " </b>";1832 }1833 out() << "</td>\n";1834 1835 // bad loop1836 QMap<QString, const Node *>::Iterator it;1837 it = paragraph[currentParagraphNo[i]].begin();1838 for (j = 0; j < currentOffsetInParagraph[i]; j++)1839 ++it;1840 1841 out() << "<td>";1842 // Previously, we used generateFullName() for this, but we1843 // require some special formatting.1844 out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">";1845 QStringList pieces = fullName(it.value(), relative, marker).split("::");1846 out() << protect(pieces.last());1847 out() << "</a>";1848 if (pieces.size() > 1) {1849 out() << " (";1850 generateFullName(it.value()->parent(), relative, marker);1851 out() << ")";1852 }1853 out() << "</td>\n";1854 1855 currentOffset[i]++;1856 currentOffsetInParagraph[i]++;1857 }1858 }1859 out() << "</tr>\n";1860 }1861 out() << "</table></p>\n";1862 }1863 1864 void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker)1865 {1866 out() << "<p align=\"center\"><font size=\"+1\"><b>";1867 for (int i = 0; i < 26; i++) {1868 QChar ch('a' + i);1869 out() << QString("<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());1870 }1871 out() << "</b></font></p>\n";1872 1873 char nextLetter = 'a';1874 char currentLetter;1875 1876 #if 11877 out() << "<ul>\n";1878 #endif1879 QMap<QString, QMap<QString, const Node *> >::ConstIterator f = funcIndex.begin();1880 while (f != funcIndex.end()) {1881 #if 11882 out() << "<li>";1883 #else1884 out() << "<p>";1885 #endif1886 out() << protect(f.key()) << ":";1887 1888 currentLetter = f.key()[0].unicode();1889 while (islower(currentLetter) && currentLetter >= nextLetter) {1890 out() << QString("<a name=\"%1\"></a>").arg(nextLetter);1891 nextLetter++;1892 }1893 1894 QMap<QString, const Node *>::ConstIterator s = (*f).begin();1895 while (s != (*f).end()) {1896 out() << " ";1897 generateFullName((*s)->parent(), relative, marker, *s);1898 ++s;1899 }1900 #if 11901 out() << "</li>";1902 #else1903 out() << "</p>";1904 #endif1905 out() << "\n";1906 ++f;1907 }1908 #if 11909 out() << "</ul>\n";1910 #endif1911 }1912 1913 void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker)1914 {1915 QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin();1916 while (it != legaleseTexts.end()) {1917 Text text = it.key();1918 out() << "<hr />\n";1919 generateText(text, relative, marker);1920 out() << "<ul>\n";1921 do {1922 out() << "<li>";1923 generateFullName(it.value(), relative, marker);1924 out() << "</li>\n";1925 ++it;1926 } while (it != legaleseTexts.end() && it.key() == text);1927 out() << "</ul>\n";1928 }1929 }1930 1931 void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative,1932 CodeMarker *marker, CodeMarker::SynopsisStyle style)1933 {1934 QString marked = marker->markedUpSynopsis(node, relative, style);1935 QRegExp templateTag("(<[^@>]*>)");1936 if (marked.indexOf(templateTag) != -1) {1937 QString contents = protect(marked.mid(templateTag.pos(1),1938 templateTag.cap(1).length()));1939 marked.replace(templateTag.pos(1), templateTag.cap(1).length(),1940 contents);1941 }1942 marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>");1943 marked.replace("<@param>", "<i>");1944 marked.replace("</@param>", "</i>");1945 1946 if (style == CodeMarker::Summary)1947 marked.replace("@name>", "b>");1948 1949 if (style == CodeMarker::SeparateList) {1950 QRegExp extraRegExp("<@extra>.*</@extra>");1951 extraRegExp.setMinimal(true);1952 marked.replace(extraRegExp, "");1953 } else {1954 marked.replace("<@extra>", " <tt>");1955 marked.replace("</@extra>", "</tt>");1956 }1957 1958 if (style != CodeMarker::Detailed) {1959 marked.replace("<@type>", "");1960 marked.replace("</@type>", "");1961 }1962 out() << highlightedCode(marked, marker, relative);1963 }1964 1965 void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */)1966 {1967 QMap<const FakeNode *, QMap<QString, FakeNode *> > fakeNodeMap;1968 QMap<QString, const FakeNode *> groupTitlesMap;1969 QMap<QString, FakeNode *> uncategorizedNodeMap;1970 QRegExp singleDigit("\\b([0-9])\\b");1971 1972 const NodeList children = tre->root()->childNodes();1973 foreach (Node *child, children) {1974 if (child->type() == Node::Fake && child != relative) {1975 FakeNode *fakeNode = static_cast<FakeNode *>(child);1976 1977 // Check whether the page is part of a group or is the group1978 // definition page.1979 QString group;1980 bool isGroupPage = false;1981 if (fakeNode->doc().metaCommandsUsed().contains("group")) {1982 group = fakeNode->doc().metaCommandArgs("group")[0];1983 isGroupPage = true;1984 }1985 1986 // there are too many examples; they would clutter the list1987 if (fakeNode->subType() == FakeNode::Example)1988 continue;1989 1990 // not interested either in individual (Qt Designer etc.) manual chapters1991 if (fakeNode->links().contains(Node::ContentsLink))1992 continue;1993 1994 // Discard external nodes.1995 if (fakeNode->subType() == FakeNode::ExternalPage)1996 continue;1997 1998 QString sortKey = fakeNode->fullTitle().toLower();1999 if (sortKey.startsWith("the "))2000 sortKey.remove(0, 4);2001 sortKey.replace(singleDigit, "0\\1");2002 2003 if (!group.isEmpty()) {2004 if (isGroupPage) {2005 // If we encounter a group definition page, we add all2006 // the pages in that group to the list for that group.2007 foreach (Node *member, fakeNode->groupMembers()) {2008 if (member->type() != Node::Fake)2009 continue;2010 FakeNode *page = static_cast<FakeNode *>(member);2011 if (page) {2012 QString sortKey = page->fullTitle().toLower();2013 if (sortKey.startsWith("the "))2014 sortKey.remove(0, 4);2015 sortKey.replace(singleDigit, "0\\1");2016 fakeNodeMap[const_cast<const FakeNode *>(fakeNode)].insert(sortKey, page);2017 groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode);2018 }2019 }2020 } else if (!isGroupPage) {2021 // If we encounter a page that belongs to a group then2022 // we add that page to the list for that group.2023 const FakeNode *groupNode = static_cast<const FakeNode *>(tre->root()->findNode(group, Node::Fake));2024 if (groupNode)2025 fakeNodeMap[groupNode].insert(sortKey, fakeNode);2026 //else2027 // uncategorizedNodeMap.insert(sortKey, fakeNode);2028 }// else2029 // uncategorizedNodeMap.insert(sortKey, fakeNode);2030 }// else2031 // uncategorizedNodeMap.insert(sortKey, fakeNode);2032 }2033 }2034 2035 // We now list all the pages found that belong to groups.2036 // If only certain pages were found for a group, but the definition page2037 // for that group wasn't listed, the list of pages will be intentionally2038 // incomplete. However, if the group definition page was listed, all the2039 // pages in that group are listed for completeness.2040 2041 if (!fakeNodeMap.isEmpty()) {2042 foreach (const QString &groupTitle, groupTitlesMap.keys()) {2043 const FakeNode *groupNode = groupTitlesMap[groupTitle];2044 out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg(2045 linkForNode(groupNode, relative)).arg(2046 protect(groupNode->fullTitle()));2047 2048 if (fakeNodeMap[groupNode].count() == 0)2049 continue;2050 2051 out() << "<ul>\n";2052 2053 foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) {2054 QString title = fakeNode->fullTitle();2055 if (title.startsWith("The "))2056 title.remove(0, 4);2057 out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"2058 << protect(title) << "</a></li>\n";2059 }2060 out() << "</ul>\n";2061 }2062 }2063 2064 if (!uncategorizedNodeMap.isEmpty()) {2065 out() << QString("<h3>Miscellaneous</h3>\n");2066 out() << "<ul>\n";2067 foreach (const FakeNode *fakeNode, uncategorizedNodeMap) {2068 QString title = fakeNode->fullTitle();2069 if (title.startsWith("The "))2070 title.remove(0, 4);2071 out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"2072 << protect(title) << "</a></li>\n";2073 }2074 out() << "</ul>\n";2075 }2076 }2077 2078 void HtmlGenerator::generateSectionList(const Section& section, const Node *relative,2079 CodeMarker *marker, CodeMarker::SynopsisStyle style)2080 {2081 if (!section.members.isEmpty()) {2082 bool twoColumn = false;2083 if (style == CodeMarker::SeparateList) {2084 twoColumn = (section.members.count() >= 16);2085 } else if (section.members.first()->type() == Node::Property) {2086 twoColumn = (section.members.count() >= 5);2087 }2088 if (twoColumn)2089 out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\""2090 " cellspacing=\"0\">\n"2091 << "<tr><td width=\"45%\" valign=\"top\">";2092 out() << "<ul>\n";2093 2094 int i = 0;2095 NodeList::ConstIterator m = section.members.begin();2096 while (m != section.members.end()) {2097 if ((*m)->access() == Node::Private) {2098 ++m;2099 continue;2100 }2101 2102 if (twoColumn && i == (int) (section.members.count() + 1) / 2)2103 out() << "</ul></td><td valign=\"top\"><ul>\n";2104 2105 out() << "<li><div class=\"fn\"></div>";2106 if (style == CodeMarker::Accessors)2107 out() << "<b>";2108 generateSynopsis(*m, relative, marker, style);2109 if (style == CodeMarker::Accessors)2110 out() << "</b>";2111 out() << "</li>\n";2112 i++;2113 ++m;2114 }2115 out() << "</ul>\n";2116 if (twoColumn)2117 out() << "</td></tr>\n</table></p>\n";2118 }2119 2120 if (style == CodeMarker::Summary && !section.inherited.isEmpty()) {2121 out() << "<ul>\n";2122 generateSectionInheritedList(section, relative, marker);2123 out() << "</ul>\n";2124 }2125 }2126 2127 void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative,2128 CodeMarker *marker)2129 {2130 QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin();2131 while (p != section.inherited.end()) {2132 out() << "<li><div class=\"fn\"></div>";2133 out() << (*p).second << " ";2134 if ((*p).second == 1) {2135 out() << section.singularMember;2136 } else {2137 out() << section.pluralMember;2138 }2139 out() << " inherited from <a href=\"" << fileName((*p).first)2140 << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">"2141 << protect(marker->plainFullName((*p).first, relative))2142 << "</a></li>\n";2143 ++p;2144 }2145 }2146 2147 void HtmlGenerator::generateLink(const Atom *atom, const Node * /* relative */, CodeMarker *marker)2148 {2149 static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_");2150 2151 if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {2152 // hack for C++: move () outside of link2153 int k = funcLeftParen.pos(1);2154 out() << protect(atom->string().left(k));2155 if (link.isEmpty()) {2156 if (showBrokenLinks)2157 out() << "</i>";2158 } else {2159 out() << "</a>";2160 }2161 inLink = false;2162 out() << protect(atom->string().mid(k));2163 } else if (marker->recognizeLanguage("Java")) {2164 // hack for Java: remove () and use <tt> when appropriate2165 bool func = atom->string().endsWith("()");2166 bool tt = (func || atom->string().contains(camelCase));2167 if (tt)2168 out() << "<tt>";2169 if (func) {2170 out() << protect(atom->string().left(atom->string().length() - 2));2171 } else {2172 out() << protect(atom->string());2173 }2174 out() << "</tt>";2175 } else {2176 out() << protect(atom->string());2177 }2178 }2179 2180 QString HtmlGenerator::cleanRef(const QString& ref)2181 {2182 QString clean;2183 2184 if (ref.isEmpty())2185 return clean;2186 2187 clean.reserve(ref.size() + 20);2188 const QChar c = ref[0];2189 const uint u = c.unicode();2190 2191 if ((u >= 'a' && u <= 'z') ||2192 (u >= 'A' && u <= 'Z') ||2193 (u >= '0' && u <= '9')) {2194 clean += c;2195 } else if (u == '~') {2196 clean += "dtor.";2197 } else if (u == '_') {2198 clean += "underscore.";2199 } else {2200 clean += "A";2201 }2202 2203 for (int i = 1; i < (int) ref.length(); i++) {2204 const QChar c = ref[i];2205 const uint u = c.unicode();2206 if ((u >= 'a' && u <= 'z') ||2207 (u >= 'A' && u <= 'Z') ||2208 (u >= '0' && u <= '9') || u == '-' ||2209 u == '_' || u == ':' || u == '.') {2210 clean += c;2211 } else if (c.isSpace()) {2212 clean += "-";2213 } else if (u == '!') {2214 clean += "-not";2215 } else if (u == '&') {2216 clean += "-and";2217 } else if (u == '<') {2218 clean += "-lt";2219 } else if (u == '=') {2220 clean += "-eq";2221 } else if (u == '>') {2222 clean += "-gt";2223 } else if (u == '#') {2224 clean += "#";2225 } else {2226 clean += "-";2227 clean += QString::number((int)u, 16);2228 }2229 }2230 return clean;2231 }2232 2233 QString HtmlGenerator::registerRef(const QString& ref)2234 {2235 QString clean = HtmlGenerator::cleanRef(ref);2236 2237 for (;;) {2238 QString& prevRef = refMap[clean.toLower()];2239 if (prevRef.isEmpty()) {2240 prevRef = ref;2241 break;2242 } else if (prevRef == ref) {2243 break;2244 }2245 clean += "x";2246 }2247 return clean;2248 }2249 2250 QString HtmlGenerator::protect(const QString& string)2251 {2252 #define APPEND(x) \2253 if (html.isEmpty()) { \2254 html = string; \2255 html.truncate(i); \2256 } \2257 html += (x);2258 2259 QString html;2260 int n = string.length();2261 2262 for (int i = 0; i < n; ++i) {2263 QChar ch = string.at(i);2264 2265 if (ch == QLatin1Char('&')) {2266 APPEND("&");2267 } else if (ch == QLatin1Char('<')) {2268 APPEND("<");2269 } else if (ch == QLatin1Char('>')) {2270 APPEND(">");2271 } else if (ch == QLatin1Char('"')) {2272 APPEND(""");2273 } else if (ch.unicode() > 0x007F2274 || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))2275 || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {2276 // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator2277 APPEND("&#x");2278 html += QString::number(ch.unicode(), 16);2279 html += QLatin1Char(';');2280 } else {2281 if (!html.isEmpty())2282 html += ch;2283 }2284 }2285 2286 if (!html.isEmpty())2287 return html;2288 return string;2289 2290 #undef APPEND2291 }2292 81 2293 82 static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); … … 2411 200 } 2412 201 202 203 HtmlGenerator::HtmlGenerator() 204 : helpProjectWriter(0), inLink(false), inContents(false), 205 inSectionHeading(false), inTableHeader(false), numTableRows(0), 206 threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"), 207 myTree(0), slow(false), obsoleteLinks(false) 208 { 209 } 210 211 HtmlGenerator::~HtmlGenerator() 212 { 213 if (helpProjectWriter) 214 delete helpProjectWriter; 215 } 216 217 void HtmlGenerator::initializeGenerator(const Config &config) 218 { 219 static const struct { 220 const char *key; 221 const char *left; 222 const char *right; 223 } defaults[] = { 224 { ATOM_FORMATTING_BOLD, "<b>", "</b>" }, 225 { ATOM_FORMATTING_INDEX, "<!--", "-->" }, 226 { ATOM_FORMATTING_ITALIC, "<i>", "</i>" }, 227 { ATOM_FORMATTING_PARAMETER, "<i>", "</i>" }, 228 { ATOM_FORMATTING_SUBSCRIPT, "<sub>", "</sub>" }, 229 { ATOM_FORMATTING_SUPERSCRIPT, "<sup>", "</sup>" }, 230 { ATOM_FORMATTING_TELETYPE, "<tt>", "</tt>" }, 231 { ATOM_FORMATTING_UNDERLINE, "<u>", "</u>" }, 232 { 0, 0, 0 } 233 }; 234 235 Generator::initializeGenerator(config); 236 obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS)); 237 setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); 238 int i = 0; 239 while (defaults[i].key) { 240 formattingLeftMap().insert(defaults[i].key, defaults[i].left); 241 formattingRightMap().insert(defaults[i].key, defaults[i].right); 242 i++; 243 } 244 245 style = config.getString(HtmlGenerator::format() + 246 Config::dot + 247 HTMLGENERATOR_STYLE); 248 postHeader = config.getString(HtmlGenerator::format() + 249 Config::dot + 250 HTMLGENERATOR_POSTHEADER); 251 footer = config.getString(HtmlGenerator::format() + 252 Config::dot + 253 HTMLGENERATOR_FOOTER); 254 address = config.getString(HtmlGenerator::format() + 255 Config::dot + 256 HTMLGENERATOR_ADDRESS); 257 pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + 258 Config::dot + 259 HTMLGENERATOR_GENERATEMACREFS); 260 261 project = config.getString(CONFIG_PROJECT); 262 263 projectDescription = config.getString(CONFIG_DESCRIPTION); 264 if (projectDescription.isEmpty() && !project.isEmpty()) 265 projectDescription = project + " Reference Documentation"; 266 267 projectUrl = config.getString(CONFIG_URL); 268 269 QSet<QString> editionNames = config.subVars(CONFIG_EDITION); 270 QSet<QString>::ConstIterator edition = editionNames.begin(); 271 while (edition != editionNames.end()) { 272 QString editionName = *edition; 273 QStringList editionModules = config.getStringList(CONFIG_EDITION + 274 Config::dot + 275 editionName + 276 Config::dot + 277 "modules"); 278 QStringList editionGroups = config.getStringList(CONFIG_EDITION + 279 Config::dot + 280 editionName + 281 Config::dot + 282 "groups"); 283 284 if (!editionModules.isEmpty()) 285 editionModuleMap[editionName] = editionModules; 286 if (!editionGroups.isEmpty()) 287 editionGroupMap[editionName] = editionGroups; 288 289 ++edition; 290 } 291 292 slow = config.getBool(CONFIG_SLOW); 293 294 stylesheets = config.getStringList(HtmlGenerator::format() + 295 Config::dot + 296 HTMLGENERATOR_STYLESHEETS); 297 customHeadElements = config.getStringList(HtmlGenerator::format() + 298 Config::dot + 299 HTMLGENERATOR_CUSTOMHEADELEMENTS); 300 codeIndent = config.getInt(CONFIG_CODEINDENT); 301 302 helpProjectWriter = new HelpProjectWriter(config, 303 project.toLower() + 304 ".qhp"); 305 } 306 307 void HtmlGenerator::terminateGenerator() 308 { 309 Generator::terminateGenerator(); 310 } 311 312 QString HtmlGenerator::format() 313 { 314 return "HTML"; 315 } 316 317 /*! 318 This is where the html files and dcf files are written. 319 \note The html file generation is done in the base class, 320 PageGenerator::generateTree(). 321 */ 322 void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) 323 { 324 // Copy the stylesheets from the directory containing the qdocconf file. 325 // ### This should be changed to use a special directory in doc/src. 326 QStringList::ConstIterator styleIter = stylesheets.begin(); 327 QDir configPath = QDir::current(); 328 while (styleIter != stylesheets.end()) { 329 QString filePath = configPath.absoluteFilePath(*styleIter); 330 Config::copyFile(Location(), filePath, filePath, outputDir()); 331 ++styleIter; 332 } 333 334 myTree = tree; 335 nonCompatClasses.clear(); 336 mainClasses.clear(); 337 compatClasses.clear(); 338 obsoleteClasses.clear(); 339 moduleClassMap.clear(); 340 moduleNamespaceMap.clear(); 341 funcIndex.clear(); 342 legaleseTexts.clear(); 343 serviceClasses.clear(); 344 findAllClasses(tree->root()); 345 findAllFunctions(tree->root()); 346 findAllLegaleseTexts(tree->root()); 347 findAllNamespaces(tree->root()); 348 #ifdef ZZZ_QDOC_QML 349 findAllQmlClasses(tree->root()); 350 #endif 351 findAllSince(tree->root()); 352 353 PageGenerator::generateTree(tree, marker); 354 355 dcfClassesRoot.ref = "classes.html"; 356 dcfClassesRoot.title = "Classes"; 357 qSort(dcfClassesRoot.subsections); 358 359 dcfOverviewsRoot.ref = "overviews.html"; 360 dcfOverviewsRoot.title = "Overviews"; 361 qSort(dcfOverviewsRoot.subsections); 362 363 dcfExamplesRoot.ref = "examples.html"; 364 dcfExamplesRoot.title = "Tutorial & Examples"; 365 qSort(dcfExamplesRoot.subsections); 366 367 DcfSection qtRoot; 368 appendDcfSubSection(&qtRoot, dcfClassesRoot); 369 appendDcfSubSection(&qtRoot, dcfOverviewsRoot); 370 appendDcfSubSection(&qtRoot, dcfExamplesRoot); 371 372 generateDcf(project.toLower().simplified().replace(" ", "-"), 373 "index.html", 374 projectDescription, qtRoot); 375 generateDcf("designer", 376 "designer-manual.html", 377 "Qt Designer Manual", 378 dcfDesignerRoot); 379 generateDcf("linguist", 380 "linguist-manual.html", 381 "Qt Linguist Manual", 382 dcfLinguistRoot); 383 generateDcf("assistant", 384 "assistant-manual.html", 385 "Qt Assistant Manual", 386 dcfAssistantRoot); 387 generateDcf("qmake", 388 "qmake-manual.html", 389 "qmake Manual", 390 dcfQmakeRoot); 391 392 generateIndex(project.toLower().simplified().replace(" ", "-"), 393 projectUrl, 394 projectDescription); 395 396 helpProjectWriter->generate(myTree); 397 } 398 399 void HtmlGenerator::startText(const Node * /* relative */, 400 CodeMarker * /* marker */) 401 { 402 inLink = false; 403 inContents = false; 404 inSectionHeading = false; 405 inTableHeader = false; 406 numTableRows = 0; 407 threeColumnEnumValueTable = true; 408 link.clear(); 409 sectionNumber.clear(); 410 } 411 412 int HtmlGenerator::generateAtom(const Atom *atom, 413 const Node *relative, 414 CodeMarker *marker) 415 { 416 int skipAhead = 0; 417 static bool in_para = false; 418 419 switch (atom->type()) { 420 case Atom::AbstractLeft: 421 break; 422 case Atom::AbstractRight: 423 break; 424 case Atom::AutoLink: 425 if (!inLink && !inContents && !inSectionHeading) { 426 const Node *node = 0; 427 QString link = getLink(atom, relative, marker, &node); 428 if (!link.isEmpty()) { 429 beginLink(link, node, relative, marker); 430 generateLink(atom, relative, marker); 431 endLink(); 432 } 433 else { 434 out() << protect(atom->string()); 435 } 436 } 437 else { 438 out() << protect(atom->string()); 439 } 440 break; 441 case Atom::BaseName: 442 break; 443 case Atom::BriefLeft: 444 if (relative->type() == Node::Fake) { 445 skipAhead = skipAtoms(atom, Atom::BriefRight); 446 break; 447 } 448 449 out() << "<p>"; 450 if (relative->type() == Node::Property || 451 relative->type() == Node::Variable) { 452 QString str; 453 atom = atom->next(); 454 while (atom != 0 && atom->type() != Atom::BriefRight) { 455 if (atom->type() == Atom::String || 456 atom->type() == Atom::AutoLink) 457 str += atom->string(); 458 skipAhead++; 459 atom = atom->next(); 460 } 461 str[0] = str[0].toLower(); 462 if (str.right(1) == ".") 463 str.truncate(str.length() - 1); 464 out() << "This "; 465 if (relative->type() == Node::Property) 466 out() << "property"; 467 else 468 out() << "variable"; 469 QStringList words = str.split(" "); 470 if (!(words.first() == "contains" || words.first() == "specifies" 471 || words.first() == "describes" || words.first() == "defines" 472 || words.first() == "holds" || words.first() == "determines")) 473 out() << " holds "; 474 else 475 out() << " "; 476 out() << str << "."; 477 } 478 break; 479 case Atom::BriefRight: 480 if (relative->type() != Node::Fake) 481 out() << "</p>\n"; 482 break; 483 case Atom::C: 484 out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE]; 485 if (inLink) { 486 out() << protect(plainCode(atom->string())); 487 } 488 else { 489 out() << highlightedCode(atom->string(), marker, relative); 490 } 491 out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; 492 break; 493 case Atom::Code: 494 out() << "<pre>" 495 << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), 496 marker,relative)) 497 << "</pre>\n"; 498 break; 499 #ifdef QDOC_QML 500 case Atom::Qml: 501 out() << "<pre>" 502 << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), 503 marker,relative)) 504 << "</pre>\n"; 505 break; 506 #endif 507 case Atom::CodeNew: 508 out() << "<p>you can rewrite it as</p>\n" 509 << "<pre>" 510 << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), 511 marker,relative)) 512 << "</pre>\n"; 513 break; 514 case Atom::CodeOld: 515 out() << "<p>For example, if you have code like</p>\n"; 516 // fallthrough 517 case Atom::CodeBad: 518 out() << "<pre><font color=\"#404040\">" 519 << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) 520 << "</font></pre>\n"; 521 break; 522 case Atom::FootnoteLeft: 523 // ### For now 524 if (in_para) { 525 out() << "</p>\n"; 526 in_para = false; 527 } 528 out() << "<!-- "; 529 break; 530 case Atom::FootnoteRight: 531 // ### For now 532 out() << "-->"; 533 break; 534 case Atom::FormatElse: 535 case Atom::FormatEndif: 536 case Atom::FormatIf: 537 break; 538 case Atom::FormattingLeft: 539 out() << formattingLeftMap()[atom->string()]; 540 if (atom->string() == ATOM_FORMATTING_PARAMETER) { 541 if (atom->next() != 0 && atom->next()->type() == Atom::String) { 542 QRegExp subscriptRegExp("([a-z]+)_([0-9n])"); 543 if (subscriptRegExp.exactMatch(atom->next()->string())) { 544 out() << subscriptRegExp.cap(1) << "<sub>" 545 << subscriptRegExp.cap(2) << "</sub>"; 546 skipAhead = 1; 547 } 548 } 549 } 550 break; 551 case Atom::FormattingRight: 552 if (atom->string() == ATOM_FORMATTING_LINK) { 553 endLink(); 554 } 555 else { 556 out() << formattingRightMap()[atom->string()]; 557 } 558 break; 559 case Atom::AnnotatedList: 560 { 561 QList<Node*> values = myTree->groups().values(atom->string()); 562 NodeMap nodeMap; 563 for (int i = 0; i < values.size(); ++i) { 564 const Node* n = values.at(i); 565 if ((n->status() != Node::Internal) && (n->access() != Node::Private)) { 566 nodeMap.insert(n->nameForLists(),n); 567 } 568 } 569 generateAnnotatedList(relative, marker, nodeMap); 570 } 571 break; 572 case Atom::GeneratedList: 573 if (atom->string() == "annotatedclasses") { 574 generateAnnotatedList(relative, marker, nonCompatClasses); 575 } 576 else if (atom->string() == "classes") { 577 generateCompactList(relative, marker, nonCompatClasses); 578 } 579 else if (atom->string().contains("classesbymodule")) { 580 QString arg = atom->string().trimmed(); 581 QString moduleName = atom->string().mid(atom->string().indexOf( 582 "classesbymodule") + 15).trimmed(); 583 if (moduleClassMap.contains(moduleName)) 584 generateAnnotatedList(relative, marker, moduleClassMap[moduleName]); 585 } 586 else if (atom->string().contains("classesbyedition")) { 587 588 QString arg = atom->string().trimmed(); 589 QString editionName = atom->string().mid(atom->string().indexOf( 590 "classesbyedition") + 16).trimmed(); 591 592 if (editionModuleMap.contains(editionName)) { 593 594 // Add all classes in the modules listed for that edition. 595 NodeMap editionClasses; 596 foreach (const QString &moduleName, editionModuleMap[editionName]) { 597 if (moduleClassMap.contains(moduleName)) 598 editionClasses.unite(moduleClassMap[moduleName]); 599 } 600 601 // Add additional groups and remove groups of classes that 602 // should be excluded from the edition. 603 604 QMultiMap <QString, Node *> groups = myTree->groups(); 605 foreach (const QString &groupName, editionGroupMap[editionName]) { 606 QList<Node *> groupClasses; 607 if (groupName.startsWith("-")) { 608 groupClasses = groups.values(groupName.mid(1)); 609 foreach (const Node *node, groupClasses) 610 editionClasses.remove(node->name()); 611 } 612 else { 613 groupClasses = groups.values(groupName); 614 foreach (const Node *node, groupClasses) 615 editionClasses.insert(node->name(), node); 616 } 617 } 618 generateAnnotatedList(relative, marker, editionClasses); 619 } 620 } 621 else if (atom->string() == "classhierarchy") { 622 generateClassHierarchy(relative, marker, nonCompatClasses); 623 } 624 else if (atom->string() == "compatclasses") { 625 generateCompactList(relative, marker, compatClasses); 626 } 627 else if (atom->string() == "obsoleteclasses") { 628 generateCompactList(relative, marker, obsoleteClasses); 629 } 630 else if (atom->string() == "functionindex") { 631 generateFunctionIndex(relative, marker); 632 } 633 else if (atom->string() == "legalese") { 634 generateLegaleseList(relative, marker); 635 } 636 else if (atom->string() == "mainclasses") { 637 generateCompactList(relative, marker, mainClasses); 638 } 639 else if (atom->string() == "services") { 640 generateCompactList(relative, marker, serviceClasses); 641 } 642 else if (atom->string() == "overviews") { 643 generateOverviewList(relative, marker); 644 } 645 else if (atom->string() == "namespaces") { 646 generateAnnotatedList(relative, marker, namespaceIndex); 647 } 648 else if (atom->string() == "related") { 649 const FakeNode *fake = static_cast<const FakeNode *>(relative); 650 if (fake && !fake->groupMembers().isEmpty()) { 651 NodeMap groupMembersMap; 652 foreach (const Node *node, fake->groupMembers()) { 653 if (node->type() == Node::Fake) 654 groupMembersMap[fullName(node, relative, marker)] = node; 655 } 656 generateAnnotatedList(fake, marker, groupMembersMap); 657 } 658 } 659 else if (atom->string() == "relatedinline") { 660 const FakeNode *fake = static_cast<const FakeNode *>(relative); 661 if (fake && !fake->groupMembers().isEmpty()) { 662 // Reverse the list into the original scan order. 663 // Should be sorted. But on what? It may not be a 664 // regular class or page definition. 665 QList<const Node *> list; 666 foreach (const Node *node, fake->groupMembers()) 667 list.prepend(node); 668 foreach (const Node *node, list) 669 generateBody(node, marker); 670 } 671 } 672 break; 673 case Atom::SinceList: 674 { 675 NewSinceMaps::const_iterator nsmap; 676 nsmap = newSinceMaps.find(atom->string()); 677 NewClassMaps::const_iterator ncmap; 678 ncmap = newClassMaps.find(atom->string()); 679 if ((nsmap != newSinceMaps.constEnd()) && !nsmap.value().isEmpty()) { 680 QList<Section> sections; 681 QList<Section>::ConstIterator s; 682 for (int i=0; i<LastSinceType; ++i) 683 sections.append(Section(sinceTitle(i),QString(),QString())); 684 685 NodeMultiMap::const_iterator n = nsmap.value().constBegin(); 686 while (n != nsmap.value().constEnd()) { 687 const Node* node = n.value(); 688 switch (node->type()) { 689 case Node::Namespace: 690 sections[Namespace].appendMember((Node*)node); 691 break; 692 case Node::Class: 693 sections[Class].appendMember((Node*)node); 694 break; 695 case Node::Enum: 696 sections[Enum].appendMember((Node*)node); 697 break; 698 case Node::Typedef: 699 sections[Typedef].appendMember((Node*)node); 700 break; 701 case Node::Function: { 702 const FunctionNode* fn = static_cast<const FunctionNode*>(node); 703 if (fn->isMacro()) 704 sections[Macro].appendMember((Node*)node); 705 else { 706 Node* p = fn->parent(); 707 if (p) { 708 if (p->type() == Node::Class) 709 sections[MemberFunction].appendMember((Node*)node); 710 else if (p->type() == Node::Namespace) { 711 if (p->name().isEmpty()) 712 sections[GlobalFunction].appendMember((Node*)node); 713 else 714 sections[NamespaceFunction].appendMember((Node*)node); 715 } 716 else 717 sections[GlobalFunction].appendMember((Node*)node); 718 } 719 else 720 sections[GlobalFunction].appendMember((Node*)node); 721 } 722 break; 723 } 724 case Node::Property: 725 sections[Property].appendMember((Node*)node); 726 break; 727 case Node::Variable: 728 sections[Variable].appendMember((Node*)node); 729 break; 730 case Node::QmlProperty: 731 sections[QmlProperty].appendMember((Node*)node); 732 break; 733 case Node::QmlSignal: 734 sections[QmlSignal].appendMember((Node*)node); 735 break; 736 case Node::QmlMethod: 737 sections[QmlMethod].appendMember((Node*)node); 738 break; 739 default: 740 break; 741 } 742 ++n; 743 } 744 745 /* 746 First generate the table of contents. 747 */ 748 out() << "<ul>\n"; 749 s = sections.constBegin(); 750 while (s != sections.constEnd()) { 751 if (!(*s).members.isEmpty()) { 752 753 out() << "<li>" 754 << "<a href=\"#" 755 << Doc::canonicalTitle((*s).name) 756 << "\">" 757 << (*s).name 758 << "</a></li>\n"; 759 } 760 ++s; 761 } 762 out() << "</ul>\n"; 763 764 int idx = 0; 765 s = sections.constBegin(); 766 while (s != sections.constEnd()) { 767 if (!(*s).members.isEmpty()) { 768 out() << "<a name=\"" 769 << Doc::canonicalTitle((*s).name) 770 << "\"></a>\n"; 771 out() << "<h3>" << protect((*s).name) << "</h3>\n"; 772 if (idx == Class) 773 generateCompactList(0, marker, ncmap.value(), QString("Q")); 774 else if (idx == MemberFunction) { 775 ParentMaps parentmaps; 776 ParentMaps::iterator pmap; 777 NodeList::const_iterator i = s->members.constBegin(); 778 while (i != s->members.constEnd()) { 779 Node* p = (*i)->parent(); 780 pmap = parentmaps.find(p); 781 if (pmap == parentmaps.end()) 782 pmap = parentmaps.insert(p,NodeMultiMap()); 783 pmap->insert((*i)->name(),(*i)); 784 ++i; 785 } 786 pmap = parentmaps.begin(); 787 while (pmap != parentmaps.end()) { 788 NodeList nlist = pmap->values(); 789 out() << "<p>Class "; 790 791 out() << "<a href=\"" 792 << linkForNode(pmap.key(), 0) 793 << "\">"; 794 QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); 795 out() << protect(pieces.last()); 796 out() << "</a>" << ":</p>\n"; 797 798 generateSection(nlist, 0, marker, CodeMarker::Summary); 799 out() << "<br />"; 800 ++pmap; 801 } 802 } 803 else 804 generateSection(s->members, 0, marker, CodeMarker::Summary); 805 } 806 ++idx; 807 ++s; 808 } 809 } 810 } 811 break; 812 case Atom::Image: 813 case Atom::InlineImage: 814 { 815 QString fileName = imageFileName(relative, atom->string()); 816 QString text; 817 if (atom->next() != 0) 818 text = atom->next()->string(); 819 if (atom->type() == Atom::Image) 820 out() << "<p align=\"center\">"; 821 if (fileName.isEmpty()) { 822 out() << "<font color=\"red\">[Missing image " 823 << protect(atom->string()) << "]</font>"; 824 } 825 else { 826 out() << "<img src=\"" << protect(fileName) << "\""; 827 if (!text.isEmpty()) 828 out() << " alt=\"" << protect(text) << "\""; 829 out() << " />"; 830 helpProjectWriter->addExtraFile(fileName); 831 } 832 if (atom->type() == Atom::Image) 833 out() << "</p>"; 834 } 835 break; 836 case Atom::ImageText: 837 break; 838 case Atom::LegaleseLeft: 839 out() << "<div style=\"padding: 0.5em; background: #e0e0e0; color: black\">"; 840 break; 841 case Atom::LegaleseRight: 842 out() << "</div>"; 843 break; 844 case Atom::LineBreak: 845 out() << "<br />"; 846 break; 847 case Atom::Link: 848 { 849 const Node *node = 0; 850 QString myLink = getLink(atom, relative, marker, &node); 851 if (myLink.isEmpty()) { 852 relative->doc().location().warning(tr("Cannot link to '%1' in %2") 853 .arg(atom->string()) 854 .arg(marker->plainFullName(relative))); 855 } 856 beginLink(myLink, node, relative, marker); 857 skipAhead = 1; 858 } 859 break; 860 case Atom::LinkNode: 861 { 862 const Node *node = CodeMarker::nodeForString(atom->string()); 863 beginLink(linkForNode(node, relative), node, relative, marker); 864 skipAhead = 1; 865 } 866 break; 867 case Atom::ListLeft: 868 if (in_para) { 869 out() << "</p>\n"; 870 in_para = false; 871 } 872 if (atom->string() == ATOM_LIST_BULLET) { 873 out() << "<ul>\n"; 874 } 875 else if (atom->string() == ATOM_LIST_TAG) { 876 out() << "<dl>\n"; 877 } 878 else if (atom->string() == ATOM_LIST_VALUE) { 879 threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); 880 if (threeColumnEnumValueTable) { 881 out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " 882 << "cellspacing=\"1\" width=\"100%\">\n" 883 << "<tr><th width=\"25%\">Constant</th>" 884 << "<th width=\"15%\">Value</th>" 885 << "<th width=\"60%\">Description</th></tr>\n"; 886 } 887 else { 888 out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " 889 << "cellspacing=\"1\" width=\"40%\">\n" 890 << "<tr><th width=\"60%\">Constant</th><th " 891 << "width=\"40%\">Value</th></tr>\n"; 892 } 893 } 894 else { 895 out() << "<ol type="; 896 if (atom->string() == ATOM_LIST_UPPERALPHA) { 897 out() << "\"A\""; 898 } 899 else if (atom->string() == ATOM_LIST_LOWERALPHA) { 900 out() << "\"a\""; 901 } 902 else if (atom->string() == ATOM_LIST_UPPERROMAN) { 903 out() << "\"I\""; 904 } 905 else if (atom->string() == ATOM_LIST_LOWERROMAN) { 906 out() << "\"i\""; 907 } 908 else { // (atom->string() == ATOM_LIST_NUMERIC) 909 out() << "\"1\""; 910 } 911 if (atom->next() != 0 && atom->next()->string().toInt() != 1) 912 out() << " start=\"" << atom->next()->string() << "\""; 913 out() << ">\n"; 914 } 915 break; 916 case Atom::ListItemNumber: 917 break; 918 case Atom::ListTagLeft: 919 if (atom->string() == ATOM_LIST_TAG) { 920 out() << "<dt>"; 921 } 922 else { // (atom->string() == ATOM_LIST_VALUE) 923 // ### Trenton 924 925 out() << "<tr><td valign=\"top\"><tt>" 926 << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(), 927 relative))) 928 << "</tt></td><td align=\"center\" valign=\"top\">"; 929 930 QString itemValue; 931 if (relative->type() == Node::Enum) { 932 const EnumNode *enume = static_cast<const EnumNode *>(relative); 933 itemValue = enume->itemValue(atom->next()->string()); 934 } 935 936 if (itemValue.isEmpty()) 937 out() << "?"; 938 else 939 out() << "<tt>" << protect(itemValue) << "</tt>"; 940 941 skipAhead = 1; 942 } 943 break; 944 case Atom::ListTagRight: 945 if (atom->string() == ATOM_LIST_TAG) 946 out() << "</dt>\n"; 947 break; 948 case Atom::ListItemLeft: 949 if (atom->string() == ATOM_LIST_TAG) { 950 out() << "<dd>"; 951 } 952 else if (atom->string() == ATOM_LIST_VALUE) { 953 if (threeColumnEnumValueTable) { 954 out() << "</td><td valign=\"top\">"; 955 if (matchAhead(atom, Atom::ListItemRight)) 956 out() << " "; 957 } 958 } 959 else { 960 out() << "<li>"; 961 } 962 if (matchAhead(atom, Atom::ParaLeft)) 963 skipAhead = 1; 964 break; 965 case Atom::ListItemRight: 966 if (atom->string() == ATOM_LIST_TAG) { 967 out() << "</dd>\n"; 968 } 969 else if (atom->string() == ATOM_LIST_VALUE) { 970 out() << "</td></tr>\n"; 971 } 972 else { 973 out() << "</li>\n"; 974 } 975 break; 976 case Atom::ListRight: 977 if (atom->string() == ATOM_LIST_BULLET) { 978 out() << "</ul>\n"; 979 } 980 else if (atom->string() == ATOM_LIST_TAG) { 981 out() << "</dl>\n"; 982 } 983 else if (atom->string() == ATOM_LIST_VALUE) { 984 out() << "</table></p>\n"; 985 } 986 else { 987 out() << "</ol>\n"; 988 } 989 break; 990 case Atom::Nop: 991 break; 992 case Atom::ParaLeft: 993 out() << "<p>"; 994 in_para = true; 995 break; 996 case Atom::ParaRight: 997 endLink(); 998 if (in_para) { 999 out() << "</p>\n"; 1000 in_para = false; 1001 } 1002 //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight)) 1003 // out() << "</p>\n"; 1004 break; 1005 case Atom::QuotationLeft: 1006 out() << "<blockquote>"; 1007 break; 1008 case Atom::QuotationRight: 1009 out() << "</blockquote>\n"; 1010 break; 1011 case Atom::RawString: 1012 out() << atom->string(); 1013 break; 1014 case Atom::SectionLeft: 1015 #if 0 1016 { 1017 int nextLevel = atom->string().toInt(); 1018 if (sectionNumber.size() < nextLevel) { 1019 do { 1020 sectionNumber.append("1"); 1021 } while (sectionNumber.size() < nextLevel); 1022 } 1023 else { 1024 while (sectionNumber.size() > nextLevel) { 1025 sectionNumber.removeLast(); 1026 } 1027 sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); 1028 } 1029 out() << "<a name=\"sec-" << sectionNumber.join("-") << "\"></a>\n"; 1030 } 1031 #else 1032 out() << "<a name=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString()) 1033 << "\"></a>\n"; 1034 #endif 1035 break; 1036 case Atom::SectionRight: 1037 break; 1038 case Atom::SectionHeadingLeft: 1039 out() << "<h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">"; 1040 inSectionHeading = true; 1041 break; 1042 case Atom::SectionHeadingRight: 1043 out() << "</h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">\n"; 1044 inSectionHeading = false; 1045 break; 1046 case Atom::SidebarLeft: 1047 break; 1048 case Atom::SidebarRight: 1049 break; 1050 case Atom::String: 1051 if (inLink && !inContents && !inSectionHeading) { 1052 generateLink(atom, relative, marker); 1053 } 1054 else { 1055 out() << protect(atom->string()); 1056 } 1057 break; 1058 case Atom::TableLeft: 1059 if (in_para) { 1060 out() << "</p>\n"; 1061 in_para = false; 1062 } 1063 if (!atom->string().isEmpty()) { 1064 if (atom->string().contains("%")) 1065 out() << "<p><table class=\"generic\" width=\"" << atom->string() << "\" " 1066 << "align=\"center\" cellpadding=\"2\" " 1067 << "cellspacing=\"1\" border=\"0\">\n"; 1068 else { 1069 out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " 1070 << "cellspacing=\"1\" border=\"0\">\n"; 1071 } 1072 } 1073 else { 1074 out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " 1075 << "cellspacing=\"1\" border=\"0\">\n"; 1076 } 1077 numTableRows = 0; 1078 break; 1079 case Atom::TableRight: 1080 out() << "</table></p>\n"; 1081 break; 1082 case Atom::TableHeaderLeft: 1083 out() << "<thead><tr valign=\"top\" class=\"qt-style\">"; 1084 inTableHeader = true; 1085 break; 1086 case Atom::TableHeaderRight: 1087 out() << "</tr>"; 1088 if (matchAhead(atom, Atom::TableHeaderLeft)) { 1089 skipAhead = 1; 1090 out() << "\n<tr valign=\"top\" class=\"qt-style\">"; 1091 } 1092 else { 1093 out() << "</thead>\n"; 1094 inTableHeader = false; 1095 } 1096 break; 1097 case Atom::TableRowLeft: 1098 if (++numTableRows % 2 == 1) 1099 out() << "<tr valign=\"top\" class=\"odd\">"; 1100 else 1101 out() << "<tr valign=\"top\" class=\"even\">"; 1102 break; 1103 case Atom::TableRowRight: 1104 out() << "</tr>\n"; 1105 break; 1106 case Atom::TableItemLeft: 1107 { 1108 if (inTableHeader) 1109 out() << "<th"; 1110 else 1111 out() << "<td"; 1112 1113 QStringList spans = atom->string().split(","); 1114 if (spans.size() == 2) { 1115 if (spans.at(0) != "1") 1116 out() << " colspan=\"" << spans.at(0) << "\""; 1117 if (spans.at(1) != "1") 1118 out() << " rowspan=\"" << spans.at(1) << "\""; 1119 out() << ">"; 1120 } 1121 if (matchAhead(atom, Atom::ParaLeft)) 1122 skipAhead = 1; 1123 } 1124 break; 1125 case Atom::TableItemRight: 1126 if (inTableHeader) 1127 out() << "</th>"; 1128 else 1129 out() << "</td>"; 1130 if (matchAhead(atom, Atom::ParaLeft)) 1131 skipAhead = 1; 1132 break; 1133 case Atom::TableOfContents: 1134 { 1135 int numColumns = 1; 1136 const Node *node = relative; 1137 1138 Doc::SectioningUnit sectioningUnit = Doc::Section4; 1139 QStringList params = atom->string().split(","); 1140 QString columnText = params.at(0); 1141 QStringList pieces = columnText.split(" ", QString::SkipEmptyParts); 1142 if (pieces.size() >= 2) { 1143 columnText = pieces.at(0); 1144 pieces.pop_front(); 1145 QString path = pieces.join(" ").trimmed(); 1146 node = findNodeForTarget(path, relative, marker, atom); 1147 } 1148 1149 if (params.size() == 2) { 1150 numColumns = qMax(columnText.toInt(), numColumns); 1151 sectioningUnit = (Doc::SectioningUnit)params.at(1).toInt(); 1152 } 1153 1154 if (node) 1155 generateTableOfContents(node, 1156 marker, 1157 sectioningUnit, 1158 numColumns, 1159 relative); 1160 } 1161 break; 1162 case Atom::Target: 1163 out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>"; 1164 break; 1165 case Atom::UnhandledFormat: 1166 out() << "<font color=\"red\"><b><Missing HTML></b></font>"; 1167 break; 1168 case Atom::UnknownCommand: 1169 out() << "<font color=\"red\"><b><code>\\" << protect(atom->string()) 1170 << "</code></b></font>"; 1171 break; 1172 #ifdef QDOC_QML 1173 case Atom::QmlText: 1174 case Atom::EndQmlText: 1175 // don't do anything with these. They are just tags. 1176 break; 1177 #endif 1178 default: 1179 unknownAtom(atom); 1180 } 1181 return skipAhead; 1182 } 1183 1184 void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, 1185 CodeMarker *marker) 1186 { 1187 QList<Section> sections; 1188 QList<Section>::ConstIterator s; 1189 1190 const ClassNode *classe = 0; 1191 const NamespaceNode *namespasse = 0; 1192 1193 QString title; 1194 QString rawTitle; 1195 QString fullTitle; 1196 if (inner->type() == Node::Namespace) { 1197 namespasse = static_cast<const NamespaceNode *>(inner); 1198 rawTitle = marker->plainName(inner); 1199 fullTitle = marker->plainFullName(inner); 1200 title = rawTitle + " Namespace Reference"; 1201 } 1202 else if (inner->type() == Node::Class) { 1203 classe = static_cast<const ClassNode *>(inner); 1204 rawTitle = marker->plainName(inner); 1205 fullTitle = marker->plainFullName(inner); 1206 title = rawTitle + " Class Reference"; 1207 } 1208 1209 DcfSection classSection; 1210 classSection.title = title; 1211 classSection.ref = linkForNode(inner, 0); 1212 classSection.keywords += qMakePair(inner->name(), classSection.ref); 1213 1214 Text subtitleText; 1215 if (rawTitle != fullTitle) 1216 subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" 1217 << Atom(Atom::LineBreak); 1218 1219 QString fixedModule = inner->moduleName(); 1220 if (fixedModule == "Qt3SupportLight") 1221 fixedModule = "Qt3Support"; 1222 if (!fixedModule.isEmpty()) 1223 subtitleText << "[" << Atom(Atom::AutoLink, fixedModule) << " module]"; 1224 1225 if (fixedModule.isEmpty()) { 1226 QMultiMap<QString, QString> publicGroups = myTree->publicGroups(); 1227 QList<QString> groupNames = publicGroups.values(inner->name()); 1228 if (!groupNames.isEmpty()) { 1229 qSort(groupNames.begin(), groupNames.end()); 1230 subtitleText << "["; 1231 for (int j=0; j<groupNames.count(); j++) { 1232 subtitleText << Atom(Atom::AutoLink, groupNames[j]); 1233 if (j<groupNames.count()-1) 1234 subtitleText <<", "; 1235 } 1236 subtitleText << "]"; 1237 } 1238 } 1239 1240 generateHeader(title, inner, marker, true); 1241 generateTitle(title, subtitleText, SmallSubTitle, inner, marker); 1242 1243 #ifdef QDOC_QML 1244 if (classe && !classe->qmlElement().isEmpty()) { 1245 generateInstantiatedBy(classe,marker); 1246 } 1247 #endif 1248 1249 generateBrief(inner, marker); 1250 generateIncludes(inner, marker); 1251 generateStatus(inner, marker); 1252 if (classe) { 1253 generateModuleWarning(classe, marker); 1254 generateInherits(classe, marker); 1255 generateInheritedBy(classe, marker); 1256 } 1257 generateThreadSafeness(inner, marker); 1258 generateSince(inner, marker); 1259 1260 out() << "<ul>\n"; 1261 1262 QString membersLink = generateListOfAllMemberFile(inner, marker); 1263 if (!membersLink.isEmpty()) 1264 out() << "<li><a href=\"" << membersLink << "\">" 1265 << "List of all members, including inherited members</a></li>\n"; 1266 1267 QString obsoleteLink = generateLowStatusMemberFile(inner, 1268 marker, 1269 CodeMarker::Obsolete); 1270 if (!obsoleteLink.isEmpty()) 1271 out() << "<li><a href=\"" << obsoleteLink << "\">" 1272 << "Obsolete members</a></li>\n"; 1273 1274 QString compatLink = generateLowStatusMemberFile(inner, 1275 marker, 1276 CodeMarker::Compat); 1277 if (!compatLink.isEmpty()) 1278 out() << "<li><a href=\"" << compatLink << "\">" 1279 << "Qt 3 support members</a></li>\n"; 1280 1281 out() << "</ul>\n"; 1282 1283 bool needOtherSection = false; 1284 1285 sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); 1286 s = sections.begin(); 1287 while (s != sections.end()) { 1288 if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { 1289 if (!s->inherited.isEmpty()) 1290 needOtherSection = true; 1291 } 1292 else { 1293 if (!s->members.isEmpty()) { 1294 out() << "<hr />\n"; 1295 out() << "<a name=\"" 1296 << registerRef((*s).name.toLower()) 1297 << "\"></a>\n"; 1298 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1299 generateSection(s->members, inner, marker, CodeMarker::Summary); 1300 } 1301 if (!s->reimpMembers.isEmpty()) { 1302 QString name = QString("Reimplemented ") + (*s).name; 1303 out() << "<hr />\n"; 1304 out() << "<a name=\"" 1305 << registerRef(name.toLower()) 1306 << "\"></a>\n"; 1307 out() << "<h2>" << protect(name) << "</h2>\n"; 1308 generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); 1309 } 1310 1311 if (!s->inherited.isEmpty()) { 1312 out() << "<ul>\n"; 1313 generateSectionInheritedList(*s, inner, marker, true); 1314 out() << "</ul>\n"; 1315 } 1316 } 1317 ++s; 1318 } 1319 1320 if (needOtherSection) { 1321 out() << "<h3>Additional Inherited Members</h3>\n" 1322 "<ul>\n"; 1323 1324 s = sections.begin(); 1325 while (s != sections.end()) { 1326 if (s->members.isEmpty() && !s->inherited.isEmpty()) 1327 generateSectionInheritedList(*s, inner, marker); 1328 ++s; 1329 } 1330 out() << "</ul>\n"; 1331 } 1332 1333 out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; 1334 1335 if (!inner->doc().isEmpty()) { 1336 out() << "<hr />\n" 1337 << "<h2>" << "Detailed Description" << "</h2>\n"; 1338 generateBody(inner, marker); 1339 generateAlsoList(inner, marker); 1340 } 1341 1342 sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay); 1343 s = sections.begin(); 1344 while (s != sections.end()) { 1345 out() << "<hr />\n"; 1346 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1347 1348 NodeList::ConstIterator m = (*s).members.begin(); 1349 while (m != (*s).members.end()) { 1350 if ((*m)->access() != Node::Private) { // ### check necessary? 1351 if ((*m)->type() != Node::Class) 1352 generateDetailedMember(*m, inner, marker); 1353 else { 1354 out() << "<h3> class "; 1355 generateFullName(*m, inner, marker); 1356 out() << "</h3>"; 1357 generateBrief(*m, marker, inner); 1358 } 1359 1360 QStringList names; 1361 names << (*m)->name(); 1362 if ((*m)->type() == Node::Function) { 1363 const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); 1364 if (func->metaness() == FunctionNode::Ctor || 1365 func->metaness() == FunctionNode::Dtor || 1366 func->overloadNumber() != 1) 1367 names.clear(); 1368 } 1369 else if ((*m)->type() == Node::Property) { 1370 const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); 1371 if (!prop->getters().isEmpty() && 1372 !names.contains(prop->getters().first()->name())) 1373 names << prop->getters().first()->name(); 1374 if (!prop->setters().isEmpty()) 1375 names << prop->setters().first()->name(); 1376 if (!prop->resetters().isEmpty()) 1377 names << prop->resetters().first()->name(); 1378 } 1379 else if ((*m)->type() == Node::Enum) { 1380 const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); 1381 if (enume->flagsType()) 1382 names << enume->flagsType()->name(); 1383 1384 foreach (const QString &enumName, 1385 enume->doc().enumItemNames().toSet() - 1386 enume->doc().omitEnumItemNames().toSet()) 1387 names << plainCode(marker->markedUpEnumValue(enumName, 1388 enume)); 1389 } 1390 foreach (const QString &name, names) 1391 classSection.keywords += qMakePair(name,linkForNode(*m,0)); 1392 } 1393 ++m; 1394 } 1395 ++s; 1396 } 1397 generateFooter(inner); 1398 1399 if (!membersLink.isEmpty()) { 1400 DcfSection membersSection; 1401 membersSection.title = "List of all members"; 1402 membersSection.ref = membersLink; 1403 appendDcfSubSection(&classSection, membersSection); 1404 } 1405 if (!obsoleteLink.isEmpty()) { 1406 DcfSection obsoleteSection; 1407 obsoleteSection.title = "Obsolete members"; 1408 obsoleteSection.ref = obsoleteLink; 1409 appendDcfSubSection(&classSection, obsoleteSection); 1410 } 1411 if (!compatLink.isEmpty()) { 1412 DcfSection compatSection; 1413 compatSection.title = "Qt 3 support members"; 1414 compatSection.ref = compatLink; 1415 appendDcfSubSection(&classSection, compatSection); 1416 } 1417 1418 appendDcfSubSection(&dcfClassesRoot, classSection); 1419 } 1420 1421 void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) 1422 { 1423 SubTitleSize subTitleSize = LargeSubTitle; 1424 DcfSection fakeSection; 1425 fakeSection.title = fake->fullTitle(); 1426 fakeSection.ref = linkForNode(fake, 0); 1427 1428 QList<Section> sections; 1429 QList<Section>::const_iterator s; 1430 1431 QString htmlTitle = fake->fullTitle(); 1432 if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { 1433 subTitleSize = SmallSubTitle; 1434 htmlTitle += " (" + fake->subTitle() + ")"; 1435 } 1436 1437 generateHeader(htmlTitle, fake, marker, true); 1438 generateTitle(fake->fullTitle(), 1439 Text() << fake->subTitle(), 1440 subTitleSize, 1441 fake, 1442 marker); 1443 1444 if (fake->subType() == Node::Module) { 1445 // Generate brief text and status for modules. 1446 generateBrief(fake, marker); 1447 generateStatus(fake, marker); 1448 1449 if (moduleNamespaceMap.contains(fake->name())) { 1450 out() << "<h2>Namespaces</h2>\n"; 1451 generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]); 1452 } 1453 if (moduleClassMap.contains(fake->name())) { 1454 out() << "<h2>Classes</h2>\n"; 1455 generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); 1456 } 1457 } 1458 else if (fake->subType() == Node::HeaderFile) { 1459 // Generate brief text and status for modules. 1460 generateBrief(fake, marker); 1461 generateStatus(fake, marker); 1462 1463 out() << "<ul>\n"; 1464 1465 QString membersLink = generateListOfAllMemberFile(fake, marker); 1466 if (!membersLink.isEmpty()) 1467 out() << "<li><a href=\"" << membersLink << "\">" 1468 << "List of all members, including inherited members</a></li>\n"; 1469 1470 QString obsoleteLink = generateLowStatusMemberFile(fake, 1471 marker, 1472 CodeMarker::Obsolete); 1473 if (!obsoleteLink.isEmpty()) 1474 out() << "<li><a href=\"" << obsoleteLink << "\">" 1475 << "Obsolete members</a></li>\n"; 1476 1477 QString compatLink = generateLowStatusMemberFile(fake, 1478 marker, 1479 CodeMarker::Compat); 1480 if (!compatLink.isEmpty()) 1481 out() << "<li><a href=\"" << compatLink << "\">" 1482 << "Qt 3 support members</a></li>\n"; 1483 1484 out() << "</ul>\n"; 1485 1486 if (!membersLink.isEmpty()) { 1487 DcfSection membersSection; 1488 membersSection.title = "List of all members"; 1489 membersSection.ref = membersLink; 1490 appendDcfSubSection(&fakeSection, membersSection); 1491 } 1492 if (!obsoleteLink.isEmpty()) { 1493 DcfSection obsoleteSection; 1494 obsoleteSection.title = "Obsolete members"; 1495 obsoleteSection.ref = obsoleteLink; 1496 appendDcfSubSection(&fakeSection, obsoleteSection); 1497 } 1498 if (!compatLink.isEmpty()) { 1499 DcfSection compatSection; 1500 compatSection.title = "Qt 3 support members"; 1501 compatSection.ref = compatLink; 1502 appendDcfSubSection(&fakeSection, compatSection); 1503 } 1504 } 1505 #ifdef QDOC_QML 1506 else if (fake->subType() == Node::QmlClass) { 1507 const QmlClassNode* qml_cn = static_cast<const QmlClassNode*>(fake); 1508 const ClassNode* cn = qml_cn->classNode(); 1509 generateQmlInherits(qml_cn, marker); 1510 generateQmlInstantiates(qml_cn, marker); 1511 generateBrief(qml_cn, marker); 1512 sections = marker->qmlSections(qml_cn,CodeMarker::Summary); 1513 s = sections.begin(); 1514 while (s != sections.end()) { 1515 out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; 1516 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1517 generateQmlSummary(*s,fake,marker); 1518 ++s; 1519 } 1520 1521 out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; 1522 out() << "<h2>" << "Detailed Description" << "</h2>\n"; 1523 generateBody(fake, marker); 1524 if (cn) 1525 generateQmlText(cn->doc().body(), cn, marker, fake->name()); 1526 generateAlsoList(fake, marker); 1527 out() << "<hr />\n"; 1528 1529 sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); 1530 s = sections.begin(); 1531 while (s != sections.end()) { 1532 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1533 NodeList::ConstIterator m = (*s).members.begin(); 1534 while (m != (*s).members.end()) { 1535 generateDetailedQmlMember(*m, fake, marker); 1536 out() << "<br />\n"; 1537 fakeSection.keywords += qMakePair((*m)->name(), 1538 linkForNode(*m,0)); 1539 ++m; 1540 } 1541 ++s; 1542 } 1543 generateFooter(fake); 1544 return; 1545 } 1546 #endif 1547 1548 sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); 1549 s = sections.begin(); 1550 while (s != sections.end()) { 1551 out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; 1552 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1553 generateSectionList(*s, fake, marker, CodeMarker::Summary); 1554 ++s; 1555 } 1556 1557 Text brief = fake->doc().briefText(); 1558 if (fake->subType() == Node::Module && !brief.isEmpty()) { 1559 out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; 1560 out() << "<h2>" << "Detailed Description" << "</h2>\n"; 1561 } 1562 1563 generateBody(fake, marker); 1564 generateAlsoList(fake, marker); 1565 1566 if (!fake->groupMembers().isEmpty()) { 1567 NodeMap groupMembersMap; 1568 foreach (const Node *node, fake->groupMembers()) { 1569 if (node->type() == Node::Class || node->type() == Node::Namespace) 1570 groupMembersMap[node->name()] = node; 1571 } 1572 generateAnnotatedList(fake, marker, groupMembersMap); 1573 } 1574 1575 fakeSection.keywords += qMakePair(fakeSection.title, fakeSection.ref); 1576 1577 sections = marker->sections(fake, CodeMarker::Detailed, CodeMarker::Okay); 1578 s = sections.begin(); 1579 while (s != sections.end()) { 1580 out() << "<hr />\n"; 1581 out() << "<h2>" << protect((*s).name) << "</h2>\n"; 1582 1583 NodeList::ConstIterator m = (*s).members.begin(); 1584 while (m != (*s).members.end()) { 1585 generateDetailedMember(*m, fake, marker); 1586 fakeSection.keywords += qMakePair((*m)->name(), linkForNode(*m, 0)); 1587 ++m; 1588 } 1589 ++s; 1590 } 1591 generateFooter(fake); 1592 1593 if (fake->subType() == Node::Example) { 1594 appendDcfSubSection(&dcfExamplesRoot, fakeSection); 1595 } 1596 else if (fake->subType() != Node::File) { 1597 QString contentsPage = fake->links().value(Node::ContentsLink).first; 1598 1599 if (contentsPage == "Qt Designer Manual") { 1600 appendDcfSubSection(&dcfDesignerRoot, fakeSection); 1601 } 1602 else if (contentsPage == "Qt Linguist Manual") { 1603 appendDcfSubSection(&dcfLinguistRoot, fakeSection); 1604 } 1605 else if (contentsPage == "Qt Assistant Manual") { 1606 appendDcfSubSection(&dcfAssistantRoot, fakeSection); 1607 } 1608 else if (contentsPage == "qmake Manual") { 1609 appendDcfSubSection(&dcfQmakeRoot, fakeSection); 1610 } 1611 else { 1612 appendDcfSubSection(&dcfOverviewsRoot, fakeSection); 1613 } 1614 } 1615 } 1616 1617 QString HtmlGenerator::fileExtension(const Node * /* node */) 1618 { 1619 return "html"; 1620 } 1621 1622 void HtmlGenerator::generateHeader(const QString& title, 1623 const Node *node, 1624 CodeMarker *marker, 1625 bool mainPage) 1626 { 1627 out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; 1628 1629 out() << "<!DOCTYPE html\n" 1630 " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" 1631 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"; 1632 1633 QString shortVersion; 1634 if ((project != "Qtopia") && (project != "Qt Extended")) { 1635 shortVersion = project + " " + shortVersion + ": "; 1636 if (node && !node->doc().location().isEmpty()) 1637 out() << "<!-- " << node->doc().location().fileName() << " -->\n"; 1638 1639 shortVersion = myTree->version(); 1640 if (shortVersion.count(QChar('.')) == 2) 1641 shortVersion.truncate(shortVersion.lastIndexOf(QChar('.'))); 1642 if (!shortVersion.isEmpty()) { 1643 if (project == "QSA") 1644 shortVersion = "QSA " + shortVersion + ": "; 1645 else 1646 shortVersion = "Qt " + shortVersion + ": "; 1647 } 1648 } 1649 1650 out() << "<head>\n" 1651 " <title>" << shortVersion << protect(title) << "</title>\n"; 1652 if (!style.isEmpty()) 1653 out() << " <style type=\"text/css\">" << style << "</style>\n"; 1654 1655 const QMap<QString, QString> &metaMap = node->doc().metaTagMap(); 1656 if (!metaMap.isEmpty()) { 1657 QMapIterator<QString, QString> i(metaMap); 1658 while (i.hasNext()) { 1659 i.next(); 1660 out() << " <meta name=\"" << protect(i.key()) << "\" contents=\"" 1661 << protect(i.value()) << "\" />\n"; 1662 } 1663 } 1664 1665 navigationLinks.clear(); 1666 1667 if (node && !node->links().empty()) { 1668 QPair<QString,QString> linkPair; 1669 QPair<QString,QString> anchorPair; 1670 const Node *linkNode; 1671 1672 if (node->links().contains(Node::PreviousLink)) { 1673 linkPair = node->links()[Node::PreviousLink]; 1674 linkNode = findNodeForTarget(linkPair.first, node, marker); 1675 if (!linkNode || linkNode == node) 1676 anchorPair = linkPair; 1677 else 1678 anchorPair = anchorForNode(linkNode); 1679 1680 out() << " <link rel=\"prev\" href=\"" 1681 << anchorPair.first << "\" />\n"; 1682 1683 navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">"; 1684 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) 1685 navigationLinks += protect(anchorPair.second); 1686 else 1687 navigationLinks += protect(linkPair.second); 1688 navigationLinks += "</a>]\n"; 1689 } 1690 if (node->links().contains(Node::ContentsLink)) { 1691 linkPair = node->links()[Node::ContentsLink]; 1692 linkNode = findNodeForTarget(linkPair.first, node, marker); 1693 if (!linkNode || linkNode == node) 1694 anchorPair = linkPair; 1695 else 1696 anchorPair = anchorForNode(linkNode); 1697 1698 out() << " <link rel=\"contents\" href=\"" 1699 << anchorPair.first << "\" />\n"; 1700 1701 navigationLinks += "[<a href=\"" + anchorPair.first + "\">"; 1702 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) 1703 navigationLinks += protect(anchorPair.second); 1704 else 1705 navigationLinks += protect(linkPair.second); 1706 navigationLinks += "</a>]\n"; 1707 } 1708 if (node->links().contains(Node::NextLink)) { 1709 linkPair = node->links()[Node::NextLink]; 1710 linkNode = findNodeForTarget(linkPair.first, node, marker); 1711 if (!linkNode || linkNode == node) 1712 anchorPair = linkPair; 1713 else 1714 anchorPair = anchorForNode(linkNode); 1715 1716 out() << " <link rel=\"next\" href=\"" 1717 << anchorPair.first << "\" />\n"; 1718 1719 navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">"; 1720 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) 1721 navigationLinks += protect(anchorPair.second); 1722 else 1723 navigationLinks += protect(linkPair.second); 1724 navigationLinks += "</a>]\n"; 1725 } 1726 if (node->links().contains(Node::IndexLink)) { 1727 linkPair = node->links()[Node::IndexLink]; 1728 linkNode = findNodeForTarget(linkPair.first, node, marker); 1729 if (!linkNode || linkNode == node) 1730 anchorPair = linkPair; 1731 else 1732 anchorPair = anchorForNode(linkNode); 1733 out() << " <link rel=\"index\" href=\"" 1734 << anchorPair.first << "\" />\n"; 1735 } 1736 if (node->links().contains(Node::StartLink)) { 1737 linkPair = node->links()[Node::StartLink]; 1738 linkNode = findNodeForTarget(linkPair.first, node, marker); 1739 if (!linkNode || linkNode == node) 1740 anchorPair = linkPair; 1741 else 1742 anchorPair = anchorForNode(linkNode); 1743 out() << " <link rel=\"start\" href=\"" 1744 << anchorPair.first << "\" />\n"; 1745 } 1746 } 1747 1748 foreach (const QString &stylesheet, stylesheets) { 1749 out() << " <link href=\"" << stylesheet << "\" rel=\"stylesheet\" " 1750 << "type=\"text/css\" />\n"; 1751 } 1752 1753 foreach (const QString &customHeadElement, customHeadElements) { 1754 out() << " " << customHeadElement << "\n"; 1755 } 1756 1757 out() << "</head>\n" 1758 "<body>\n"; 1759 if (mainPage) 1760 generateMacRef(node, marker); 1761 out() << QString(postHeader).replace("\\" + COMMAND_VERSION, myTree->version()); 1762 1763 1764 if (node && !node->links().empty()) 1765 out() << "<p>\n" << navigationLinks << "</p>\n"; 1766 } 1767 1768 void HtmlGenerator::generateTitle(const QString& title, 1769 const Text &subTitle, 1770 SubTitleSize subTitleSize, 1771 const Node *relative, 1772 CodeMarker *marker) 1773 { 1774 out() << "<h1 class=\"title\">" << protect(title); 1775 if (!subTitle.isEmpty()) { 1776 out() << "<br />"; 1777 if (subTitleSize == SmallSubTitle) 1778 out() << "<span class=\"small-subtitle\">"; 1779 else 1780 out() << "<span class=\"subtitle\">"; 1781 generateText(subTitle, relative, marker); 1782 out() << "</span>\n"; 1783 } 1784 out() << "</h1>\n"; 1785 } 1786 1787 void HtmlGenerator::generateFooter(const Node *node) 1788 { 1789 if (node && !node->links().empty()) 1790 out() << "<p>\n" << navigationLinks << "</p>\n"; 1791 1792 out() << QString(footer).replace("\\" + COMMAND_VERSION, myTree->version()) 1793 << QString(address).replace("\\" + COMMAND_VERSION, myTree->version()) 1794 << "</body>\n" 1795 "</html>\n"; 1796 } 1797 1798 void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, 1799 const Node *relative) 1800 { 1801 Text brief = node->doc().briefText(); 1802 if (!brief.isEmpty()) { 1803 out() << "<p>"; 1804 generateText(brief, node, marker); 1805 if (!relative || node == relative) 1806 out() << " <a href=\"#"; 1807 else 1808 out() << " <a href=\"" << linkForNode(node, relative) << "#"; 1809 out() << registerRef("details") << "\">More...</a></p>\n"; 1810 } 1811 } 1812 1813 void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) 1814 { 1815 if (!inner->includes().isEmpty()) { 1816 out() << "<pre>" 1817 << trimmedTrailing(highlightedCode(indent(codeIndent, 1818 marker->markedUpIncludes(inner->includes())), 1819 marker,inner)) 1820 << "</pre>"; 1821 } 1822 } 1823 1824 void HtmlGenerator::generateTableOfContents(const Node *node, 1825 CodeMarker *marker, 1826 Doc::SectioningUnit sectioningUnit, 1827 int numColumns, 1828 const Node *relative) 1829 1830 { 1831 if (!node->doc().hasTableOfContents()) 1832 return; 1833 QList<Atom *> toc = node->doc().tableOfContents(); 1834 if (toc.isEmpty()) 1835 return; 1836 1837 QString nodeName = ""; 1838 if (node != relative) 1839 nodeName = node->name(); 1840 1841 QStringList sectionNumber; 1842 int columnSize = 0; 1843 1844 QString tdTag; 1845 if (numColumns > 1) { 1846 tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">"; 1847 out() << "<p><table class=\"toc\" width=\"100%\">\n<tr valign=\"top\">" 1848 << tdTag << "\n"; 1849 } 1850 1851 // disable nested links in table of contents 1852 inContents = true; 1853 inLink = true; 1854 1855 for (int i = 0; i < toc.size(); ++i) { 1856 Atom *atom = toc.at(i); 1857 1858 int nextLevel = atom->string().toInt(); 1859 if (nextLevel > (int)sectioningUnit) 1860 continue; 1861 1862 if (sectionNumber.size() < nextLevel) { 1863 do { 1864 out() << "<ul>"; 1865 sectionNumber.append("1"); 1866 } while (sectionNumber.size() < nextLevel); 1867 } 1868 else { 1869 while (sectionNumber.size() > nextLevel) { 1870 out() << "</ul>\n"; 1871 sectionNumber.removeLast(); 1872 } 1873 sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); 1874 } 1875 int numAtoms; 1876 Text headingText = Text::sectionHeading(atom); 1877 1878 if (sectionNumber.size() == 1 && columnSize > toc.size() / numColumns) { 1879 out() << "</ul></td>" << tdTag << "<ul>\n"; 1880 columnSize = 0; 1881 } 1882 out() << "<li>"; 1883 out() << "<a href=\"" 1884 << nodeName 1885 << "#" 1886 << Doc::canonicalTitle(headingText.toString()) 1887 << "\">"; 1888 generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); 1889 out() << "</a></li>\n"; 1890 1891 ++columnSize; 1892 } 1893 while (!sectionNumber.isEmpty()) { 1894 out() << "</ul>\n"; 1895 sectionNumber.removeLast(); 1896 } 1897 1898 if (numColumns > 1) 1899 out() << "</td></tr></table></p>\n"; 1900 1901 inContents = false; 1902 inLink = false; 1903 } 1904 1905 #if 0 1906 void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, 1907 const Node *node, 1908 CodeMarker *marker) 1909 { 1910 if (bar.prev.begin() != 0 || bar.current.begin() != 0 || 1911 bar.next.begin() != 0) { 1912 out() << "<p align=\"right\">"; 1913 if (bar.prev.begin() != 0) { 1914 #if 0 1915 out() << "[<a href=\"" << section.previousBaseName() 1916 << ".html\">Prev: "; 1917 generateText(section.previousHeading(), node, marker); 1918 out() << "</a>]\n"; 1919 #endif 1920 } 1921 if (bar.current.begin() != 0) { 1922 out() << "[<a href=\"" << "home" 1923 << ".html\">Home</a>]\n"; 1924 } 1925 if (bar.next.begin() != 0) { 1926 out() << "[<a href=\"" << fileBase(node, bar.next) 1927 << ".html\">Next: "; 1928 generateText(Text::sectionHeading(bar.next.begin()), node, marker); 1929 out() << "</a>]\n"; 1930 } 1931 out() << "</p>\n"; 1932 } 1933 } 1934 #endif 1935 1936 QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, 1937 CodeMarker *marker) 1938 { 1939 QList<Section> sections; 1940 QList<Section>::ConstIterator s; 1941 1942 sections = marker->sections(inner, 1943 CodeMarker::SeparateList, 1944 CodeMarker::Okay); 1945 if (sections.isEmpty()) 1946 return QString(); 1947 1948 QString fileName = fileBase(inner) + "-members." + fileExtension(inner); 1949 beginSubPage(inner->location(), fileName); 1950 QString title = "List of All Members for " + inner->name(); 1951 generateHeader(title, inner, marker, false); 1952 generateTitle(title, Text(), SmallSubTitle, inner, marker); 1953 out() << "<p>This is the complete list of members for "; 1954 generateFullName(inner, 0, marker); 1955 out() << ", including inherited members.</p>\n"; 1956 1957 Section section = sections.first(); 1958 generateSectionList(section, 0, marker, CodeMarker::SeparateList); 1959 1960 generateFooter(); 1961 endSubPage(); 1962 return fileName; 1963 } 1964 1965 QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, 1966 CodeMarker *marker, 1967 CodeMarker::Status status) 1968 { 1969 QList<Section> sections = marker->sections(inner, 1970 CodeMarker::Summary, 1971 status); 1972 QMutableListIterator<Section> j(sections); 1973 while (j.hasNext()) { 1974 if (j.next().members.size() == 0) 1975 j.remove(); 1976 } 1977 if (sections.isEmpty()) 1978 return QString(); 1979 1980 int i; 1981 1982 QString title; 1983 QString fileName; 1984 1985 if (status == CodeMarker::Compat) { 1986 title = "Qt 3 Support Members for " + inner->name(); 1987 fileName = fileBase(inner) + "-qt3." + fileExtension(inner); 1988 } 1989 else { 1990 title = "Obsolete Members for " + inner->name(); 1991 fileName = fileBase(inner) + "-obsolete." + fileExtension(inner); 1992 } 1993 1994 beginSubPage(inner->location(), fileName); 1995 generateHeader(title, inner, marker, false); 1996 generateTitle(title, Text(), SmallSubTitle, inner, marker); 1997 1998 if (status == CodeMarker::Compat) { 1999 out() << "<p><b>The following class members are part of the " 2000 "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> " 2001 "They are provided to help you port old code to Qt 4. We advise against " 2002 "using them in new code.</p>\n"; 2003 } 2004 else { 2005 out() << "<p><b>The following class members are obsolete.</b> " 2006 << "They are provided to keep old source code working. " 2007 << "We strongly advise against using them in new code.</p>\n"; 2008 } 2009 2010 out() << "<p><ul><li><a href=\"" 2011 << linkForNode(inner, 0) << "\">" 2012 << protect(inner->name()) 2013 << " class reference</a></li></ul></p>\n"; 2014 2015 for (i = 0; i < sections.size(); ++i) { 2016 out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; 2017 generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); 2018 } 2019 2020 sections = marker->sections(inner, CodeMarker::Detailed, status); 2021 for (i = 0; i < sections.size(); ++i) { 2022 out() << "<hr />\n"; 2023 out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; 2024 2025 NodeList::ConstIterator m = sections.at(i).members.begin(); 2026 while (m != sections.at(i).members.end()) { 2027 if ((*m)->access() != Node::Private) 2028 generateDetailedMember(*m, inner, marker); 2029 ++m; 2030 } 2031 } 2032 2033 generateFooter(); 2034 endSubPage(); 2035 return fileName; 2036 } 2037 2038 void HtmlGenerator::generateClassHierarchy(const Node *relative, 2039 CodeMarker *marker, 2040 const QMap<QString,const Node*> &classMap) 2041 { 2042 if (classMap.isEmpty()) 2043 return; 2044 2045 NodeMap topLevel; 2046 NodeMap::ConstIterator c = classMap.begin(); 2047 while (c != classMap.end()) { 2048 const ClassNode *classe = static_cast<const ClassNode *>(*c); 2049 if (classe->baseClasses().isEmpty()) 2050 topLevel.insert(classe->name(), classe); 2051 ++c; 2052 } 2053 2054 QStack<NodeMap > stack; 2055 stack.push(topLevel); 2056 2057 out() << "<ul>\n"; 2058 while (!stack.isEmpty()) { 2059 if (stack.top().isEmpty()) { 2060 stack.pop(); 2061 out() << "</ul>\n"; 2062 } 2063 else { 2064 const ClassNode *child = 2065 static_cast<const ClassNode *>(*stack.top().begin()); 2066 out() << "<li>"; 2067 generateFullName(child, relative, marker); 2068 out() << "</li>\n"; 2069 stack.top().erase(stack.top().begin()); 2070 2071 NodeMap newTop; 2072 foreach (const RelatedClass &d, child->derivedClasses()) { 2073 if (d.access != Node::Private) 2074 newTop.insert(d.node->name(), d.node); 2075 } 2076 if (!newTop.isEmpty()) { 2077 stack.push(newTop); 2078 out() << "<ul>\n"; 2079 } 2080 } 2081 } 2082 } 2083 2084 void HtmlGenerator::generateAnnotatedList(const Node *relative, 2085 CodeMarker *marker, 2086 const NodeMap &nodeMap) 2087 { 2088 out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" " 2089 << "cellspacing=\"1\" border=\"0\">\n"; 2090 2091 int row = 0; 2092 foreach (const QString &name, nodeMap.keys()) { 2093 const Node *node = nodeMap[name]; 2094 2095 if (node->status() == Node::Obsolete) 2096 continue; 2097 2098 if (++row % 2 == 1) 2099 out() << "<tr valign=\"top\" class=\"odd\">"; 2100 else 2101 out() << "<tr valign=\"top\" class=\"even\">"; 2102 out() << "<th>"; 2103 generateFullName(node, relative, marker); 2104 out() << "</th>"; 2105 2106 if (!(node->type() == Node::Fake)) { 2107 Text brief = node->doc().trimmedBriefText(name); 2108 if (!brief.isEmpty()) { 2109 out() << "<td>"; 2110 generateText(brief, node, marker); 2111 out() << "</td>"; 2112 } 2113 } 2114 else { 2115 out() << "<td>"; 2116 out() << protect(node->doc().briefText().toString()); 2117 out() << "</td>"; 2118 } 2119 out() << "</tr>\n"; 2120 } 2121 out() << "</table></p>\n"; 2122 } 2123 2124 /*! 2125 This function finds the common prefix of the names of all 2126 the classes in \a classMap and then generates a compact 2127 list of the class names alphabetized on the part of the 2128 name not including the common prefix. You can tell the 2129 function to use \a comonPrefix as the common prefix, but 2130 normally you let it figure it out itself by looking at 2131 the name of the first and last classes in \a classMap. 2132 */ 2133 void HtmlGenerator::generateCompactList(const Node *relative, 2134 CodeMarker *marker, 2135 const NodeMap &classMap, 2136 QString commonPrefix) 2137 { 2138 const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' 2139 const int NumColumns = 4; // number of columns in the result 2140 2141 if (classMap.isEmpty()) 2142 return; 2143 2144 /* 2145 If commonPrefix is not empty, then the caller knows what 2146 the common prefix is and has passed it in, so just use that 2147 one. 2148 */ 2149 int commonPrefixLen = commonPrefix.length(); 2150 if (commonPrefixLen == 0) { 2151 QString first; 2152 QString last; 2153 2154 /* 2155 The caller didn't pass in a common prefix, so get the common 2156 prefix by looking at the class names of the first and last 2157 classes in the class map. Discard any namespace names and 2158 just use the bare class names. For Qt, the prefix is "Q". 2159 2160 Note that the algorithm used here to derive the common prefix 2161 from the first and last classes in alphabetical order (QAccel 2162 and QXtWidget in Qt 2.1), fails if either class name does not 2163 begin with Q. 2164 */ 2165 2166 NodeMap::const_iterator iter = classMap.begin(); 2167 while (iter != classMap.end()) { 2168 if (!iter.key().contains("::")) { 2169 first = iter.key(); 2170 break; 2171 } 2172 ++iter; 2173 } 2174 2175 if (first.isEmpty()) 2176 first = classMap.begin().key(); 2177 2178 iter = classMap.end(); 2179 while (iter != classMap.begin()) { 2180 --iter; 2181 if (!iter.key().contains("::")) { 2182 last = iter.key(); 2183 break; 2184 } 2185 } 2186 2187 if (last.isEmpty()) 2188 last = classMap.begin().key(); 2189 2190 if (classMap.size() > 1) { 2191 while (commonPrefixLen < first.length() + 1 && 2192 commonPrefixLen < last.length() + 1 && 2193 first[commonPrefixLen] == last[commonPrefixLen]) 2194 ++commonPrefixLen; 2195 } 2196 2197 commonPrefix = first.left(commonPrefixLen); 2198 } 2199 2200 /* 2201 Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z, 2202 underscore (_). QAccel will fall in paragraph 10 (A) and 2203 QXtWidget in paragraph 33 (X). This is the only place where we 2204 assume that NumParagraphs is 37. Each paragraph is a NodeMap. 2205 */ 2206 NodeMap paragraph[NumParagraphs+1]; 2207 QString paragraphName[NumParagraphs+1]; 2208 2209 NodeMap::ConstIterator c = classMap.begin(); 2210 while (c != classMap.end()) { 2211 QStringList pieces = c.key().split("::"); 2212 QString key; 2213 int idx = commonPrefixLen; 2214 if (!pieces.last().startsWith(commonPrefix)) 2215 idx = 0; 2216 if (pieces.size() == 1) 2217 key = pieces.last().mid(idx).toLower(); 2218 else 2219 key = pieces.last().toLower(); 2220 2221 int paragraphNo = NumParagraphs - 1; 2222 2223 if (key[0].digitValue() != -1) { 2224 paragraphNo = key[0].digitValue(); 2225 } 2226 else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { 2227 paragraphNo = 10 + key[0].unicode() - 'a'; 2228 } 2229 2230 paragraphName[paragraphNo] = key[0].toUpper(); 2231 paragraph[paragraphNo].insert(key, c.value()); 2232 ++c; 2233 } 2234 2235 /* 2236 Each paragraph j has a size: paragraph[j].count(). In the 2237 discussion, we will assume paragraphs 0 to 5 will have sizes 2238 3, 1, 4, 1, 5, 9. 2239 2240 We now want to compute the paragraph offset. Paragraphs 0 to 6 2241 start at offsets 0, 3, 4, 8, 9, 14, 23. 2242 */ 2243 int paragraphOffset[NumParagraphs + 1]; // 37 + 1 2244 int i, j, k; 2245 2246 paragraphOffset[0] = 0; 2247 for (j = 0; j < NumParagraphs; j++) // j = 0..36 2248 paragraphOffset[j + 1] = paragraphOffset[j] + paragraph[j].count(); 2249 2250 int firstOffset[NumColumns + 1]; // 4 + 1 2251 int currentOffset[NumColumns]; // 4 2252 int currentParagraphNo[NumColumns]; // 4 2253 int currentOffsetInParagraph[NumColumns]; // 4 2254 2255 int numRows = (classMap.count() + NumColumns - 1) / NumColumns; 2256 int curParagNo = 0; 2257 2258 for (i = 0; i < NumColumns; i++) { // i = 0..3 2259 firstOffset[i] = qMin(i * numRows, classMap.size()); 2260 currentOffset[i] = firstOffset[i]; 2261 2262 for (j = curParagNo; j < NumParagraphs; j++) { 2263 if (paragraphOffset[j] > firstOffset[i]) 2264 break; 2265 if (paragraphOffset[j] <= firstOffset[i]) 2266 curParagNo = j; 2267 } 2268 currentParagraphNo[i] = curParagNo; 2269 currentOffsetInParagraph[i] = firstOffset[i] - 2270 paragraphOffset[curParagNo]; 2271 } 2272 firstOffset[NumColumns] = classMap.count(); 2273 2274 out() << "<p><table class=\"generic\" width=\"100%\">\n"; 2275 for (k = 0; k < numRows; k++) { 2276 out() << "<tr>\n"; 2277 for (i = 0; i < NumColumns; i++) { 2278 if (currentOffset[i] >= firstOffset[i + 1]) { 2279 // this column is finished 2280 out() << "<td>\n</td>\n"; 2281 } 2282 else { 2283 while ((currentParagraphNo[i] < NumParagraphs) && 2284 (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count())) { 2285 ++currentParagraphNo[i]; 2286 currentOffsetInParagraph[i] = 0; 2287 } 2288 #if 0 2289 if (currentParagraphNo[i] >= NumParagraphs) { 2290 qDebug() << "### Internal error ###" << __FILE__ << __LINE__ 2291 << currentParagraphNo[i] << NumParagraphs; 2292 currentParagraphNo[i] = NumParagraphs - 1; 2293 } 2294 #endif 2295 out() << "<td align=\"right\">"; 2296 if (currentOffsetInParagraph[i] == 0) { 2297 // start a new paragraph 2298 out() << "<b>" 2299 << paragraphName[currentParagraphNo[i]] 2300 << " </b>"; 2301 } 2302 out() << "</td>\n"; 2303 2304 out() << "<td>"; 2305 if ((currentParagraphNo[i] < NumParagraphs) && 2306 !paragraphName[currentParagraphNo[i]].isEmpty()) { 2307 NodeMap::Iterator it; 2308 it = paragraph[currentParagraphNo[i]].begin(); 2309 for (j = 0; j < currentOffsetInParagraph[i]; j++) 2310 ++it; 2311 2312 // Previously, we used generateFullName() for this, but we 2313 // require some special formatting. 2314 out() << "<a href=\"" 2315 << linkForNode(it.value(), relative) 2316 << "\">"; 2317 QStringList pieces = fullName(it.value(), relative, marker).split("::"); 2318 out() << protect(pieces.last()); 2319 out() << "</a>"; 2320 if (pieces.size() > 1) { 2321 out() << " ("; 2322 generateFullName(it.value()->parent(), relative, marker); 2323 out() << ")"; 2324 } 2325 } 2326 out() << "</td>\n"; 2327 2328 currentOffset[i]++; 2329 currentOffsetInParagraph[i]++; 2330 } 2331 } 2332 out() << "</tr>\n"; 2333 } 2334 out() << "</table></p>\n"; 2335 } 2336 2337 void HtmlGenerator::generateFunctionIndex(const Node *relative, 2338 CodeMarker *marker) 2339 { 2340 out() << "<p align=\"center\"><font size=\"+1\"><b>"; 2341 for (int i = 0; i < 26; i++) { 2342 QChar ch('a' + i); 2343 out() << QString("<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper()); 2344 } 2345 out() << "</b></font></p>\n"; 2346 2347 char nextLetter = 'a'; 2348 char currentLetter; 2349 2350 #if 1 2351 out() << "<ul>\n"; 2352 #endif 2353 QMap<QString, NodeMap >::ConstIterator f = funcIndex.begin(); 2354 while (f != funcIndex.end()) { 2355 #if 1 2356 out() << "<li>"; 2357 #else 2358 out() << "<p>"; 2359 #endif 2360 out() << protect(f.key()) << ":"; 2361 2362 currentLetter = f.key()[0].unicode(); 2363 while (islower(currentLetter) && currentLetter >= nextLetter) { 2364 out() << QString("<a name=\"%1\"></a>").arg(nextLetter); 2365 nextLetter++; 2366 } 2367 2368 NodeMap::ConstIterator s = (*f).begin(); 2369 while (s != (*f).end()) { 2370 out() << " "; 2371 generateFullName((*s)->parent(), relative, marker, *s); 2372 ++s; 2373 } 2374 #if 1 2375 out() << "</li>"; 2376 #else 2377 out() << "</p>"; 2378 #endif 2379 out() << "\n"; 2380 ++f; 2381 } 2382 #if 1 2383 out() << "</ul>\n"; 2384 #endif 2385 } 2386 2387 void HtmlGenerator::generateLegaleseList(const Node *relative, 2388 CodeMarker *marker) 2389 { 2390 QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin(); 2391 while (it != legaleseTexts.end()) { 2392 Text text = it.key(); 2393 out() << "<hr />\n"; 2394 generateText(text, relative, marker); 2395 out() << "<ul>\n"; 2396 do { 2397 out() << "<li>"; 2398 generateFullName(it.value(), relative, marker); 2399 out() << "</li>\n"; 2400 ++it; 2401 } while (it != legaleseTexts.end() && it.key() == text); 2402 out() << "</ul>\n"; 2403 } 2404 } 2405 2406 /*void HtmlGenerator::generateSynopsis(const Node *node, 2407 const Node *relative, 2408 CodeMarker *marker, 2409 CodeMarker::SynopsisStyle style) 2410 { 2411 QString marked = marker->markedUpSynopsis(node, relative, style); 2412 QRegExp templateTag("(<[^@>]*>)"); 2413 if (marked.indexOf(templateTag) != -1) { 2414 QString contents = protect(marked.mid(templateTag.pos(1), 2415 templateTag.cap(1).length())); 2416 marked.replace(templateTag.pos(1), templateTag.cap(1).length(), 2417 contents); 2418 } 2419 marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), 2420 "<i>\\1<sub>\\2</sub></i>"); 2421 marked.replace("<@param>", "<i>"); 2422 marked.replace("</@param>", "</i>"); 2423 2424 if (style == CodeMarker::Summary) 2425 marked.replace("@name>", "b>"); 2426 2427 if (style == CodeMarker::SeparateList) { 2428 QRegExp extraRegExp("<@extra>.*</@extra>"); 2429 extraRegExp.setMinimal(true); 2430 marked.replace(extraRegExp, ""); 2431 } 2432 else { 2433 marked.replace("<@extra>", " <tt>"); 2434 marked.replace("</@extra>", "</tt>"); 2435 } 2436 2437 if (style != CodeMarker::Detailed) { 2438 marked.replace("<@type>", ""); 2439 marked.replace("</@type>", ""); 2440 } 2441 out() << highlightedCode(marked, marker, relative); 2442 }*/ 2443 2444 #ifdef QDOC_QML 2445 void HtmlGenerator::generateQmlItem(const Node *node, 2446 const Node *relative, 2447 CodeMarker *marker, 2448 bool summary) 2449 { 2450 QString marked = marker->markedUpQmlItem(node,summary); 2451 QRegExp templateTag("(<[^@>]*>)"); 2452 if (marked.indexOf(templateTag) != -1) { 2453 QString contents = protect(marked.mid(templateTag.pos(1), 2454 templateTag.cap(1).length())); 2455 marked.replace(templateTag.pos(1), templateTag.cap(1).length(), 2456 contents); 2457 } 2458 marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), 2459 "<i>\\1<sub>\\2</sub></i>"); 2460 marked.replace("<@param>", "<i>"); 2461 marked.replace("</@param>", "</i>"); 2462 2463 if (summary) 2464 marked.replace("@name>", "b>"); 2465 2466 marked.replace("<@extra>", " <tt>"); 2467 marked.replace("</@extra>", "</tt>"); 2468 2469 if (summary) { 2470 marked.replace("<@type>", ""); 2471 marked.replace("</@type>", ""); 2472 } 2473 out() << highlightedCode(marked, marker, relative); 2474 } 2475 #endif 2476 2477 void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) 2478 { 2479 QMap<const FakeNode *, QMap<QString, FakeNode *> > fakeNodeMap; 2480 QMap<QString, const FakeNode *> groupTitlesMap; 2481 QMap<QString, FakeNode *> uncategorizedNodeMap; 2482 QRegExp singleDigit("\\b([0-9])\\b"); 2483 2484 const NodeList children = myTree->root()->childNodes(); 2485 foreach (Node *child, children) { 2486 if (child->type() == Node::Fake && child != relative) { 2487 FakeNode *fakeNode = static_cast<FakeNode *>(child); 2488 2489 // Check whether the page is part of a group or is the group 2490 // definition page. 2491 QString group; 2492 bool isGroupPage = false; 2493 if (fakeNode->doc().metaCommandsUsed().contains("group")) { 2494 group = fakeNode->doc().metaCommandArgs("group")[0]; 2495 isGroupPage = true; 2496 } 2497 2498 // there are too many examples; they would clutter the list 2499 if (fakeNode->subType() == Node::Example) 2500 continue; 2501 2502 // not interested either in individual (Qt Designer etc.) manual chapters 2503 if (fakeNode->links().contains(Node::ContentsLink)) 2504 continue; 2505 2506 // Discard external nodes. 2507 if (fakeNode->subType() == Node::ExternalPage) 2508 continue; 2509 2510 QString sortKey = fakeNode->fullTitle().toLower(); 2511 if (sortKey.startsWith("the ")) 2512 sortKey.remove(0, 4); 2513 sortKey.replace(singleDigit, "0\\1"); 2514 2515 if (!group.isEmpty()) { 2516 if (isGroupPage) { 2517 // If we encounter a group definition page, we add all 2518 // the pages in that group to the list for that group. 2519 foreach (Node *member, fakeNode->groupMembers()) { 2520 if (member->type() != Node::Fake) 2521 continue; 2522 FakeNode *page = static_cast<FakeNode *>(member); 2523 if (page) { 2524 QString sortKey = page->fullTitle().toLower(); 2525 if (sortKey.startsWith("the ")) 2526 sortKey.remove(0, 4); 2527 sortKey.replace(singleDigit, "0\\1"); 2528 fakeNodeMap[const_cast<const FakeNode *>(fakeNode)].insert(sortKey, page); 2529 groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode); 2530 } 2531 } 2532 } 2533 else if (!isGroupPage) { 2534 // If we encounter a page that belongs to a group then 2535 // we add that page to the list for that group. 2536 const FakeNode *groupNode = static_cast<const FakeNode *>(myTree->root()->findNode(group, Node::Fake)); 2537 if (groupNode) 2538 fakeNodeMap[groupNode].insert(sortKey, fakeNode); 2539 //else 2540 // uncategorizedNodeMap.insert(sortKey, fakeNode); 2541 }// else 2542 // uncategorizedNodeMap.insert(sortKey, fakeNode); 2543 }// else 2544 // uncategorizedNodeMap.insert(sortKey, fakeNode); 2545 } 2546 } 2547 2548 // We now list all the pages found that belong to groups. 2549 // If only certain pages were found for a group, but the definition page 2550 // for that group wasn't listed, the list of pages will be intentionally 2551 // incomplete. However, if the group definition page was listed, all the 2552 // pages in that group are listed for completeness. 2553 2554 if (!fakeNodeMap.isEmpty()) { 2555 foreach (const QString &groupTitle, groupTitlesMap.keys()) { 2556 const FakeNode *groupNode = groupTitlesMap[groupTitle]; 2557 out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg( 2558 linkForNode(groupNode, relative)).arg( 2559 protect(groupNode->fullTitle())); 2560 2561 if (fakeNodeMap[groupNode].count() == 0) 2562 continue; 2563 2564 out() << "<ul>\n"; 2565 2566 foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) { 2567 QString title = fakeNode->fullTitle(); 2568 if (title.startsWith("The ")) 2569 title.remove(0, 4); 2570 out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" 2571 << protect(title) << "</a></li>\n"; 2572 } 2573 out() << "</ul>\n"; 2574 } 2575 } 2576 2577 if (!uncategorizedNodeMap.isEmpty()) { 2578 out() << QString("<h3>Miscellaneous</h3>\n"); 2579 out() << "<ul>\n"; 2580 foreach (const FakeNode *fakeNode, uncategorizedNodeMap) { 2581 QString title = fakeNode->fullTitle(); 2582 if (title.startsWith("The ")) 2583 title.remove(0, 4); 2584 out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" 2585 << protect(title) << "</a></li>\n"; 2586 } 2587 out() << "</ul>\n"; 2588 } 2589 } 2590 2591 #ifdef QDOC_NAME_ALIGNMENT 2592 void HtmlGenerator::generateSection(const NodeList& nl, 2593 const Node *relative, 2594 CodeMarker *marker, 2595 CodeMarker::SynopsisStyle style) 2596 { 2597 bool name_alignment = true; 2598 if (!nl.isEmpty()) { 2599 bool twoColumn = false; 2600 if (style == CodeMarker::SeparateList) { 2601 name_alignment = false; 2602 twoColumn = (nl.count() >= 16); 2603 } 2604 else if (nl.first()->type() == Node::Property) { 2605 twoColumn = (nl.count() >= 5); 2606 name_alignment = false; 2607 } 2608 if (name_alignment) { 2609 out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " 2610 << "cellspacing=\"0\" width=\"100%\">\n"; 2611 } 2612 else { 2613 if (twoColumn) 2614 out() << "<p><table class=\"propsummary\" width=\"100%\" " 2615 << "border=\"0\" cellpadding=\"0\"" 2616 << " cellspacing=\"0\">\n" 2617 << "<tr><td width=\"45%\" valign=\"top\">"; 2618 out() << "<ul>\n"; 2619 } 2620 2621 int i = 0; 2622 NodeList::ConstIterator m = nl.begin(); 2623 while (m != nl.end()) { 2624 if ((*m)->access() == Node::Private) { 2625 ++m; 2626 continue; 2627 } 2628 2629 if (name_alignment) { 2630 out() << "<tr><td class=\"memItemLeft\" " 2631 << "align=\"right\" valign=\"top\">"; 2632 } 2633 else { 2634 if (twoColumn && i == (int) (nl.count() + 1) / 2) 2635 out() << "</ul></td><td valign=\"top\"><ul>\n"; 2636 out() << "<li><div class=\"fn\">"; 2637 } 2638 2639 generateSynopsis(*m, relative, marker, style, name_alignment); 2640 if (name_alignment) 2641 out() << "</td></tr>\n"; 2642 else 2643 out() << "</div></li>\n"; 2644 i++; 2645 ++m; 2646 } 2647 if (name_alignment) 2648 out() << "</table>\n"; 2649 else { 2650 out() << "</ul>\n"; 2651 if (twoColumn) 2652 out() << "</td></tr>\n</table></p>\n"; 2653 } 2654 } 2655 } 2656 2657 void HtmlGenerator::generateSectionList(const Section& section, 2658 const Node *relative, 2659 CodeMarker *marker, 2660 CodeMarker::SynopsisStyle style) 2661 { 2662 bool name_alignment = true; 2663 if (!section.members.isEmpty()) { 2664 bool twoColumn = false; 2665 if (style == CodeMarker::SeparateList) { 2666 name_alignment = false; 2667 twoColumn = (section.members.count() >= 16); 2668 } 2669 else if (section.members.first()->type() == Node::Property) { 2670 twoColumn = (section.members.count() >= 5); 2671 name_alignment = false; 2672 } 2673 if (name_alignment) { 2674 out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " 2675 << "cellspacing=\"0\" width=\"100%\">\n"; 2676 } 2677 else { 2678 if (twoColumn) 2679 out() << "<p><table class=\"propsummary\" width=\"100%\" " 2680 << "border=\"0\" cellpadding=\"0\"" 2681 << " cellspacing=\"0\">\n" 2682 << "<tr><td width=\"45%\" valign=\"top\">"; 2683 out() << "<ul>\n"; 2684 } 2685 2686 int i = 0; 2687 NodeList::ConstIterator m = section.members.begin(); 2688 while (m != section.members.end()) { 2689 if ((*m)->access() == Node::Private) { 2690 ++m; 2691 continue; 2692 } 2693 2694 if (name_alignment) { 2695 out() << "<tr><td class=\"memItemLeft\" " 2696 << "align=\"right\" valign=\"top\">"; 2697 } 2698 else { 2699 if (twoColumn && i == (int) (section.members.count() + 1) / 2) 2700 out() << "</ul></td><td valign=\"top\"><ul>\n"; 2701 out() << "<li><div class=\"fn\">"; 2702 } 2703 2704 generateSynopsis(*m, relative, marker, style, name_alignment); 2705 if (name_alignment) 2706 out() << "</td></tr>\n"; 2707 else 2708 out() << "</div></li>\n"; 2709 i++; 2710 ++m; 2711 } 2712 if (name_alignment) 2713 out() << "</table>\n"; 2714 else { 2715 out() << "</ul>\n"; 2716 if (twoColumn) 2717 out() << "</td></tr>\n</table></p>\n"; 2718 } 2719 } 2720 2721 if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { 2722 out() << "<ul>\n"; 2723 generateSectionInheritedList(section, relative, marker, name_alignment); 2724 out() << "</ul>\n"; 2725 } 2726 } 2727 2728 void HtmlGenerator::generateSectionInheritedList(const Section& section, 2729 const Node *relative, 2730 CodeMarker *marker, 2731 bool nameAlignment) 2732 { 2733 QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); 2734 while (p != section.inherited.end()) { 2735 if (nameAlignment) 2736 out() << "<li><div bar=\"2\" class=\"fn\"></div>"; 2737 else 2738 out() << "<li><div class=\"fn\"></div>"; 2739 out() << (*p).second << " "; 2740 if ((*p).second == 1) { 2741 out() << section.singularMember; 2742 } 2743 else { 2744 out() << section.pluralMember; 2745 } 2746 out() << " inherited from <a href=\"" << fileName((*p).first) 2747 << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" 2748 << protect(marker->plainFullName((*p).first, relative)) 2749 << "</a></li>\n"; 2750 ++p; 2751 } 2752 } 2753 2754 void HtmlGenerator::generateSynopsis(const Node *node, 2755 const Node *relative, 2756 CodeMarker *marker, 2757 CodeMarker::SynopsisStyle style, 2758 bool nameAlignment) 2759 { 2760 QString marked = marker->markedUpSynopsis(node, relative, style); 2761 QRegExp templateTag("(<[^@>]*>)"); 2762 if (marked.indexOf(templateTag) != -1) { 2763 QString contents = protect(marked.mid(templateTag.pos(1), 2764 templateTag.cap(1).length())); 2765 marked.replace(templateTag.pos(1), templateTag.cap(1).length(), 2766 contents); 2767 } 2768 marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), 2769 "<i>\\1<sub>\\2</sub></i>"); 2770 marked.replace("<@param>", "<i>"); 2771 marked.replace("</@param>", "</i>"); 2772 2773 if (style == CodeMarker::Summary) { 2774 marked.replace("<@name>", ""); // was "<b>" 2775 marked.replace("</@name>", ""); // was "</b>" 2776 } 2777 2778 if (style == CodeMarker::SeparateList) { 2779 QRegExp extraRegExp("<@extra>.*</@extra>"); 2780 extraRegExp.setMinimal(true); 2781 marked.replace(extraRegExp, ""); 2782 } else { 2783 marked.replace("<@extra>", " <tt>"); 2784 marked.replace("</@extra>", "</tt>"); 2785 } 2786 2787 if (style != CodeMarker::Detailed) { 2788 marked.replace("<@type>", ""); 2789 marked.replace("</@type>", ""); 2790 } 2791 out() << highlightedCode(marked, marker, relative, style, nameAlignment); 2792 } 2793 2413 2794 QString HtmlGenerator::highlightedCode(const QString& markedCode, 2414 2795 CodeMarker *marker, 2415 const Node *relative) 2796 const Node *relative, 2797 CodeMarker::SynopsisStyle , 2798 bool nameAlignment) 2416 2799 { 2417 2800 QString src = markedCode; … … 2425 2808 // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)" 2426 2809 static const QString linkTag("link"); 2810 bool done = false; 2427 2811 for (int i = 0, n = src.size(); i < n;) { 2428 if (src.at(i) == charLangle && src.at(i + 1) == charAt) { 2812 if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { 2813 if (nameAlignment && !done) {// && (i != 0)) Why was this here? 2814 html += "</td><td class=\"memItemRight\" valign=\"bottom\">"; 2815 done = true; 2816 } 2429 2817 i += 2; 2430 2818 if (parseArg(src, linkTag, &i, n, &arg, &par1)) { 2819 html += "<b>"; 2431 2820 QString link = linkForNode( 2432 2821 CodeMarker::nodeForString(par1.toString()), relative); 2433 2822 addLink(link, arg, &html); 2823 html += "</b>"; 2434 2824 } 2435 2825 else { … … 2456 2846 QString link = linkForNode( 2457 2847 marker->resolveTarget(par1.toString(), 2458 tre,2848 myTree, 2459 2849 relative), 2460 2850 relative); … … 2485 2875 par1 = QStringRef(); 2486 2876 QString link = linkForNode( 2487 marker->resolveTarget(arg.toString(), tre, relative),2877 marker->resolveTarget(arg.toString(), myTree, relative), 2488 2878 relative); 2489 2879 addLink(link, arg, &html); … … 2572 2962 } 2573 2963 2964 #else 2965 void HtmlGenerator::generateSectionList(const Section& section, 2966 const Node *relative, 2967 CodeMarker *marker, 2968 CodeMarker::SynopsisStyle style) 2969 { 2970 if (!section.members.isEmpty()) { 2971 bool twoColumn = false; 2972 if (style == CodeMarker::SeparateList) { 2973 twoColumn = (section.members.count() >= 16); 2974 } 2975 else if (section.members.first()->type() == Node::Property) { 2976 twoColumn = (section.members.count() >= 5); 2977 } 2978 if (twoColumn) 2979 out() << "<p><table class=\"generic\" width=\"100%\" border=\"0\" " 2980 << "cellpadding=\"0\" cellspacing=\"0\">\n" 2981 << "<tr><td width=\"45%\" valign=\"top\">"; 2982 out() << "<ul>\n"; 2983 2984 int i = 0; 2985 NodeList::ConstIterator m = section.members.begin(); 2986 while (m != section.members.end()) { 2987 if ((*m)->access() == Node::Private) { 2988 ++m; 2989 continue; 2990 } 2991 2992 if (twoColumn && i == (int) (section.members.count() + 1) / 2) 2993 out() << "</ul></td><td valign=\"top\"><ul>\n"; 2994 2995 out() << "<li><div class=\"fn\"></div>"; 2996 if (style == CodeMarker::Accessors) 2997 out() << "<b>"; 2998 generateSynopsis(*m, relative, marker, style); 2999 if (style == CodeMarker::Accessors) 3000 out() << "</b>"; 3001 out() << "</li>\n"; 3002 i++; 3003 ++m; 3004 } 3005 out() << "</ul>\n"; 3006 if (twoColumn) 3007 out() << "</td></tr>\n</table></p>\n"; 3008 } 3009 3010 if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { 3011 out() << "<ul>\n"; 3012 generateSectionInheritedList(section, relative, marker); 3013 out() << "</ul>\n"; 3014 } 3015 } 3016 3017 void HtmlGenerator::generateSectionInheritedList(const Section& section, 3018 const Node *relative, 3019 CodeMarker *marker) 3020 { 3021 QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); 3022 while (p != section.inherited.end()) { 3023 out() << "<li><div bar=\"2\" class=\"fn\"></div>"; 3024 out() << (*p).second << " "; 3025 if ((*p).second == 1) { 3026 out() << section.singularMember; 3027 } else { 3028 out() << section.pluralMember; 3029 } 3030 out() << " inherited from <a href=\"" << fileName((*p).first) 3031 << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" 3032 << protect(marker->plainFullName((*p).first, relative)) 3033 << "</a></li>\n"; 3034 ++p; 3035 } 3036 } 3037 3038 void HtmlGenerator::generateSynopsis(const Node *node, 3039 const Node *relative, 3040 CodeMarker *marker, 3041 CodeMarker::SynopsisStyle style) 3042 { 3043 QString marked = marker->markedUpSynopsis(node, relative, style); 3044 QRegExp templateTag("(<[^@>]*>)"); 3045 if (marked.indexOf(templateTag) != -1) { 3046 QString contents = protect(marked.mid(templateTag.pos(1), 3047 templateTag.cap(1).length())); 3048 marked.replace(templateTag.pos(1), templateTag.cap(1).length(), 3049 contents); 3050 } 3051 marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); 3052 marked.replace("<@param>", "<i>"); 3053 marked.replace("</@param>", "</i>"); 3054 3055 if (style == CodeMarker::Summary) 3056 marked.replace("@name>", "b>"); 3057 3058 if (style == CodeMarker::SeparateList) { 3059 QRegExp extraRegExp("<@extra>.*</@extra>"); 3060 extraRegExp.setMinimal(true); 3061 marked.replace(extraRegExp, ""); 3062 } else { 3063 marked.replace("<@extra>", " <tt>"); 3064 marked.replace("</@extra>", "</tt>"); 3065 } 3066 3067 if (style != CodeMarker::Detailed) { 3068 marked.replace("<@type>", ""); 3069 marked.replace("</@type>", ""); 3070 } 3071 out() << highlightedCode(marked, marker, relative); 3072 } 3073 3074 QString HtmlGenerator::highlightedCode(const QString& markedCode, 3075 CodeMarker *marker, 3076 const Node *relative) 3077 { 3078 QString src = markedCode; 3079 QString html; 3080 QStringRef arg; 3081 QStringRef par1; 3082 3083 const QChar charLangle = '<'; 3084 const QChar charAt = '@'; 3085 3086 // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)" 3087 static const QString linkTag("link"); 3088 for (int i = 0, n = src.size(); i < n;) { 3089 if (src.at(i) == charLangle && src.at(i + 1) == charAt) { 3090 i += 2; 3091 if (parseArg(src, linkTag, &i, n, &arg, &par1)) { 3092 const Node* node = CodeMarker::nodeForString(par1.toString()); 3093 QString link = linkForNode(node, relative); 3094 addLink(link, arg, &html); 3095 } 3096 else { 3097 html += charLangle; 3098 html += charAt; 3099 } 3100 } 3101 else { 3102 html += src.at(i++); 3103 } 3104 } 3105 3106 if (slow) { 3107 // is this block ever used at all? 3108 // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" 3109 src = html; 3110 html = QString(); 3111 static const QString funcTag("func"); 3112 for (int i = 0, n = src.size(); i < n;) { 3113 if (src.at(i) == charLangle && src.at(i + 1) == charAt) { 3114 i += 2; 3115 if (parseArg(src, funcTag, &i, n, &arg, &par1)) { 3116 QString link = linkForNode( 3117 marker->resolveTarget(par1.toString(), 3118 myTree, 3119 relative), 3120 relative); 3121 addLink(link, arg, &html); 3122 par1 = QStringRef(); 3123 } 3124 else { 3125 html += charLangle; 3126 html += charAt; 3127 } 3128 } 3129 else { 3130 html += src.at(i++); 3131 } 3132 } 3133 } 3134 3135 // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags 3136 src = html; 3137 html = QString(); 3138 static const QString typeTags[] = { "type", "headerfile", "func" }; 3139 for (int i = 0, n = src.size(); i < n;) { 3140 if (src.at(i) == charLangle && src.at(i + 1) == charAt) { 3141 i += 2; 3142 bool handled = false; 3143 for (int k = 0; k != 3; ++k) { 3144 if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) { 3145 par1 = QStringRef(); 3146 QString link = linkForNode( 3147 marker->resolveTarget(arg.toString(), myTree, relative), 3148 relative); 3149 addLink(link, arg, &html); 3150 handled = true; 3151 break; 3152 } 3153 } 3154 if (!handled) { 3155 html += charLangle; 3156 html += charAt; 3157 } 3158 } 3159 else { 3160 html += src.at(i++); 3161 } 3162 } 3163 3164 // replace all 3165 // "<@comment>" -> "<span class=\"comment\">"; 3166 // "<@preprocessor>" -> "<span class=\"preprocessor\">"; 3167 // "<@string>" -> "<span class=\"string\">"; 3168 // "<@char>" -> "<span class=\"char\">"; 3169 // "</@(?:comment|preprocessor|string|char)>" -> "</span>" 3170 src = html; 3171 html = QString(); 3172 static const QString spanTags[] = { 3173 "<@comment>", "<span class=\"comment\">", 3174 "<@preprocessor>", "<span class=\"preprocessor\">", 3175 "<@string>", "<span class=\"string\">", 3176 "<@char>", "<span class=\"char\">", 3177 "</@comment>", "</span>", 3178 "</@preprocessor>","</span>", 3179 "</@string>", "</span>", 3180 "</@char>", "</span>" 3181 // "<@char>", "<font color=blue>", 3182 // "</@char>", "</font>", 3183 // "<@func>", "<font color=green>", 3184 // "</@func>", "</font>", 3185 // "<@id>", "<i>", 3186 // "</@id>", "</i>", 3187 // "<@keyword>", "<b>", 3188 // "</@keyword>", "</b>", 3189 // "<@number>", "<font color=yellow>", 3190 // "</@number>", "</font>", 3191 // "<@op>", "<b>", 3192 // "</@op>", "</b>", 3193 // "<@param>", "<i>", 3194 // "</@param>", "</i>", 3195 // "<@string>", "<font color=green>", 3196 // "</@string>", "</font>", 3197 }; 3198 for (int i = 0, n = src.size(); i < n;) { 3199 if (src.at(i) == charLangle) { 3200 bool handled = false; 3201 for (int k = 0; k != 8; ++k) { 3202 const QString & tag = spanTags[2 * k]; 3203 if (tag == QStringRef(&src, i, tag.length())) { 3204 html += spanTags[2 * k + 1]; 3205 i += tag.length(); 3206 handled = true; 3207 break; 3208 } 3209 } 3210 if (!handled) { 3211 ++i; 3212 if (src.at(i) == charAt || 3213 (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) { 3214 // drop 'our' unknown tags (the ones still containing '@') 3215 while (i < n && src.at(i) != QLatin1Char('>')) 3216 ++i; 3217 ++i; 3218 } 3219 else { 3220 // retain all others 3221 html += charLangle; 3222 } 3223 } 3224 } 3225 else { 3226 html += src.at(i); 3227 ++i; 3228 } 3229 } 3230 3231 return html; 3232 } 3233 #endif 3234 3235 void HtmlGenerator::generateLink(const Atom* atom, 3236 const Node* /* relative */, 3237 CodeMarker* marker) 3238 { 3239 static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); 3240 3241 if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { 3242 // hack for C++: move () outside of link 3243 int k = funcLeftParen.pos(1); 3244 out() << protect(atom->string().left(k)); 3245 if (link.isEmpty()) { 3246 if (showBrokenLinks) 3247 out() << "</i>"; 3248 } else { 3249 out() << "</a>"; 3250 } 3251 inLink = false; 3252 out() << protect(atom->string().mid(k)); 3253 } else if (marker->recognizeLanguage("Java")) { 3254 // hack for Java: remove () and use <tt> when appropriate 3255 bool func = atom->string().endsWith("()"); 3256 bool tt = (func || atom->string().contains(camelCase)); 3257 if (tt) 3258 out() << "<tt>"; 3259 if (func) { 3260 out() << protect(atom->string().left(atom->string().length() - 2)); 3261 } else { 3262 out() << protect(atom->string()); 3263 } 3264 out() << "</tt>"; 3265 } else { 3266 out() << protect(atom->string()); 3267 } 3268 } 3269 3270 QString HtmlGenerator::cleanRef(const QString& ref) 3271 { 3272 QString clean; 3273 3274 if (ref.isEmpty()) 3275 return clean; 3276 3277 clean.reserve(ref.size() + 20); 3278 const QChar c = ref[0]; 3279 const uint u = c.unicode(); 3280 3281 if ((u >= 'a' && u <= 'z') || 3282 (u >= 'A' && u <= 'Z') || 3283 (u >= '0' && u <= '9')) { 3284 clean += c; 3285 } else if (u == '~') { 3286 clean += "dtor."; 3287 } else if (u == '_') { 3288 clean += "underscore."; 3289 } else { 3290 clean += "A"; 3291 } 3292 3293 for (int i = 1; i < (int) ref.length(); i++) { 3294 const QChar c = ref[i]; 3295 const uint u = c.unicode(); 3296 if ((u >= 'a' && u <= 'z') || 3297 (u >= 'A' && u <= 'Z') || 3298 (u >= '0' && u <= '9') || u == '-' || 3299 u == '_' || u == ':' || u == '.') { 3300 clean += c; 3301 } else if (c.isSpace()) { 3302 clean += "-"; 3303 } else if (u == '!') { 3304 clean += "-not"; 3305 } else if (u == '&') { 3306 clean += "-and"; 3307 } else if (u == '<') { 3308 clean += "-lt"; 3309 } else if (u == '=') { 3310 clean += "-eq"; 3311 } else if (u == '>') { 3312 clean += "-gt"; 3313 } else if (u == '#') { 3314 clean += "#"; 3315 } else { 3316 clean += "-"; 3317 clean += QString::number((int)u, 16); 3318 } 3319 } 3320 return clean; 3321 } 3322 3323 QString HtmlGenerator::registerRef(const QString& ref) 3324 { 3325 QString clean = HtmlGenerator::cleanRef(ref); 3326 3327 for (;;) { 3328 QString& prevRef = refMap[clean.toLower()]; 3329 if (prevRef.isEmpty()) { 3330 prevRef = ref; 3331 break; 3332 } else if (prevRef == ref) { 3333 break; 3334 } 3335 clean += "x"; 3336 } 3337 return clean; 3338 } 3339 3340 QString HtmlGenerator::protect(const QString& string) 3341 { 3342 #define APPEND(x) \ 3343 if (html.isEmpty()) { \ 3344 html = string; \ 3345 html.truncate(i); \ 3346 } \ 3347 html += (x); 3348 3349 QString html; 3350 int n = string.length(); 3351 3352 for (int i = 0; i < n; ++i) { 3353 QChar ch = string.at(i); 3354 3355 if (ch == QLatin1Char('&')) { 3356 APPEND("&"); 3357 } else if (ch == QLatin1Char('<')) { 3358 APPEND("<"); 3359 } else if (ch == QLatin1Char('>')) { 3360 APPEND(">"); 3361 } else if (ch == QLatin1Char('"')) { 3362 APPEND("""); 3363 } else if (ch.unicode() > 0x007F 3364 || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) 3365 || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { 3366 // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator 3367 APPEND("&#x"); 3368 html += QString::number(ch.unicode(), 16); 3369 html += QLatin1Char(';'); 3370 } else { 3371 if (!html.isEmpty()) 3372 html += ch; 3373 } 3374 } 3375 3376 if (!html.isEmpty()) 3377 return html; 3378 return string; 3379 3380 #undef APPEND 3381 } 3382 2574 3383 QString HtmlGenerator::fileBase(const Node *node) 2575 3384 { … … 2619 3428 { 2620 3429 if (node->type() == Node::Fake) { 2621 if (static_cast<const FakeNode *>(node)->subType() == FakeNode::ExternalPage)3430 if (static_cast<const FakeNode *>(node)->subType() == Node::ExternalPage) 2622 3431 return node->name(); 2623 } 2624 3432 if (static_cast<const FakeNode *>(node)->subType() == Node::Image) 3433 return node->name(); 3434 } 2625 3435 return PageGenerator::fileName(node); 2626 3436 } … … 2644 3454 if (typedeffe->associatedEnum()) { 2645 3455 return refForNode(typedeffe->associatedEnum()); 2646 } else { 3456 } 3457 else { 2647 3458 ref = node->name() + "-typedef"; 2648 3459 } … … 2652 3463 if (func->associatedProperty()) { 2653 3464 return refForNode(func->associatedProperty()); 2654 } else { 3465 } 3466 else { 2655 3467 ref = func->name(); 2656 3468 if (func->overloadNumber() != 1) … … 2658 3470 } 2659 3471 break; 3472 #ifdef QDOC_QML 3473 case Node::Fake: 3474 if (node->subType() != Node::QmlPropertyGroup) 3475 break; 3476 case Node::QmlProperty: 3477 #endif 2660 3478 case Node::Property: 2661 3479 ref = node->name() + "-prop"; 2662 3480 break; 3481 #ifdef QDOC_QML 3482 case Node::QmlSignal: 3483 ref = node->name() + "-signal"; 3484 break; 3485 case Node::QmlMethod: 3486 ref = node->name() + "-method"; 3487 break; 3488 #endif 2663 3489 case Node::Variable: 2664 3490 ref = node->name() + "-var"; … … 2692 3518 if (fn != outFileName()) 2693 3519 #endif 2694 2695 2696 if (!node->isInnerNode() ) {3520 link += fn; 3521 3522 if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { 2697 3523 ref = refForNode(node); 2698 3524 if (relative && fn == fileName(relative) && ref == refForNode(relative)) … … 2709 3535 if (atom->type() == Atom::SectionLeft) { 2710 3536 return Doc::canonicalTitle(Text::sectionHeading(atom).toString()); 2711 } else if (atom->type() == Atom::Target) { 3537 } 3538 else if (atom->type() == Atom::Target) { 2712 3539 return Doc::canonicalTitle(atom->string()); 2713 } else { 3540 } 3541 else { 2714 3542 return QString(); 2715 3543 } … … 2755 3583 generateSynopsis(enume, relative, marker, CodeMarker::Detailed); 2756 3584 out() << "<br />"; 2757 generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed); 3585 generateSynopsis(enume->flagsType(), 3586 relative, 3587 marker, 3588 CodeMarker::Detailed); 2758 3589 out() << "</h3>\n"; 2759 3590 } … … 2779 3610 2780 3611 if (!section.members.isEmpty()) { 2781 out() << "<p> Access functions:</p>\n";3612 out() << "<p><b>Access functions:</b></p>\n"; 2782 3613 generateSectionList(section, node, marker, CodeMarker::Accessors); 3614 } 3615 3616 Section notifiers; 3617 notifiers.members += property->notifiers(); 3618 3619 if (!notifiers.members.isEmpty()) { 3620 out() << "<p><b>Notifier signal:</b></p>\n"; 3621 //out() << "<p>This signal is emitted when the property value is changed.</p>\n"; 3622 generateSectionList(notifiers, node, marker, CodeMarker::Accessors); 2783 3623 } 2784 3624 } … … 2790 3630 << "<a href=\"qflags.html\">QFlags</a><" 2791 3631 << protect(enume->name()) 2792 << ">. It stores an OR combination of " << protect(enume->name()) 3632 << ">. It stores an OR combination of " 3633 << protect(enume->name()) 2793 3634 << " values.</p>\n"; 2794 3635 } … … 2804 3645 if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { 2805 3646 QString className = (*c)->name(); 2806 if ((*c)->parent() && (*c)->parent()->type() == Node::Namespace && 3647 if ((*c)->parent() && 3648 (*c)->parent()->type() == Node::Namespace && 2807 3649 !(*c)->parent()->name().isEmpty()) 2808 3650 className = (*c)->parent()->name()+"::"+className; … … 2811 3653 if ((*c)->status() == Node::Compat) { 2812 3654 compatClasses.insert(className, *c); 3655 } 3656 else if ((*c)->status() == Node::Obsolete) { 3657 obsoleteClasses.insert(className, *c); 2813 3658 } 2814 3659 else { … … 2840 3685 } 2841 3686 3687 /*! 3688 For generating the "New Classes... in 4.6" section on the 3689 What's New in 4.6" page. 3690 */ 3691 void HtmlGenerator::findAllSince(const InnerNode *node) 3692 { 3693 NodeList::const_iterator child = node->childNodes().constBegin(); 3694 while (child != node->childNodes().constEnd()) { 3695 QString sinceVersion = (*child)->since(); 3696 if (((*child)->access() != Node::Private) && !sinceVersion.isEmpty()) { 3697 NewSinceMaps::iterator nsmap = newSinceMaps.find(sinceVersion); 3698 if (nsmap == newSinceMaps.end()) 3699 nsmap = newSinceMaps.insert(sinceVersion,NodeMultiMap()); 3700 NewClassMaps::iterator ncmap = newClassMaps.find(sinceVersion); 3701 if (ncmap == newClassMaps.end()) 3702 ncmap = newClassMaps.insert(sinceVersion,NodeMap()); 3703 3704 if ((*child)->type() == Node::Function) { 3705 FunctionNode *func = static_cast<FunctionNode *>(*child); 3706 if ((func->status() > Node::Obsolete) && 3707 (func->metaness() != FunctionNode::Ctor) && 3708 (func->metaness() != FunctionNode::Dtor)) { 3709 nsmap.value().insert(func->name(),(*child)); 3710 } 3711 } 3712 else if ((*child)->url().isEmpty()) { 3713 if ((*child)->type() == Node::Class && !(*child)->doc().isEmpty()) { 3714 QString className = (*child)->name(); 3715 if ((*child)->parent() && 3716 (*child)->parent()->type() == Node::Namespace && 3717 !(*child)->parent()->name().isEmpty()) 3718 className = (*child)->parent()->name()+"::"+className; 3719 nsmap.value().insert(className,(*child)); 3720 ncmap.value().insert(className,(*child)); 3721 } 3722 } 3723 else { 3724 QString name = (*child)->name(); 3725 if ((*child)->parent() && 3726 (*child)->parent()->type() == Node::Namespace && 3727 !(*child)->parent()->name().isEmpty()) 3728 name = (*child)->parent()->name()+"::"+name; 3729 nsmap.value().insert(name,(*child)); 3730 } 3731 if ((*child)->isInnerNode()) { 3732 findAllSince(static_cast<InnerNode *>(*child)); 3733 } 3734 } 3735 ++child; 3736 } 3737 } 3738 3739 #if 0 3740 const QRegExp versionSeparator("[\\-\\.]"); 3741 const int minorIndex = version.indexOf(versionSeparator); 3742 const int patchIndex = version.indexOf(versionSeparator, minorIndex+1); 3743 version = version.left(patchIndex); 3744 #endif 3745 2842 3746 void HtmlGenerator::findAllFunctions(const InnerNode *node) 2843 3747 { … … 2850 3754 else if ((*c)->type() == Node::Function) { 2851 3755 const FunctionNode *func = static_cast<const FunctionNode *>(*c); 2852 if (func->status() > Node::Obsolete && func->metaness() != FunctionNode::Ctor 2853 && func->metaness() != FunctionNode::Dtor) { 2854 funcIndex[(*c)->name()].insert((*c)->parent()->name(), *c); 3756 if ((func->status() > Node::Obsolete) && 3757 (func->metaness() != FunctionNode::Ctor) && 3758 (func->metaness() != FunctionNode::Dtor)) { 3759 funcIndex[(*c)->name()].insert(myTree->fullDocumentName((*c)->parent()), *c); 2855 3760 } 2856 3761 } … … 2902 3807 } 2903 3808 2904 #ifdef ZZZ_QDOC_QML 3809 #ifdef ZZZ_QDOC_QML 2905 3810 /*! 2906 3811 This function finds all the qml element nodes and … … 2913 3818 if ((*c)->type() == Node::Fake) { 2914 3819 const FakeNode* fakeNode = static_cast<const FakeNode *>(*c); 2915 if (fakeNode->subType() == FakeNode::QmlClass) {2916 const Qml Node* qmlNode = static_cast<const QmlNode*>(fakeNode);2917 //qDebug() << "HtmlGenerator: QML CLASS" << qmlNode->name();3820 if (fakeNode->subType() == Node::QmlClass) { 3821 const QmlClassNode* qmlNode = 3822 static_cast<const QmlClassNode*>(fakeNode); 2918 3823 const Node* n = qmlNode->classNode(); 2919 if (n)2920 //qDebug() << " FOUND IT!" << n->name();2921 3824 } 2922 3825 qmlClasses.insert(fakeNode->name(),*c); … … 2925 3828 } 2926 3829 } 2927 #endif2928 2929 #if 02930 else if ((*c)->isInnerNode()) {2931 findAllClasses(static_cast<InnerNode *>(*c));2932 }2933 3830 #endif 2934 3831 … … 2974 3871 } 2975 3872 else if (target.endsWith(".html")) { 2976 node = tre->root()->findNode(target, Node::Fake);3873 node = myTree->root()->findNode(target, Node::Fake); 2977 3874 } 2978 3875 else if (marker) { 2979 node = marker->resolveTarget(target, tre, relative);3876 node = marker->resolveTarget(target, myTree, relative); 2980 3877 if (!node) 2981 node = tre->findFakeNodeByTitle(target);3878 node = myTree->findFakeNodeByTitle(target); 2982 3879 if (!node && atom) { 2983 node = tre->findUnambiguousTarget(target,3880 node = myTree->findUnambiguousTarget(target, 2984 3881 *const_cast<Atom**>(&atom)); 2985 3882 } … … 3008 3905 const Node *relative, 3009 3906 CodeMarker *marker, 3010 const Node *node)3907 const Node** node) 3011 3908 { 3012 3909 QString link; 3013 node = 0; 3910 *node = 0; 3911 inObsoleteLink = false; 3014 3912 3015 3913 if (atom->string().contains(":") && … … 3035 3933 QString first = path.first().trimmed(); 3036 3934 if (first.isEmpty()) { 3037 node = relative;3935 *node = relative; 3038 3936 } 3039 3937 else if (first.endsWith(".html")) { 3040 node = tre->root()->findNode(first, Node::Fake);3938 *node = myTree->root()->findNode(first, Node::Fake); 3041 3939 } 3042 3940 else { 3043 node = marker->resolveTarget(first, tre, relative);3044 if (! node)3045 node = tre->findFakeNodeByTitle(first);3046 if (! node)3047 node = tre->findUnambiguousTarget(first, targetAtom);3048 } 3049 3050 if ( node) {3051 if (! node->url().isEmpty())3052 return node->url();3941 *node = marker->resolveTarget(first, myTree, relative); 3942 if (!*node) 3943 *node = myTree->findFakeNodeByTitle(first); 3944 if (!*node) 3945 *node = myTree->findUnambiguousTarget(first, targetAtom); 3946 } 3947 3948 if (*node) { 3949 if (!(*node)->url().isEmpty()) 3950 return (*node)->url(); 3053 3951 else 3054 3952 path.removeFirst(); 3055 3953 } 3056 3954 else { 3057 node = relative; 3955 *node = relative; 3956 } 3957 3958 if (*node) { 3959 if ((*node)->status() == Node::Obsolete) { 3960 if (relative) { 3961 if (relative->parent() != *node) { 3962 if (relative->status() != Node::Obsolete) { 3963 bool porting = false; 3964 if (relative->type() == Node::Fake) { 3965 const FakeNode* fake = static_cast<const FakeNode*>(relative); 3966 if (fake->title().startsWith("Porting")) 3967 porting = true; 3968 } 3969 QString name = marker->plainFullName(relative); 3970 if (!porting && !name.startsWith("Q3")) { 3971 if (obsoleteLinks) { 3972 relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") 3973 .arg(atom->string()) 3974 .arg(name)); 3975 } 3976 inObsoleteLink = true; 3977 } 3978 } 3979 } 3980 } 3981 else { 3982 qDebug() << "Link to Obsolete entity" 3983 << (*node)->name() << "no relative"; 3984 } 3985 } 3986 #if 0 3987 else if ((*node)->status() == Node::Deprecated) { 3988 qDebug() << "Link to Deprecated entity"; 3989 } 3990 else if ((*node)->status() == Node::Internal) { 3991 qDebug() << "Link to Internal entity"; 3992 } 3993 #endif 3058 3994 } 3059 3995 3060 3996 while (!path.isEmpty()) { 3061 targetAtom = tre->findTarget(path.first(),node);3997 targetAtom = myTree->findTarget(path.first(), *node); 3062 3998 if (targetAtom == 0) 3063 3999 break; … … 3066 4002 3067 4003 if (path.isEmpty()) { 3068 link = linkForNode(node, relative); 4004 link = linkForNode(*node, relative); 4005 if (*node && (*node)->subType() == Node::Image) 4006 link = "images/used-in-examples/" + link; 3069 4007 if (targetAtom) 3070 link += "#" + refForAtom(targetAtom, node);4008 link += "#" + refForAtom(targetAtom, *node); 3071 4009 } 3072 4010 } … … 3088 4026 const QString &title) 3089 4027 { 3090 tre->generateIndex(outputDir() + "/" + fileBase + ".index", url, title);4028 myTree->generateIndex(outputDir() + "/" + fileBase + ".index", url, title); 3091 4029 } 3092 4030 … … 3103 4041 if (node->isInnerNode()) { 3104 4042 text << Atom::ParaLeft 3105 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) << "This " 3106 << typeString(node) << " is part of the Qt 3 support library." 4043 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) 4044 << "This " 4045 << typeString(node) 4046 << " is part of the Qt 3 support library." 3107 4047 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) 3108 << " It is provided to keep old source code working. We strongly advise against " 4048 << " It is provided to keep old source code working. " 4049 << "We strongly advise against " 3109 4050 << "using it in new code. See "; 3110 4051 3111 const FakeNode *fakeNode = tre->findFakeNodeByTitle("Porting To Qt 4");4052 const FakeNode *fakeNode = myTree->findFakeNodeByTitle("Porting To Qt 4"); 3112 4053 Atom *targetAtom = 0; 3113 4054 if (fakeNode && node->type() == Node::Class) { 3114 4055 QString oldName(node->name()); 3115 targetAtom = tre->findTarget(oldName.replace("3", ""),3116 fakeNode);4056 targetAtom = myTree->findTarget(oldName.replace("3", ""), 4057 fakeNode); 3117 4058 } 3118 4059 … … 3144 4085 QStringList macRefs = marker->macRefsForNode(node); 3145 4086 foreach (const QString &macRef, macRefs) 3146 out() << "<a name=\"" << "//apple_ref/" << macRef << "\" />\n";4087 out() << "<a name=\"" << "//apple_ref/" << macRef << "\"></a>\n"; 3147 4088 } 3148 4089 … … 3187 4128 } 3188 4129 else { 4130 if (inObsoleteLink) { 4131 out() << "<sup>(obsolete)</sup>"; 4132 } 3189 4133 out() << "</a>"; 3190 4134 } 3191 4135 } 3192 4136 inLink = false; 4137 inObsoleteLink = false; 3193 4138 } 3194 4139 3195 4140 QT_END_NAMESPACE 4141 4142 #ifdef QDOC_QML 4143 4144 /*! 4145 Generates the summary for for the \a section. Only used for 4146 sections of QML element documentation. 4147 4148 Currently handles only the QML property group. 4149 */ 4150 void HtmlGenerator::generateQmlSummary(const Section& section, 4151 const Node *relative, 4152 CodeMarker *marker) 4153 { 4154 if (!section.members.isEmpty()) { 4155 NodeList::ConstIterator m; 4156 int count = section.members.size(); 4157 bool twoColumn = false; 4158 if (section.members.first()->type() == Node::QmlProperty) { 4159 twoColumn = (count >= 5); 4160 } 4161 if (twoColumn) 4162 out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" 4163 " cellspacing=\"0\">\n" 4164 << "<tr><td width=\"45%\" valign=\"top\">"; 4165 out() << "<ul>\n"; 4166 4167 int row = 0; 4168 m = section.members.begin(); 4169 while (m != section.members.end()) { 4170 if (twoColumn && row == (int) (count + 1) / 2) 4171 out() << "</ul></td><td valign=\"top\"><ul>\n"; 4172 out() << "<li><div class=\"fn\"></div>"; 4173 generateQmlItem(*m,relative,marker,true); 4174 out() << "</li>\n"; 4175 row++; 4176 ++m; 4177 } 4178 out() << "</ul>\n"; 4179 if (twoColumn) 4180 out() << "</td></tr>\n</table></p>\n"; 4181 } 4182 } 4183 4184 /*! 4185 Outputs the html detailed documentation for a section 4186 on a QML element reference page. 4187 */ 4188 void HtmlGenerator::generateDetailedQmlMember(const Node *node, 4189 const InnerNode *relative, 4190 CodeMarker *marker) 4191 { 4192 const QmlPropertyNode* qpn = 0; 4193 generateMacRef(node, marker); 4194 out() << "<div class=\"qmlitem\">"; 4195 if (node->subType() == Node::QmlPropertyGroup) { 4196 const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); 4197 NodeList::ConstIterator p = qpgn->childNodes().begin(); 4198 out() << "<div class=\"qmlproto\">"; 4199 out() << "<table width=\"100%\" class=\"qmlname\">"; 4200 4201 while (p != qpgn->childNodes().end()) { 4202 if ((*p)->type() == Node::QmlProperty) { 4203 qpn = static_cast<const QmlPropertyNode*>(*p); 4204 out() << "<tr><td>"; 4205 out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; 4206 if (!qpn->isWritable()) 4207 out() << "<span class=\"qmlreadonly\">read-only</span>"; 4208 generateQmlItem(qpn, relative, marker, false); 4209 out() << "</td></tr>"; 4210 if (qpgn->isDefault()) { 4211 out() << "</table>" 4212 << "</div></div>" 4213 << "<div class=\"qmlitem\">" 4214 << "<div class=\"qmlproto\">" 4215 << "<table class=\"qmlname\">" 4216 << "<tr><td><font color=\"green\">" 4217 << "default</font></td></tr>"; 4218 } 4219 } 4220 ++p; 4221 } 4222 out() << "</table>"; 4223 out() << "</div>"; 4224 } 4225 else if (node->type() == Node::QmlSignal) { 4226 const FunctionNode* qsn = static_cast<const FunctionNode*>(node); 4227 out() << "<div class=\"qmlproto\">"; 4228 out() << "<table class=\"qmlname\">"; 4229 out() << "<tr><td>"; 4230 out() << "<a name=\"" + refForNode(qsn) + "\"></a>"; 4231 generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false); 4232 //generateQmlItem(qsn,relative,marker,false); 4233 out() << "</td></tr>"; 4234 out() << "</table>"; 4235 out() << "</div>"; 4236 } 4237 else if (node->type() == Node::QmlMethod) { 4238 const FunctionNode* qmn = static_cast<const FunctionNode*>(node); 4239 out() << "<div class=\"qmlproto\">"; 4240 out() << "<table class=\"qmlname\">"; 4241 out() << "<tr><td>"; 4242 out() << "<a name=\"" + refForNode(qmn) + "\"></a>"; 4243 generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); 4244 out() << "</td></tr>"; 4245 out() << "</table>"; 4246 out() << "</div>"; 4247 } 4248 out() << "<div class=\"qmldoc\">"; 4249 generateStatus(node, marker); 4250 generateBody(node, marker); 4251 generateThreadSafeness(node, marker); 4252 generateSince(node, marker); 4253 generateAlsoList(node, marker); 4254 out() << "</div>"; 4255 out() << "</div>"; 4256 } 4257 4258 /*! 4259 Output the "Inherits" line for the QML element, 4260 if there should be one. 4261 */ 4262 void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, 4263 CodeMarker* marker) 4264 { 4265 if (cn && !cn->links().empty()) { 4266 if (cn->links().contains(Node::InheritsLink)) { 4267 QPair<QString,QString> linkPair; 4268 linkPair = cn->links()[Node::InheritsLink]; 4269 QStringList strList(linkPair.first); 4270 const Node* n = myTree->findNode(strList,Node::Fake); 4271 if (n && n->subType() == Node::QmlClass) { 4272 const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n); 4273 out() << "<p style=\"text-align: center\">"; 4274 Text text; 4275 text << "[Inherits "; 4276 text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); 4277 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); 4278 text << Atom(Atom::String, linkPair.second); 4279 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); 4280 text << "]"; 4281 generateText(text, cn, marker); 4282 out() << "</p>"; 4283 } 4284 } 4285 } 4286 } 4287 4288 /*! 4289 Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]" 4290 line for the QML element, if there should be one. 4291 4292 If there is no class node, or if the class node status 4293 is set to Node::Internal, do nothing. 4294 */ 4295 void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, 4296 CodeMarker* marker) 4297 { 4298 const ClassNode* cn = qcn->classNode(); 4299 if (cn && (cn->status() != Node::Internal)) { 4300 out() << "<p style=\"text-align: center\">"; 4301 Text text; 4302 text << "["; 4303 text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); 4304 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); 4305 text << Atom(Atom::String, qcn->name()); 4306 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); 4307 text << " instantiates the C++ class "; 4308 text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); 4309 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); 4310 text << Atom(Atom::String, cn->name()); 4311 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); 4312 text << "]"; 4313 generateText(text, qcn, marker); 4314 out() << "</p>"; 4315 } 4316 } 4317 4318 /*! 4319 Output the "[QmlGraphicsXxx is instantiated by QML element Xxx]" 4320 line for the class, if there should be one. 4321 4322 If there is no QML element, or if the class node status 4323 is set to Node::Internal, do nothing. 4324 */ 4325 void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, 4326 CodeMarker* marker) 4327 { 4328 if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { 4329 const Node* n = myTree->root()->findNode(cn->qmlElement(),Node::Fake); 4330 if (n && n->subType() == Node::QmlClass) { 4331 out() << "<p style=\"text-align: center\">"; 4332 Text text; 4333 text << "["; 4334 text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); 4335 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); 4336 text << Atom(Atom::String, cn->name()); 4337 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); 4338 text << " is instantiated by QML element "; 4339 text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n)); 4340 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); 4341 text << Atom(Atom::String, n->name()); 4342 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); 4343 text << "]"; 4344 generateText(text, cn, marker); 4345 out() << "</p>"; 4346 } 4347 } 4348 } 4349 4350 #endif
Note:
See TracChangeset
for help on using the changeset viewer.