diff options
Diffstat (limited to 'tools/qdoc3/htmlgenerator.cpp')
-rw-r--r-- | tools/qdoc3/htmlgenerator.cpp | 1764 |
1 files changed, 1329 insertions, 435 deletions
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 543975e..df63138 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -61,11 +61,132 @@ QT_BEGIN_NAMESPACE static bool showBrokenLinks = false; +static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); +static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); +static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); +static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); +static QRegExp unknownTag("</?@[^>]*>"); + +bool parseArg(const QString &src, + const QString &tag, + int *pos, + int n, + QStringRef *contents, + QStringRef *par1 = 0, + bool debug = false) +{ +#define SKIP_CHAR(c) \ + if (debug) \ + qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ + if (i >= n || src[i] != c) { \ + if (debug) \ + qDebug() << " char '" << c << "' not found"; \ + return false; \ + } \ + ++i; + + +#define SKIP_SPACE \ + while (i < n && src[i] == ' ') \ + ++i; + + int i = *pos; + int j = i; + + // assume "<@" has been parsed outside + //SKIP_CHAR('<'); + //SKIP_CHAR('@'); + + if (tag != QStringRef(&src, i, tag.length())) { + if (0 && debug) + qDebug() << "tag " << tag << " not found at " << i; + return false; + } + + if (debug) + qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; + + // skip tag + i += tag.length(); + + // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); + if (par1) { + SKIP_SPACE; + // read parameter name + j = i; + while (i < n && src[i].isLetter()) + ++i; + if (src[i] == '=') { + if (debug) + qDebug() << "read parameter" << QString(src.data() + j, i - j); + SKIP_CHAR('='); + SKIP_CHAR('"'); + // skip parameter name + j = i; + while (i < n && src[i] != '"') + ++i; + *par1 = QStringRef(&src, j, i - j); + SKIP_CHAR('"'); + SKIP_SPACE; + } else { + if (debug) + qDebug() << "no optional parameter found"; + } + } + SKIP_SPACE; + SKIP_CHAR('>'); + + // find contents up to closing "</@tag> + j = i; + for (; true; ++i) { + if (i + 4 + tag.length() > n) + return false; + if (src[i] != '<') + continue; + if (src[i + 1] != '/') + continue; + if (src[i + 2] != '@') + continue; + if (tag != QStringRef(&src, i + 3, tag.length())) + continue; + if (src[i + 3 + tag.length()] != '>') + continue; + break; + } + + *contents = QStringRef(&src, j, i - j); + + i += tag.length() + 4; + + *pos = i; + if (debug) + qDebug() << " tag " << tag << " found: pos now: " << i; + return true; +#undef SKIP_CHAR +} + +static void addLink(const QString &linkTarget, + const QStringRef &nestedStuff, + QString *res) +{ + if (!linkTarget.isEmpty()) { + *res += "<a href=\""; + *res += linkTarget; + *res += "\">"; + *res += nestedStuff; + *res += "</a>"; + } + else { + *res += nestedStuff; + } +} + + HtmlGenerator::HtmlGenerator() : helpProjectWriter(0), inLink(false), inContents(false), inSectionHeading(false), inTableHeader(false), numTableRows(0), threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"), - tre(0), slow(false) + tre(0), slow(false), obsoleteLinks(false) { } @@ -94,6 +215,7 @@ void HtmlGenerator::initializeGenerator(const Config &config) }; Generator::initializeGenerator(config); + obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS)); setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); int i = 0; while (defaults[i].key) { @@ -102,11 +224,21 @@ void HtmlGenerator::initializeGenerator(const Config &config) i++; } - style = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLE); - postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER); - footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); - address = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS); - pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS); + style = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLE); + postHeader = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_POSTHEADER); + footer = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_FOOTER); + address = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_ADDRESS); + pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_GENERATEMACREFS); project = config.getString(CONFIG_PROJECT); @@ -120,10 +252,16 @@ void HtmlGenerator::initializeGenerator(const Config &config) QSet<QString>::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { QString editionName = *edition; - QStringList editionModules = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "modules"); - QStringList editionGroups = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "groups"); + QStringList editionModules = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "modules"); + QStringList editionGroups = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "groups"); if (!editionModules.isEmpty()) editionModuleMap[editionName] = editionModules; @@ -135,11 +273,17 @@ void HtmlGenerator::initializeGenerator(const Config &config) slow = config.getBool(CONFIG_SLOW); - stylesheets = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLESHEETS); - customHeadElements = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_CUSTOMHEADELEMENTS); + stylesheets = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLESHEETS); + customHeadElements = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_CUSTOMHEADELEMENTS); codeIndent = config.getInt(CONFIG_CODEINDENT); - helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp"); + helpProjectWriter = new HelpProjectWriter(config, + project.toLower() + + ".qhp"); } void HtmlGenerator::terminateGenerator() @@ -173,6 +317,7 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) nonCompatClasses.clear(); mainClasses.clear(); compatClasses.clear(); + obsoleteClasses.clear(); moduleClassMap.clear(); moduleNamespaceMap.clear(); funcIndex.clear(); @@ -182,9 +327,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) findAllFunctions(tree->root()); findAllLegaleseTexts(tree->root()); findAllNamespaces(tree->root()); -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML findAllQmlClasses(tree->root()); -#endif +#endif PageGenerator::generateTree(tree, marker); @@ -260,7 +405,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::AutoLink: if (!inLink && !inContents && !inSectionHeading) { const Node *node = 0; - QString link = getLink(atom, relative, marker, node); + QString link = getLink(atom, relative, marker, &node); if (!link.isEmpty()) { beginLink(link, node, relative, marker); generateLink(atom, relative, marker); @@ -288,7 +433,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, QString str; atom = atom->next(); while (atom != 0 && atom->type() != Atom::BriefRight) { - if (atom->type() == Atom::String || atom->type() == Atom::AutoLink) + if (atom->type() == Atom::String || + atom->type() == Atom::AutoLink) str += atom->string(); skipAhead++; atom = atom->next(); @@ -326,21 +472,24 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; break; case Atom::Code: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#ifdef QDOC_QML +#ifdef QDOC_QML case Atom::Qml: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#endif +#endif case Atom::CodeNew: out() << "<p>you can rewrite it as</p>\n" - << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; case Atom::CodeOld: @@ -348,7 +497,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent, atom->string())))) + << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) << "</font></pre>\n"; break; case Atom::FootnoteLeft: @@ -388,6 +537,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[atom->string()]; } break; + case Atom::AnnotatedList: + { + QList<Node*> values = tre->groups().values(atom->string()); + QMap<QString, const Node*> nodeMap; + for (int i = 0; i < values.size(); ++i) { + const Node* n = values.at(i); + nodeMap.insert(n->name(),n); + } + generateAnnotatedList(relative, marker, nodeMap); + } + break; case Atom::GeneratedList: if (atom->string() == "annotatedclasses") { generateAnnotatedList(relative, marker, nonCompatClasses); @@ -443,6 +603,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == "compatclasses") { generateCompactList(relative, marker, compatClasses); } + else if (atom->string() == "obsoleteclasses") { + generateCompactList(relative, marker, obsoleteClasses); + } else if (atom->string() == "functionindex") { generateFunctionIndex(relative, marker); } @@ -524,11 +687,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::Link: { const Node *node = 0; - QString myLink = getLink(atom, relative, marker, node); - if (myLink.isEmpty()) + QString myLink = getLink(atom, relative, marker, &node); + if (myLink.isEmpty()) { relative->doc().location().warning(tr("Cannot link to '%1' in %2") .arg(atom->string()) .arg(marker->plainFullName(relative))); + } beginLink(myLink, node, relative, marker); skipAhead = 1; } @@ -554,13 +718,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"100%\">\n" - "<tr><th width=\"25%\">Constant</th><th width=\"15%\">Value</th>" - "<th width=\"60%\">Description</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"100%\">\n" + << "<tr><th width=\"25%\">Constant</th>" + << "<th width=\"15%\">Value</th>" + << "<th width=\"60%\">Description</th></tr>\n"; } else { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"40%\">\n" - << "<tr><th width=\"60%\">Constant</th><th width=\"40%\">Value</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"40%\">\n" + << "<tr><th width=\"60%\">Constant</th><th " + << "width=\"40%\">Value</th></tr>\n"; } } else { @@ -734,14 +902,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, } if (!atom->string().isEmpty()) { if (atom->string().contains("%")) - out() << "<p><table width=\"" << atom->string() << "\" " + out() << "<p><table class=\"generic\" width=\"" << atom->string() << "\" " << "align=\"center\" cellpadding=\"2\" " << "cellspacing=\"1\" border=\"0\">\n"; - else - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + else { + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; + } } else { - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; } numTableRows = 0; break; @@ -840,7 +1011,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::EndQmlText: // don't do anything with these. They are just tags. break; -#endif +#endif default: unknownAtom(atom); } @@ -906,6 +1077,12 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, generateHeader(title, inner, marker, true); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); +#ifdef QDOC_QML + if (classe && !classe->qmlElement().isEmpty()) { + generateInstantiatedBy(classe,marker); + } +#endif + generateBrief(inner, marker); generateIncludes(inner, marker); generateStatus(inner, marker); @@ -924,12 +1101,16 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -941,14 +1122,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { - if (s->members.isEmpty()) { + if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { if (!s->inherited.isEmpty()) needOtherSection = true; - } else { - out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + } + else { + if (!s->members.isEmpty()) { + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef((*s).name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateSection(s->members, inner, marker, CodeMarker::Summary); + } + if (!s->reimpMembers.isEmpty()) { + QString name = QString("Reimplemented ") + (*s).name; + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef(name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect(name) << "</h2>\n"; + generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); + } - generateSectionList(*s, inner, marker, CodeMarker::Summary); + if (!s->inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(*s, inner, marker, true); + out() << "</ul>\n"; + } } ++s; } @@ -997,29 +1198,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, names << (*m)->name(); if ((*m)->type() == Node::Function) { const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); - if (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor - || func->overloadNumber() != 1) + if (func->metaness() == FunctionNode::Ctor || + func->metaness() == FunctionNode::Dtor || + func->overloadNumber() != 1) names.clear(); - } else if ((*m)->type() == Node::Property) { + } + else if ((*m)->type() == Node::Property) { const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); - if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name())) + if (!prop->getters().isEmpty() && + !names.contains(prop->getters().first()->name())) names << prop->getters().first()->name(); if (!prop->setters().isEmpty()) names << prop->setters().first()->name(); if (!prop->resetters().isEmpty()) names << prop->resetters().first()->name(); - } else if ((*m)->type() == Node::Enum) { - const EnumNode *enume = reinterpret_cast<const EnumNode *>(*m); + } + else if ((*m)->type() == Node::Enum) { + const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); if (enume->flagsType()) names << enume->flagsType()->name(); foreach (const QString &enumName, - enume->doc().enumItemNames().toSet() - - enume->doc().omitEnumItemNames().toSet()) - names << plainCode(marker->markedUpEnumValue(enumName, enume)); + enume->doc().enumItemNames().toSet() - + enume->doc().omitEnumItemNames().toSet()) + names << plainCode(marker->markedUpEnumValue(enumName, + enume)); } foreach (const QString &name, names) - classSection.keywords += qMakePair(name, linkForNode(*m, 0)); + classSection.keywords += qMakePair(name,linkForNode(*m,0)); } ++m; } @@ -1060,16 +1266,19 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) QList<Section>::const_iterator s; QString htmlTitle = fake->fullTitle(); - if (fake->subType() == FakeNode::File && !fake->subTitle().isEmpty()) { + if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { subTitleSize = SmallSubTitle; htmlTitle += " (" + fake->subTitle() + ")"; } generateHeader(htmlTitle, fake, marker, true); - generateTitle(fake->fullTitle(), Text() << fake->subTitle(), subTitleSize, - fake, marker); + generateTitle(fake->fullTitle(), + Text() << fake->subTitle(), + subTitleSize, + fake, + marker); - if (fake->subType() == FakeNode::Module) { + if (fake->subType() == Node::Module) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1083,7 +1292,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } } - else if (fake->subType() == FakeNode::HeaderFile) { + else if (fake->subType() == Node::HeaderFile) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1095,12 +1304,16 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -1126,35 +1339,65 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) appendDcfSubSection(&fakeSection, compatSection); } } +#ifdef QDOC_QML + else if (fake->subType() == Node::QmlClass) { + const QmlClassNode* qml_cn = static_cast<const QmlClassNode*>(fake); + const ClassNode* cn = qml_cn->classNode(); + generateQmlInherits(qml_cn, marker); + generateQmlInstantiates(qml_cn, marker); + generateBrief(qml_cn, marker); + sections = marker->qmlSections(qml_cn,CodeMarker::Summary); + s = sections.begin(); + while (s != sections.end()) { + out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateQmlSummary(*s,fake,marker); + ++s; + } + + out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; + out() << "<h2>" << "Detailed Description" << "</h2>\n"; + generateBody(fake, marker); + if (cn) + generateQmlText(cn->doc().body(), cn, marker, fake->name()); + generateAlsoList(fake, marker); + out() << "<hr />\n"; + sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); + s = sections.begin(); + while (s != sections.end()) { + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + NodeList::ConstIterator m = (*s).members.begin(); + while (m != (*s).members.end()) { + generateDetailedQmlMember(*m, fake, marker); + out() << "<br />\n"; + fakeSection.keywords += qMakePair((*m)->name(), + linkForNode(*m,0)); + ++m; + } + ++s; + } + generateFooter(fake); + return; + } +#endif + sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } Text brief = fake->doc().briefText(); - if (fake->subType() == FakeNode::Module && !brief.isEmpty()) { + if (fake->subType() == Node::Module && !brief.isEmpty()) { out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; out() << "<h2>" << "Detailed Description" << "</h2>\n"; } generateBody(fake, marker); -#ifdef QDOC_QML - if (fake->subType() == FakeNode::QmlClass) { - //qDebug() << "generateFakeNode(): QML CLASS" << fake->name(); - const QmlNode* qmlNode = static_cast<const QmlNode*>(fake); - const ClassNode* cn = qmlNode->classNode(); - if (cn) { - //qDebug() << " CPP CLASS" << cn->name(); - generateQmlText(cn->doc().body(), cn, marker); - } - } -#endif - generateAlsoList(fake, marker); if (!fake->groupMembers().isEmpty()) { @@ -1184,10 +1427,10 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } generateFooter(fake); - if (fake->subType() == FakeNode::Example) { + if (fake->subType() == Node::Example) { appendDcfSubSection(&dcfExamplesRoot, fakeSection); } - else if (fake->subType() != FakeNode::File) { + else if (fake->subType() != Node::File) { QString contentsPage = fake->links().value(Node::ContentsLink).first; if (contentsPage == "Qt Designer Manual") { @@ -1407,17 +1650,19 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) { if (!inner->includes().isEmpty()) { - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, - marker->markedUpIncludes( - inner->includes())), - marker, inner)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent, + marker->markedUpIncludes(inner->includes())), + marker,inner)) << "</pre>"; } } -void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, +void HtmlGenerator::generateTableOfContents(const Node *node, + CodeMarker *marker, Doc::SectioningUnit sectioningUnit, - int numColumns, const Node *relative) + int numColumns, + const Node *relative) { if (!node->doc().hasTableOfContents()) @@ -1436,7 +1681,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker QString tdTag; if (numColumns > 1) { tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">"; - out() << "<p><table width=\"100%\">\n<tr valign=\"top\">" << tdTag << "\n"; + out() << "<p><table class=\"toc\" width=\"100%\">\n<tr valign=\"top\">" + << tdTag << "\n"; } // disable nested links in table of contents @@ -1455,7 +1701,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker out() << "<ul>"; sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); - } else { + } + else { while (sectionNumber.size() > nextLevel) { out() << "</ul>\n"; sectionNumber.removeLast(); @@ -1470,7 +1717,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker columnSize = 0; } out() << "<li>"; - out() << "<a href=\"" << nodeName << "#" << Doc::canonicalTitle(headingText.toString()) + out() << "<a href=\"" + << nodeName + << "#" + << Doc::canonicalTitle(headingText.toString()) << "\">"; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "</a></li>\n"; @@ -1520,12 +1770,15 @@ void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, } #endif -QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker) +QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, + CodeMarker *marker) { QList<Section> sections; QList<Section>::ConstIterator s; - sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay); + sections = marker->sections(inner, + CodeMarker::SeparateList, + CodeMarker::Okay); if (sections.isEmpty()) return QString(); @@ -1546,10 +1799,13 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeM return fileName; } -QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker, +QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, + CodeMarker *marker, CodeMarker::Status status) { - QList<Section> sections = marker->sections(inner, CodeMarker::Summary, status); + QList<Section> sections = marker->sections(inner, + CodeMarker::Summary, + status); QMutableListIterator<Section> j(sections); while (j.hasNext()) { if (j.next().members.size() == 0) @@ -1566,7 +1822,8 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM if (status == CodeMarker::Compat) { title = "Qt 3 Support Members for " + inner->name(); fileName = fileBase(inner) + "-qt3." + fileExtension(inner); - } else { + } + else { title = "Obsolete Members for " + inner->name(); fileName = fileBase(inner) + "-obsolete." + fileExtension(inner); } @@ -1580,18 +1837,20 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> " "They are provided to help you port old code to Qt 4. We advise against " "using them in new code.</p>\n"; - } else { - out() << "<p><b>The following class members are obsolete.</b> They are provided to keep " - "old source code working. We strongly advise against using them in new " - "code.</p>\n"; + } + else { + out() << "<p><b>The following class members are obsolete.</b> " + << "They are provided to keep old source code working. " + << "We strongly advise against using them in new code.</p>\n"; } - out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" << protect(inner->name()) + out() << "<p><ul><li><a href=\"" + << linkForNode(inner, 0) << "\">" + << protect(inner->name()) << " class reference</a></li></ul></p>\n"; for (i = 0; i < sections.size(); ++i) { - out() << "<h3>" << protect(sections.at(i).name) << "</h3>\n"; - + out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } @@ -1613,8 +1872,9 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM return fileName; } -void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &classMap) +void HtmlGenerator::generateClassHierarchy(const Node *relative, + CodeMarker *marker, + const QMap<QString,const Node*> &classMap) { if (classMap.isEmpty()) return; @@ -1636,8 +1896,10 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar if (stack.top().isEmpty()) { stack.pop(); out() << "</ul>\n"; - } else { - const ClassNode *child = static_cast<const ClassNode *>(*stack.top().begin()); + } + else { + const ClassNode *child = + static_cast<const ClassNode *>(*stack.top().begin()); out() << "<li>"; generateFullName(child, relative, marker); out() << "</li>\n"; @@ -1656,15 +1918,20 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar } } -void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &nodeMap) +void HtmlGenerator::generateAnnotatedList(const Node *relative, + CodeMarker *marker, + const QMap<QString, const Node *> &nodeMap) { - out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { const Node *node = nodeMap[name]; + if (node->status() == Node::Obsolete) + continue; + if (++row % 2 == 1) out() << "<tr valign=\"top\" class=\"odd\">"; else @@ -1680,7 +1947,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark generateText(brief, node, marker); out() << "</td>"; } - } else { + } + else { out() << "<td>"; out() << protect(node->doc().briefText().toString()); out() << "</td>"; @@ -1690,7 +1958,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark out() << "</table></p>\n"; } -void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker, +void HtmlGenerator::generateCompactList(const Node *relative, + CodeMarker *marker, const QMap<QString, const Node *> &classMap) { const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' @@ -1734,8 +2003,9 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker last = classMap.begin().key(); if (classMap.size() > 1) { - while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1 - && first[commonPrefixLen] == last[commonPrefixLen]) + while (commonPrefixLen < first.length() + 1 && + commonPrefixLen < last.length() + 1 && + first[commonPrefixLen] == last[commonPrefixLen]) ++commonPrefixLen; } @@ -1764,7 +2034,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker if (key[0].digitValue() != -1) { paragraphNo = key[0].digitValue(); - } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { + } + else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { paragraphNo = 10 + key[0].unicode() - 'a'; } @@ -1812,45 +2083,56 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker } firstOffset[NumColumns] = classMap.count(); - out() << "<p><table width=\"100%\">\n"; + out() << "<p><table class=\"generic\" width=\"100%\">\n"; for (k = 0; k < numRows; k++) { out() << "<tr>\n"; for (i = 0; i < NumColumns; i++) { if (currentOffset[i] >= firstOffset[i + 1]) { // this column is finished out() << "<td>\n</td>\n"; - } else { + } + else { while (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count()) { ++currentParagraphNo[i]; currentOffsetInParagraph[i] = 0; } + if (currentParagraphNo[i] >= NumParagraphs) { + qDebug() << "### Internal error ###" << __FILE__ << __LINE__; + currentParagraphNo[i] = NumParagraphs - 1; + } + out() << "<td align=\"right\">"; if (currentOffsetInParagraph[i] == 0) { // start a new paragraph - out() << "<b>" << paragraphName[currentParagraphNo[i]] << " </b>"; - } - out() << "</td>\n"; - - // bad loop - QMap<QString, const Node *>::Iterator it; - it = paragraph[currentParagraphNo[i]].begin(); - for (j = 0; j < currentOffsetInParagraph[i]; j++) - ++it; - - out() << "<td>"; - // Previously, we used generateFullName() for this, but we - // require some special formatting. - out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">"; - QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); - out() << "</a>"; - if (pieces.size() > 1) { - out() << " ("; - generateFullName(it.value()->parent(), relative, marker); - out() << ")"; + out() << "<b>" + << paragraphName[currentParagraphNo[i]] + << " </b>"; } out() << "</td>\n"; + + if (!paragraphName[currentParagraphNo[i]].isEmpty()) { + QMap<QString, const Node *>::Iterator it; + it = paragraph[currentParagraphNo[i]].begin(); + for (j = 0; j < currentOffsetInParagraph[i]; j++) + ++it; + + out() << "<td>"; + // Previously, we used generateFullName() for this, but we + // require some special formatting. + out() << "<a href=\"" + << linkForNode(it.value(), relative) + << "\">"; + QStringList pieces = fullName(it.value(), relative, marker).split("::"); + out() << protect(pieces.last()); + out() << "</a>"; + if (pieces.size() > 1) { + out() << " ("; + generateFullName(it.value()->parent(), relative, marker); + out() << ")"; + } + out() << "</td>\n"; + } currentOffset[i]++; currentOffsetInParagraph[i]++; @@ -1861,7 +2143,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker out() << "</table></p>\n"; } -void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateFunctionIndex(const Node *relative, + CodeMarker *marker) { out() << "<p align=\"center\"><font size=\"+1\"><b>"; for (int i = 0; i < 26; i++) { @@ -1910,7 +2193,8 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *mark #endif } -void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateLegaleseList(const Node *relative, + CodeMarker *marker) { QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin(); while (it != legaleseTexts.end()) { @@ -1928,8 +2212,10 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marke } } -void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +/*void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); @@ -1939,7 +2225,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } - marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); marked.replace("<@param>", "<i>"); marked.replace("</@param>", "</i>"); @@ -1950,7 +2237,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, QRegExp extraRegExp("<@extra>.*</@extra>"); extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); - } else { + } + else { marked.replace("<@extra>", " <tt>"); marked.replace("</@extra>", "</tt>"); } @@ -1960,7 +2248,40 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace("</@type>", ""); } out() << highlightedCode(marked, marker, relative); +}*/ + +#ifdef QDOC_QML +void HtmlGenerator::generateQmlItem(const Node *node, + const Node *relative, + CodeMarker *marker, + bool summary) +{ + QString marked = marker->markedUpQmlItem(node,summary); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); + } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); + + if (summary) + marked.replace("@name>", "b>"); + + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); + + if (summary) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); + } + out() << highlightedCode(marked, marker, relative); } +#endif void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) { @@ -1984,7 +2305,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } // there are too many examples; they would clutter the list - if (fakeNode->subType() == FakeNode::Example) + if (fakeNode->subType() == Node::Example) continue; // not interested either in individual (Qt Designer etc.) manual chapters @@ -1992,7 +2313,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m continue; // Discard external nodes. - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) continue; QString sortKey = fakeNode->fullTitle().toLower(); @@ -2017,7 +2338,8 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode); } } - } else if (!isGroupPage) { + } + else if (!isGroupPage) { // If we encounter a page that belongs to a group then // we add that page to the list for that group. const FakeNode *groupNode = static_cast<const FakeNode *>(tre->root()->findNode(group, Node::Fake)); @@ -2075,21 +2397,100 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } } -void HtmlGenerator::generateSectionList(const Section& section, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +#ifdef QDOC_NAME_ALIGNMENT +void HtmlGenerator::generateSection(const NodeList& nl, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { + bool name_alignment = true; + if (!nl.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + name_alignment = false; + twoColumn = (nl.count() >= 16); + } + else if (nl.first()->type() == Node::Property) { + twoColumn = (nl.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + } + + int i = 0; + NodeList::ConstIterator m = nl.begin(); + while (m != nl.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } + + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (nl.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } + + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; + i++; + ++m; + } + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } + } +} + +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + bool name_alignment = true; if (!section.members.isEmpty()) { bool twoColumn = false; if (style == CodeMarker::SeparateList) { + name_alignment = false; twoColumn = (section.members.count() >= 16); - } else if (section.members.first()->type() == Node::Property) { + } + else if (section.members.first()->type() == Node::Property) { twoColumn = (section.members.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; } - if (twoColumn) - out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" - " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; - out() << "<ul>\n"; int i = 0; NodeList::ConstIterator m = section.members.begin(); @@ -2099,41 +2500,56 @@ void HtmlGenerator::generateSectionList(const Section& section, const Node *rela continue; } - if (twoColumn && i == (int) (section.members.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } - out() << "<li><div class=\"fn\"></div>"; - if (style == CodeMarker::Accessors) - out() << "<b>"; - generateSynopsis(*m, relative, marker, style); - if (style == CodeMarker::Accessors) - out() << "</b>"; - out() << "</li>\n"; + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; i++; ++m; } - out() << "</ul>\n"; - if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { out() << "<ul>\n"; - generateSectionInheritedList(section, relative, marker); + generateSectionInheritedList(section, relative, marker, name_alignment); out() << "</ul>\n"; } } -void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative, - CodeMarker *marker) +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker, + bool nameAlignment) { QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { - out() << "<li><div class=\"fn\"></div>"; + if (nameAlignment) + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + else + out() << "<li><div class=\"fn\"></div>"; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; - } else { + } + else { out() << section.pluralMember; } out() << " inherited from <a href=\"" << fileName((*p).first) @@ -2144,270 +2560,324 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N } } -void HtmlGenerator::generateLink(const Atom *atom, const Node * /* relative */, CodeMarker *marker) +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style, + bool nameAlignment) { - static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); - - if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { - // hack for C++: move () outside of link - int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); - if (link.isEmpty()) { - if (showBrokenLinks) - out() << "</i>"; - } else { - out() << "</a>"; - } - inLink = false; - out() << protect(atom->string().mid(k)); - } else if (marker->recognizeLanguage("Java")) { - // hack for Java: remove () and use <tt> when appropriate - bool func = atom->string().endsWith("()"); - bool tt = (func || atom->string().contains(camelCase)); - if (tt) - out() << "<tt>"; - if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); - } else { - out() << protect(atom->string()); - } - out() << "</tt>"; - } else { - out() << protect(atom->string()); + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } -} - -QString HtmlGenerator::cleanRef(const QString& ref) -{ - QString clean; - - if (ref.isEmpty()) - return clean; + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - clean.reserve(ref.size() + 20); - const QChar c = ref[0]; - const uint u = c.unicode(); + if (style == CodeMarker::Summary) { + marked.replace("<@name>", ""); // was "<b>" + marked.replace("</@name>", ""); // was "</b>" + } - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9')) { - clean += c; - } else if (u == '~') { - clean += "dtor."; - } else if (u == '_') { - clean += "underscore."; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); } else { - clean += "A"; + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - for (int i = 1; i < (int) ref.length(); i++) { - const QChar c = ref[i]; - const uint u = c.unicode(); - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9') || u == '-' || - u == '_' || u == ':' || u == '.') { - clean += c; - } else if (c.isSpace()) { - clean += "-"; - } else if (u == '!') { - clean += "-not"; - } else if (u == '&') { - clean += "-and"; - } else if (u == '<') { - clean += "-lt"; - } else if (u == '=') { - clean += "-eq"; - } else if (u == '>') { - clean += "-gt"; - } else if (u == '#') { - clean += "#"; - } else { - clean += "-"; - clean += QString::number((int)u, 16); - } + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } - return clean; + out() << highlightedCode(marked, marker, relative, style, nameAlignment); } -QString HtmlGenerator::registerRef(const QString& ref) +QString HtmlGenerator::highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative, + CodeMarker::SynopsisStyle , + bool nameAlignment) { - QString clean = HtmlGenerator::cleanRef(ref); + QString src = markedCode; + QString html; + QStringRef arg; + QStringRef par1; - for (;;) { - QString& prevRef = refMap[clean.toLower()]; - if (prevRef.isEmpty()) { - prevRef = ref; - break; - } else if (prevRef == ref) { - break; + const QChar charLangle = '<'; + const QChar charAt = '@'; + + // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)" + static const QString linkTag("link"); + bool done = false; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { + if (nameAlignment && !done) {// && (i != 0)) Why was this here? + html += "</td><td class=\"memItemRight\" valign=\"bottom\">"; + done = true; + } + i += 2; + if (parseArg(src, linkTag, &i, n, &arg, &par1)) { + html += "<b>"; + QString link = linkForNode( + CodeMarker::nodeForString(par1.toString()), relative); + addLink(link, arg, &html); + html += "</b>"; + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } - clean += "x"; } - return clean; -} - -QString HtmlGenerator::protect(const QString& string) -{ -#define APPEND(x) \ - if (html.isEmpty()) { \ - html = string; \ - html.truncate(i); \ - } \ - html += (x); - QString html; - int n = string.length(); - for (int i = 0; i < n; ++i) { - QChar ch = string.at(i); + if (slow) { + // is this block ever used at all? + // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" + src = html; + html = QString(); + static const QString funcTag("func"); + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + if (parseArg(src, funcTag, &i, n, &arg, &par1)) { + QString link = linkForNode( + marker->resolveTarget(par1.toString(), + tre, + relative), + relative); + addLink(link, arg, &html); + par1 = QStringRef(); + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); + } + } + } - if (ch == QLatin1Char('&')) { - APPEND("&"); - } else if (ch == QLatin1Char('<')) { - APPEND("<"); - } else if (ch == QLatin1Char('>')) { - APPEND(">"); - } else if (ch == QLatin1Char('"')) { - APPEND("""); - } else if (ch.unicode() > 0x007F - || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) - || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { - // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator - APPEND("&#x"); - html += QString::number(ch.unicode(), 16); - html += QLatin1Char(';'); - } else { - if (!html.isEmpty()) - html += ch; + // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags + src = html; + html = QString(); + static const QString typeTags[] = { "type", "headerfile", "func" }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + bool handled = false; + for (int k = 0; k != 3; ++k) { + if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) { + par1 = QStringRef(); + QString link = linkForNode( + marker->resolveTarget(arg.toString(), tre, relative), + relative); + addLink(link, arg, &html); + handled = true; + break; + } + } + if (!handled) { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } } - if (!html.isEmpty()) - return html; - return string; + // replace all + // "<@comment>" -> "<span class=\"comment\">"; + // "<@preprocessor>" -> "<span class=\"preprocessor\">"; + // "<@string>" -> "<span class=\"string\">"; + // "<@char>" -> "<span class=\"char\">"; + // "</@(?:comment|preprocessor|string|char)>" -> "</span>" + src = html; + html = QString(); + static const QString spanTags[] = { + "<@comment>", "<span class=\"comment\">", + "<@preprocessor>", "<span class=\"preprocessor\">", + "<@string>", "<span class=\"string\">", + "<@char>", "<span class=\"char\">", + "</@comment>", "</span>", + "</@preprocessor>","</span>", + "</@string>", "</span>", + "</@char>", "</span>" + // "<@char>", "<font color=blue>", + // "</@char>", "</font>", + // "<@func>", "<font color=green>", + // "</@func>", "</font>", + // "<@id>", "<i>", + // "</@id>", "</i>", + // "<@keyword>", "<b>", + // "</@keyword>", "</b>", + // "<@number>", "<font color=yellow>", + // "</@number>", "</font>", + // "<@op>", "<b>", + // "</@op>", "</b>", + // "<@param>", "<i>", + // "</@param>", "</i>", + // "<@string>", "<font color=green>", + // "</@string>", "</font>", + }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle) { + bool handled = false; + for (int k = 0; k != 8; ++k) { + const QString & tag = spanTags[2 * k]; + if (tag == QStringRef(&src, i, tag.length())) { + html += spanTags[2 * k + 1]; + i += tag.length(); + handled = true; + break; + } + } + if (!handled) { + ++i; + if (src.at(i) == charAt || + (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) { + // drop 'our' unknown tags (the ones still containing '@') + while (i < n && src.at(i) != QLatin1Char('>')) + ++i; + ++i; + } + else { + // retain all others + html += charLangle; + } + } + } + else { + html += src.at(i); + ++i; + } + } -#undef APPEND + return html; } -static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); -static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); -static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); -static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); -static QRegExp unknownTag("</?@[^>]*>"); - -bool parseArg(const QString &src, - const QString &tag, - int *pos, - int n, - QStringRef *contents, - QStringRef *par1 = 0, - bool debug = false) +#else +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { -#define SKIP_CHAR(c) \ - if (debug) \ - qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ - if (i >= n || src[i] != c) { \ - if (debug) \ - qDebug() << " char '" << c << "' not found"; \ - return false; \ - } \ - ++i; - - -#define SKIP_SPACE \ - while (i < n && src[i] == ' ') \ - ++i; + if (!section.members.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + twoColumn = (section.members.count() >= 16); + } + else if (section.members.first()->type() == Node::Property) { + twoColumn = (section.members.count() >= 5); + } + if (twoColumn) + out() << "<p><table class=\"generic\" width=\"100%\" border=\"0\" " + << "cellpadding=\"0\" cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; - int i = *pos; - int j = i; + int i = 0; + NodeList::ConstIterator m = section.members.begin(); + while (m != section.members.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } - // assume "<@" has been parsed outside - //SKIP_CHAR('<'); - //SKIP_CHAR('@'); + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; - if (tag != QStringRef(&src, i, tag.length())) { - if (0 && debug) - qDebug() << "tag " << tag << " not found at " << i; - return false; + out() << "<li><div class=\"fn\"></div>"; + if (style == CodeMarker::Accessors) + out() << "<b>"; + generateSynopsis(*m, relative, marker, style); + if (style == CodeMarker::Accessors) + out() << "</b>"; + out() << "</li>\n"; + i++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; } - if (debug) - qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; - - // skip tag - i += tag.length(); + if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(section, relative, marker); + out() << "</ul>\n"; + } +} - // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); - if (par1) { - SKIP_SPACE; - // read parameter name - j = i; - while (i < n && src[i].isLetter()) - ++i; - if (src[i] == '=') { - if (debug) - qDebug() << "read parameter" << QString(src.data() + j, i - j); - SKIP_CHAR('='); - SKIP_CHAR('"'); - // skip parameter name - j = i; - while (i < n && src[i] != '"') - ++i; - *par1 = QStringRef(&src, j, i - j); - SKIP_CHAR('"'); - SKIP_SPACE; +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); + while (p != section.inherited.end()) { + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + out() << (*p).second << " "; + if ((*p).second == 1) { + out() << section.singularMember; } else { - if (debug) - qDebug() << "no optional parameter found"; + out() << section.pluralMember; } + out() << " inherited from <a href=\"" << fileName((*p).first) + << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" + << protect(marker->plainFullName((*p).first, relative)) + << "</a></li>\n"; + ++p; } - SKIP_SPACE; - SKIP_CHAR('>'); +} - // find contents up to closing "</@tag> - j = i; - for (; true; ++i) { - if (i + 4 + tag.length() > n) - return false; - if (src[i] != '<') - continue; - if (src[i + 1] != '/') - continue; - if (src[i + 2] != '@') - continue; - if (tag != QStringRef(&src, i + 3, tag.length())) - continue; - if (src[i + 3 + tag.length()] != '>') - continue; - break; +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - *contents = QStringRef(&src, j, i - j); - - i += tag.length() + 4; - - *pos = i; - if (debug) - qDebug() << " tag " << tag << " found: pos now: " << i; - return true; -#undef SKIP_CHAR -} + if (style == CodeMarker::Summary) + marked.replace("@name>", "b>"); -static void addLink(const QString &linkTarget, - const QStringRef &nestedStuff, - QString *res) -{ - if (!linkTarget.isEmpty()) { - *res += "<a href=\""; - *res += linkTarget; - *res += "\">"; - *res += nestedStuff; - *res += "</a>"; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); + } else { + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - else { - *res += nestedStuff; + + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } + out() << highlightedCode(marked, marker, relative); } QString HtmlGenerator::highlightedCode(const QString& markedCode, @@ -2428,8 +2898,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; if (parseArg(src, linkTag, &i, n, &arg, &par1)) { - QString link = linkForNode( - CodeMarker::nodeForString(par1.toString()), relative); + const Node* node = CodeMarker::nodeForString(par1.toString()); + QString link = linkForNode(node, relative); addLink(link, arg, &html); } else { @@ -2442,7 +2912,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, } } - if (slow) { // is this block ever used at all? // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" @@ -2570,6 +3039,155 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, return html; } +#endif + +void HtmlGenerator::generateLink(const Atom* atom, + const Node* /* relative */, + CodeMarker* marker) +{ + static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); + + if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { + // hack for C++: move () outside of link + int k = funcLeftParen.pos(1); + out() << protect(atom->string().left(k)); + if (link.isEmpty()) { + if (showBrokenLinks) + out() << "</i>"; + } else { + out() << "</a>"; + } + inLink = false; + out() << protect(atom->string().mid(k)); + } else if (marker->recognizeLanguage("Java")) { + // hack for Java: remove () and use <tt> when appropriate + bool func = atom->string().endsWith("()"); + bool tt = (func || atom->string().contains(camelCase)); + if (tt) + out() << "<tt>"; + if (func) { + out() << protect(atom->string().left(atom->string().length() - 2)); + } else { + out() << protect(atom->string()); + } + out() << "</tt>"; + } else { + out() << protect(atom->string()); + } +} + +QString HtmlGenerator::cleanRef(const QString& ref) +{ + QString clean; + + if (ref.isEmpty()) + return clean; + + clean.reserve(ref.size() + 20); + const QChar c = ref[0]; + const uint u = c.unicode(); + + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9')) { + clean += c; + } else if (u == '~') { + clean += "dtor."; + } else if (u == '_') { + clean += "underscore."; + } else { + clean += "A"; + } + + for (int i = 1; i < (int) ref.length(); i++) { + const QChar c = ref[i]; + const uint u = c.unicode(); + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9') || u == '-' || + u == '_' || u == ':' || u == '.') { + clean += c; + } else if (c.isSpace()) { + clean += "-"; + } else if (u == '!') { + clean += "-not"; + } else if (u == '&') { + clean += "-and"; + } else if (u == '<') { + clean += "-lt"; + } else if (u == '=') { + clean += "-eq"; + } else if (u == '>') { + clean += "-gt"; + } else if (u == '#') { + clean += "#"; + } else { + clean += "-"; + clean += QString::number((int)u, 16); + } + } + return clean; +} + +QString HtmlGenerator::registerRef(const QString& ref) +{ + QString clean = HtmlGenerator::cleanRef(ref); + + for (;;) { + QString& prevRef = refMap[clean.toLower()]; + if (prevRef.isEmpty()) { + prevRef = ref; + break; + } else if (prevRef == ref) { + break; + } + clean += "x"; + } + return clean; +} + +QString HtmlGenerator::protect(const QString& string) +{ +#define APPEND(x) \ + if (html.isEmpty()) { \ + html = string; \ + html.truncate(i); \ + } \ + html += (x); + + QString html; + int n = string.length(); + + for (int i = 0; i < n; ++i) { + QChar ch = string.at(i); + + if (ch == QLatin1Char('&')) { + APPEND("&"); + } else if (ch == QLatin1Char('<')) { + APPEND("<"); + } else if (ch == QLatin1Char('>')) { + APPEND(">"); + } else if (ch == QLatin1Char('"')) { + APPEND("""); + } else if (ch.unicode() > 0x007F + || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) + || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { + // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator + APPEND("&#x"); + html += QString::number(ch.unicode(), 16); + html += QLatin1Char(';'); + } else { + if (!html.isEmpty()) + html += ch; + } + } + + if (!html.isEmpty()) + return html; + return string; + +#undef APPEND +} QString HtmlGenerator::fileBase(const Node *node) { @@ -2618,10 +3236,9 @@ QString HtmlGenerator::fileBase(const Node *node, QString HtmlGenerator::fileName(const Node *node) { if (node->type() == Node::Fake) { - if (static_cast<const FakeNode *>(node)->subType() == FakeNode::ExternalPage) + if (static_cast<const FakeNode *>(node)->subType() == Node::ExternalPage) return node->name(); } - return PageGenerator::fileName(node); } @@ -2643,7 +3260,8 @@ QString HtmlGenerator::refForNode(const Node *node) typedeffe = static_cast<const TypedefNode *>(node); if (typedeffe->associatedEnum()) { return refForNode(typedeffe->associatedEnum()); - } else { + } + else { ref = node->name() + "-typedef"; } break; @@ -2651,15 +3269,27 @@ QString HtmlGenerator::refForNode(const Node *node) func = static_cast<const FunctionNode *>(node); if (func->associatedProperty()) { return refForNode(func->associatedProperty()); - } else { + } + else { ref = func->name(); if (func->overloadNumber() != 1) ref += "-" + QString::number(func->overloadNumber()); } break; case Node::Property: +#ifdef QDOC_QML + case Node::QmlProperty: +#endif ref = node->name() + "-prop"; break; +#ifdef QDOC_QML + case Node::QmlSignal: + ref = node->name() + "-signal"; + break; + case Node::QmlMethod: + ref = node->name() + "-method"; + break; +#endif case Node::Variable: ref = node->name() + "-var"; break; @@ -2708,9 +3338,11 @@ QString HtmlGenerator::refForAtom(Atom *atom, const Node * /* node */) { if (atom->type() == Atom::SectionLeft) { return Doc::canonicalTitle(Text::sectionHeading(atom).toString()); - } else if (atom->type() == Atom::Target) { + } + else if (atom->type() == Atom::Target) { return Doc::canonicalTitle(atom->string()); - } else { + } + else { return QString(); } } @@ -2754,7 +3386,10 @@ void HtmlGenerator::generateDetailedMember(const Node *node, out() << "<a name=\"" + refForNode(node) + "\"></a>"; generateSynopsis(enume, relative, marker, CodeMarker::Detailed); out() << "<br />"; - generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed); + generateSynopsis(enume->flagsType(), + relative, + marker, + CodeMarker::Detailed); out() << "</h3>\n"; } else { @@ -2778,7 +3413,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node, section.members += property->resetters(); if (!section.members.isEmpty()) { - out() << "<p>Access functions:</p>\n"; + out() << "<p><b>Access functions:</b></p>\n"; generateSectionList(section, node, marker, CodeMarker::Accessors); } } @@ -2789,7 +3424,8 @@ void HtmlGenerator::generateDetailedMember(const Node *node, << " type is a typedef for " << "<a href=\"qflags.html\">QFlags</a><" << protect(enume->name()) - << ">. It stores an OR combination of " << protect(enume->name()) + << ">. It stores an OR combination of " + << protect(enume->name()) << " values.</p>\n"; } } @@ -2803,7 +3439,8 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) { if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { QString className = (*c)->name(); - if ((*c)->parent() && (*c)->parent()->type() == Node::Namespace && + if ((*c)->parent() && + (*c)->parent()->type() == Node::Namespace && !(*c)->parent()->name().isEmpty()) className = (*c)->parent()->name()+"::"+className; @@ -2811,6 +3448,9 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->status() == Node::Compat) { compatClasses.insert(className, *c); } + else if ((*c)->status() == Node::Obsolete) { + obsoleteClasses.insert(className, *c); + } else { nonCompatClasses.insert(className, *c); if ((*c)->status() == Node::Main) @@ -2851,7 +3491,7 @@ void HtmlGenerator::findAllFunctions(const InnerNode *node) const FunctionNode *func = static_cast<const FunctionNode *>(*c); if (func->status() > Node::Obsolete && func->metaness() != FunctionNode::Ctor && func->metaness() != FunctionNode::Dtor) { - funcIndex[(*c)->name()].insert((*c)->parent()->name(), *c); + funcIndex[(*c)->name()].insert(tre->fullDocumentName((*c)->parent()), *c); } } } @@ -2901,7 +3541,7 @@ void HtmlGenerator::findAllNamespaces(const InnerNode *node) } } -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML /*! This function finds all the qml element nodes and stores them in a map for later use. @@ -2912,24 +3552,16 @@ void HtmlGenerator::findAllQmlClasses(const InnerNode *node) while (c != node->childNodes().constEnd()) { if ((*c)->type() == Node::Fake) { const FakeNode* fakeNode = static_cast<const FakeNode *>(*c); - if (fakeNode->subType() == FakeNode::QmlClass) { - const QmlNode* qmlNode = static_cast<const QmlNode*>(fakeNode); - //qDebug() << "HtmlGenerator: QML CLASS" << qmlNode->name(); + if (fakeNode->subType() == Node::QmlClass) { + const QmlClassNode* qmlNode = + static_cast<const QmlClassNode*>(fakeNode); const Node* n = qmlNode->classNode(); - if (n) - //qDebug() << " FOUND IT!" << n->name(); } qmlClasses.insert(fakeNode->name(),*c); } ++c; } } -#endif - -#if 0 - else if ((*c)->isInnerNode()) { - findAllClasses(static_cast<InnerNode *>(*c)); - } #endif int HtmlGenerator::hOffset(const Node *node) @@ -3007,10 +3639,11 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node) QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, CodeMarker *marker, - const Node *node) + const Node** node) { QString link; - node = 0; + *node = 0; + inObsoleteLink = false; if (atom->string().contains(":") && (atom->string().startsWith("file:") @@ -3034,40 +3667,86 @@ QString HtmlGenerator::getLink(const Atom *atom, QString first = path.first().trimmed(); if (first.isEmpty()) { - node = relative; + *node = relative; } else if (first.endsWith(".html")) { - node = tre->root()->findNode(first, Node::Fake); + *node = tre->root()->findNode(first, Node::Fake); } else { - node = marker->resolveTarget(first, tre, relative); - if (!node) - node = tre->findFakeNodeByTitle(first); - if (!node) - node = tre->findUnambiguousTarget(first, targetAtom); + *node = marker->resolveTarget(first, tre, relative); + if (!*node) + *node = tre->findFakeNodeByTitle(first); + if (!*node) + *node = tre->findUnambiguousTarget(first, targetAtom); } - if (node) { - if (!node->url().isEmpty()) - return node->url(); + if (*node) { + if (!(*node)->url().isEmpty()) + return (*node)->url(); else path.removeFirst(); } else { - node = relative; + *node = relative; + } + + if (*node) { + if ((*node)->status() == Node::Obsolete) { + if (relative) { + if (relative->parent() != *node) { + if (relative->status() != Node::Obsolete) { + bool porting = false; + if (relative->type() == Node::Fake) { + const FakeNode* fake = static_cast<const FakeNode*>(relative); + if (fake->title().startsWith("Porting")) + porting = true; + } + QString name = marker->plainFullName(relative); + if (!porting && !name.startsWith("Q3")) { + if (obsoleteLinks) { + relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") + .arg(atom->string()) + .arg(name)); + } + inObsoleteLink = true; + } +#if 0 + qDebug() << "Link to Obsolete entity" + << (*node)->name(); + qDebug() << " relative entity" + << relative->name(); +#endif + } + } + } + else { + qDebug() << "Link to Obsolete entity" + << (*node)->name() << "no relative"; + } + } +#if 0 + else if ((*node)->status() == Node::Deprecated) { + qDebug() << "Link to Deprecated entity"; + } + else if ((*node)->status() == Node::Internal) { + qDebug() << "Link to Internal entity"; + } + //else + //qDebug() << "Node Status:" << (*node)->status(); +#endif } while (!path.isEmpty()) { - targetAtom = tre->findTarget(path.first(), node); + targetAtom = tre->findTarget(path.first(), *node); if (targetAtom == 0) break; path.removeFirst(); } if (path.isEmpty()) { - link = linkForNode(node, relative); + link = linkForNode(*node, relative); if (targetAtom) - link += "#" + refForAtom(targetAtom, node); + link += "#" + refForAtom(targetAtom, *node); } } return link; @@ -3186,10 +3865,225 @@ void HtmlGenerator::endLink() out() << "</i>"; } else { + if (inObsoleteLink) { + out() << "<sup>(obsolete)</sup>"; + } out() << "</a>"; } } inLink = false; + inObsoleteLink = false; } QT_END_NAMESPACE + +#ifdef QDOC_QML + +/*! + Generates the summary for for the \a section. Only used for + sections of QML element documentation. + + Currently handles only the QML property group. + */ +void HtmlGenerator::generateQmlSummary(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + if (!section.members.isEmpty()) { + NodeList::ConstIterator m; + int count = section.members.size(); + bool twoColumn = false; + if (section.members.first()->type() == Node::QmlProperty) { + twoColumn = (count >= 5); + } + if (twoColumn) + out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" + " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + + int row = 0; + m = section.members.begin(); + while (m != section.members.end()) { + if (twoColumn && row == (int) (count + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\"></div>"; + generateQmlItem(*m,relative,marker,true); + out() << "</li>\n"; + row++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } +} + +/*! + Outputs the html detailed documentation for a section + on a QML element reference page. + */ +void HtmlGenerator::generateDetailedQmlMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker) +{ + const QmlPropertyNode* qpn = 0; + generateMacRef(node, marker); + out() << "<div class=\"qmlitem\">"; + if (node->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + qpn = static_cast<const QmlPropertyNode*>(*p); + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; + generateQmlItem(qpn, relative, marker, false); + out() << "</td></tr>"; + if (qpgn->isDefault()) { + out() << "</table>" + << "</div></div>" + << "<div class=\"qmlitem\">" + << "<div class=\"qmlproto\">" + << "<table class=\"qmlname\">" + << "<tr><td><font color=\"green\">" + << "default</font></td></tr>"; + } + } + ++p; + } + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlSignal) { + const QmlSignalNode* qsn = static_cast<const QmlSignalNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qsn) + "\"></a>"; + generateQmlItem(qsn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlMethod) { + const QmlMethodNode* qmn = static_cast<const QmlMethodNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qmn) + "\"></a>"; + generateQmlItem(qmn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + out() << "<div class=\"qmldoc\">"; + generateStatus(node, marker); + generateBody(node, marker); + generateThreadSafeness(node, marker); + generateSince(node, marker); + generateAlsoList(node, marker); + out() << "</div>"; + out() << "</div>"; +} + +/*! + Output the "Inherits" line for the QML element, + if there should be one. + */ +void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, + CodeMarker* marker) +{ + if (cn && !cn->links().empty()) { + if (cn->links().contains(Node::InheritsLink)) { + QPair<QString,QString> linkPair; + linkPair = cn->links()[Node::InheritsLink]; + QStringList strList(linkPair.first); + const Node* n = tre->findNode(strList,Node::Fake); + if (n && n->subType() == Node::QmlClass) { + const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n); + out() << "<p style=\"text-align: center\">"; + Text text; + text << "[Inherits "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, linkPair.second); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } +// else +// qDebug() << "generateQmlInherits(): " +// << "Inherited element not documented -->" +// << linkPair.first; + } + } +} + +/*! + Output the "[Xxx instantiates the C++ class QFxXxx]" + line for the QML element, if there should be one. + + If there is no class node, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, + CodeMarker* marker) +{ + const ClassNode* cn = qcn->classNode(); + if (cn && (cn->status() != Node::Internal)) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, qcn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " instantiates the C++ class "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, qcn, marker); + out() << "</p>"; + } +} + +/*! + Output the "[QFxXxx is instantiated by QML element Xxx]" + line for the class, if there should be one. + + If there is no QML element, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, + CodeMarker* marker) +{ + if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { + const Node* n = tre->root()->findNode(cn->qmlElement(),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " is instantiated by QML element "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, n->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } + } +} + +#endif |