summaryrefslogtreecommitdiffstats
path: root/tools/qdoc3/htmlgenerator.cpp
diff options
context:
space:
mode:
authorDavid Boddie <dboddie@trolltech.com>2009-06-10 12:34:54 (GMT)
committerDavid Boddie <dboddie@trolltech.com>2009-06-10 12:34:54 (GMT)
commitd8a284783b56e2ddbcedff3fc9577ec6038aab57 (patch)
tree1d49be6cb7de25836957adf30ac113c3a0499911 /tools/qdoc3/htmlgenerator.cpp
parent4a6548b83a6f1df42b82664efaca26c7efbc1909 (diff)
parentc0bbe44ab6290dee088138c01724779026d2c033 (diff)
downloadQt-d8a284783b56e2ddbcedff3fc9577ec6038aab57.zip
Qt-d8a284783b56e2ddbcedff3fc9577ec6038aab57.tar.gz
Qt-d8a284783b56e2ddbcedff3fc9577ec6038aab57.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Conflicts: src/corelib/animation/qanimationgroup.cpp src/gui/graphicsview/qgraphicsitem.cpp
Diffstat (limited to 'tools/qdoc3/htmlgenerator.cpp')
-rw-r--r--tools/qdoc3/htmlgenerator.cpp1033
1 files changed, 674 insertions, 359 deletions
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp
index eb8e65c..335cf66 100644
--- a/tools/qdoc3/htmlgenerator.cpp
+++ b/tools/qdoc3/htmlgenerator.cpp
@@ -61,6 +61,127 @@ 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),
@@ -349,27 +470,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
case Atom::Qml:
out() << "<pre>"
- << trimmedTrailing(highlightedCode(indent(codeIndent,
- atom->string()),
- marker,
- relative))
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
<< "</pre>\n";
break;
#endif
case Atom::CodeNew:
out() << "<p>you can rewrite it as</p>\n"
<< "<pre>"
- << trimmedTrailing(highlightedCode(indent(codeIndent,
- atom->string()),
- marker,
- relative))
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
<< "</pre>\n";
break;
case Atom::CodeOld:
@@ -377,7 +495,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:
@@ -983,12 +1101,11 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
if (s->members.isEmpty()) {
if (!s->inherited.isEmpty())
needOtherSection = true;
- }
- else {
- out() << "<a name=\"" << registerRef((*s).name.toLower())
+ } else {
+ out() << "<a name=\""
+ << registerRef((*s).name.toLower())
<< "\"></a>\n";
- out() << "<h3>" << protect((*s).name) << "</h3>\n";
-
+ out() << "<h2>" << protect((*s).name) << "</h2>\n";
generateSectionList(*s, inner, marker, CodeMarker::Summary);
}
++s;
@@ -1037,16 +1154,14 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
QStringList names;
names << (*m)->name();
if ((*m)->type() == Node::Function) {
- const FunctionNode *func =
- reinterpret_cast<const FunctionNode *>(*m);
+ const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m);
if (func->metaness() == FunctionNode::Ctor ||
- func->metaness() == FunctionNode::Dtor
- || func->overloadNumber() != 1)
+ func->metaness() == FunctionNode::Dtor ||
+ func->overloadNumber() != 1)
names.clear();
}
else if ((*m)->type() == Node::Property) {
- const PropertyNode *prop =
- reinterpret_cast<const PropertyNode *>(*m);
+ const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m);
if (!prop->getters().isEmpty() &&
!names.contains(prop->getters().first()->name()))
names << prop->getters().first()->name();
@@ -1056,14 +1171,13 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
names << prop->resetters().first()->name();
}
else if ((*m)->type() == Node::Enum) {
- const EnumNode *enume =
- reinterpret_cast<const EnumNode *>(*m);
+ 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())
+ enume->doc().enumItemNames().toSet() -
+ enume->doc().omitEnumItemNames().toSet())
names << plainCode(marker->markedUpEnumValue(enumName,
enume));
}
@@ -1229,7 +1343,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
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;
}
@@ -1493,17 +1607,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())
@@ -1686,13 +1802,13 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
}
out() << "<p><ul><li><a href=\""
- << linkForNode(inner, 0)
- << "\">" << protect(inner->name())
+ << 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";
- generateSectionList(sections.at(i),inner,marker,CodeMarker::Summary);
+ out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n";
+ generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
}
sections = marker->sections(inner, CodeMarker::Detailed, status);
@@ -1715,8 +1831,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
void HtmlGenerator::generateClassHierarchy(const Node *relative,
CodeMarker *marker,
- const QMap<QString,
- const Node *> &classMap)
+ const QMap<QString,const Node*> &classMap)
{
if (classMap.isEmpty())
return;
@@ -1938,7 +2053,9 @@ void HtmlGenerator::generateCompactList(const Node *relative,
out() << "<td align=\"right\">";
if (currentOffsetInParagraph[i] == 0) {
// start a new paragraph
- out() << "<b>" << paragraphName[currentParagraphNo[i]] << "&nbsp;</b>";
+ out() << "<b>"
+ << paragraphName[currentParagraphNo[i]]
+ << "&nbsp;</b>";
}
out() << "</td>\n";
@@ -1951,7 +2068,9 @@ void HtmlGenerator::generateCompactList(const Node *relative,
out() << "<td>";
// Previously, we used generateFullName() for this, but we
// require some special formatting.
- out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">";
+ out() << "<a href=\""
+ << linkForNode(it.value(), relative)
+ << "\">";
QStringList pieces = fullName(it.value(), relative, marker).split("::");
out() << protect(pieces.last());
out() << "</a>";
@@ -2040,7 +2159,7 @@ void HtmlGenerator::generateLegaleseList(const Node *relative,
}
}
-void HtmlGenerator::generateSynopsis(const Node *node,
+/*void HtmlGenerator::generateSynopsis(const Node *node,
const Node *relative,
CodeMarker *marker,
CodeMarker::SynopsisStyle style)
@@ -2076,7 +2195,7 @@ void HtmlGenerator::generateSynopsis(const Node *node,
marked.replace("</@type>", "");
}
out() << highlightedCode(marked, marker, relative);
-}
+}*/
#ifdef QDOC_QML
void HtmlGenerator::generateQmlItem(const Node *node,
@@ -2111,8 +2230,7 @@ void HtmlGenerator::generateQmlItem(const Node *node,
}
#endif
-void HtmlGenerator::generateOverviewList(const Node *relative,
- CodeMarker * /* marker */)
+void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */)
{
QMap<const FakeNode *, QMap<QString, FakeNode *> > fakeNodeMap;
QMap<QString, const FakeNode *> groupTitlesMap;
@@ -2226,24 +2344,35 @@ void HtmlGenerator::generateOverviewList(const Node *relative,
}
}
+#ifdef QDOC_NAME_ALIGNMENT
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) {
twoColumn = (section.members.count() >= 5);
+ name_alignment = false;
+ }
+ if (name_alignment) {
+ out() << "<table border=\"0\" cellpadding=\"0\" "
+ << "cellspacing=\"0\" width=\"100%\">\n";
+ }
+ else {
+ if (twoColumn)
+ out() << "<p><table 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();
@@ -2253,80 +2382,51 @@ void HtmlGenerator::generateSectionList(const Section& section,
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";
}
}
-#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";
- }
-}
-#endif
-
void HtmlGenerator::generateSectionInheritedList(const Section& section,
const Node *relative,
- CodeMarker *marker)
+ 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;
@@ -2342,298 +2442,325 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section,
}
}
-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]|_");
+ 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>");
- 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));
+ if (style == CodeMarker::Summary) {
+ marked.replace("<@name>", ""); // was "<b>"
+ marked.replace("</@name>", ""); // was "</b>"
}
- 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>";
+
+ if (style == CodeMarker::SeparateList) {
+ QRegExp extraRegExp("<@extra>.*</@extra>");
+ extraRegExp.setMinimal(true);
+ marked.replace(extraRegExp, "");
+ } else {
+ marked.replace("<@extra>", "&nbsp;&nbsp;<tt>");
+ marked.replace("</@extra>", "</tt>");
}
- else {
- out() << protect(atom->string());
+
+ if (style != CodeMarker::Detailed) {
+ marked.replace("<@type>", "");
+ marked.replace("</@type>", "");
}
+ out() << highlightedCode(marked, marker, relative, style, nameAlignment);
}
-QString HtmlGenerator::cleanRef(const QString& ref)
+QString HtmlGenerator::highlightedCode(const QString& markedCode,
+ CodeMarker *marker,
+ const Node *relative,
+ CodeMarker::SynopsisStyle style,
+ bool nameAlignment)
{
- QString clean;
-
- if (ref.isEmpty())
- return clean;
-
- clean.reserve(ref.size() + 20);
- const QChar c = ref[0];
- const uint u = c.unicode();
+ QString src = markedCode;
+ QString html;
+ QStringRef arg;
+ QStringRef par1;
- 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";
- }
+ const QChar charLangle = '<';
+ const QChar charAt = '@';
- 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 += "#";
+ // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)"
+ static const QString linkTag("link");
+ if (src.contains("setAcceptDrops"))
+ qDebug() << "SRC:" << src;
+ 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 {
- clean += "-";
- clean += QString::number((int)u, 16);
+ html += src.at(i++);
}
}
- 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;
+ 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++);
+ }
}
- 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("&amp;");
- }
- else if (ch == QLatin1Char('<')) {
- APPEND("&lt;");
- }
- else if (ch == QLatin1Char('>')) {
- APPEND("&gt;");
+ // 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 if (ch == QLatin1Char('"')) {
- APPEND("&quot;");
+ else {
+ html += src.at(i++);
}
- 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(';');
+ }
+
+ // 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 {
- if (!html.isEmpty())
- html += ch;
+ html += src.at(i);
+ ++i;
}
}
- if (!html.isEmpty())
- return html;
- return string;
-
-#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 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;
- }
- else {
- if (debug)
- qDebug() << "no optional parameter found";
+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 {
+ 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>", "&nbsp;&nbsp;<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,
@@ -2795,6 +2922,153 @@ 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("&amp;");
+ } else if (ch == QLatin1Char('<')) {
+ APPEND("&lt;");
+ } else if (ch == QLatin1Char('>')) {
+ APPEND("&gt;");
+ } else if (ch == QLatin1Char('"')) {
+ APPEND("&quot;");
+ } 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)
{
@@ -3020,7 +3294,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);
}
}
@@ -3046,7 +3320,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;
@@ -3094,7 +3369,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);
}
}
}
@@ -3432,6 +3707,46 @@ 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.
*/