From 17472a2ba329a0d329aa21c9ffef62fec0de46c5 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 28 Oct 2014 14:25:44 +0100 Subject: qdoc: Generate cross-module links-to-links pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cross-module link report is modified so that each module listed in the table is a link to a subpage on which all the links from the current module to that module are listed. To check that these links go to the correct place, click on one to be taken to the actual link. The actual link is marked with red asterisks. Click on that link to check that the link goes to the correct page. Repeat this process for all the links in the table. Change-Id: Ifddf7108ed7ef090c4063909fdbd10dac1f2566b Task-number: QTBUG-41850 Reviewed-by: Topi Reiniƶ --- doc/global/template/style/offline.css | 5 ++ doc/global/template/style/online.css | 5 ++ src/tools/qdoc/atom.cpp | 4 ++ src/tools/qdoc/atom.h | 18 ++--- src/tools/qdoc/doc.cpp | 4 +- src/tools/qdoc/htmlgenerator.cpp | 123 ++++++++++++++++++++-------------- src/tools/qdoc/htmlgenerator.h | 1 + src/tools/qdoc/qdocdatabase.h | 5 ++ src/tools/qdoc/tree.cpp | 59 +++++++++++++++- src/tools/qdoc/tree.h | 22 +++++- 10 files changed, 181 insertions(+), 65 deletions(-) diff --git a/doc/global/template/style/offline.css b/doc/global/template/style/offline.css index 5957e3840d..5adb699972 100644 --- a/doc/global/template/style/offline.css +++ b/doc/global/template/style/offline.css @@ -62,6 +62,11 @@ a:link { text-align: left; } +a.qa-mark:target:before { + content: "***"; + color: #ff0000; +} + a:hover { color: #44a51c; text-align: left; diff --git a/doc/global/template/style/online.css b/doc/global/template/style/online.css index 5d0cd7ecfb..c44f7ea672 100644 --- a/doc/global/template/style/online.css +++ b/doc/global/template/style/online.css @@ -43,6 +43,11 @@ links ----------- */ +a.qa-mark:target:before { + content: "***"; + color: #ff0000; +} + .flags { text-decoration: none; text-height: 24px; diff --git a/src/tools/qdoc/atom.cpp b/src/tools/qdoc/atom.cpp index 1af31afedd..e227526d90 100644 --- a/src/tools/qdoc/atom.cpp +++ b/src/tools/qdoc/atom.cpp @@ -107,6 +107,8 @@ QT_BEGIN_NAMESPACE \value ListItemLeft \value ListItemRight \value ListRight + \value NavAutoLink + \value NavLink \value Nop \value Note \value ParaLeft @@ -193,6 +195,8 @@ static const struct { { "ListItemLeft", Atom::ListItemLeft }, { "ListItemRight", Atom::ListItemRight }, { "ListRight", Atom::ListRight }, + { "NavAutoLink", Atom::NavAutoLink }, + { "NavLink", Atom::NavLink }, { "Nop", Atom::Nop }, { "NoteLeft", Atom::NoteLeft }, { "NoteRight", Atom::NoteRight }, diff --git a/src/tools/qdoc/atom.h b/src/tools/qdoc/atom.h index 3a7e992f7b..daa94a1fb8 100644 --- a/src/tools/qdoc/atom.h +++ b/src/tools/qdoc/atom.h @@ -57,7 +57,7 @@ public: BriefRight, C, CaptionLeft, - CaptionRight, // 10 + CaptionRight, Code, CodeBad, CodeNew, @@ -67,7 +67,7 @@ public: DivLeft, DivRight, EndQmlText, - FootnoteLeft, // 20 + FootnoteLeft, FootnoteRight, FormatElse, FormatEndif, @@ -77,7 +77,7 @@ public: GeneratedList, GuidLink, HR, - Image, // 30 + Image, ImageText, ImportantLeft, ImportantRight, @@ -87,7 +87,7 @@ public: LegaleseLeft, LegaleseRight, LineBreak, - Link, // 40 + Link, LinkNode, ListLeft, ListItemNumber, @@ -96,8 +96,10 @@ public: ListItemLeft, ListItemRight, ListRight, + NavAutoLink, + NavLink, Nop, - NoteLeft, // 50 + NoteLeft, NoteRight, ParaLeft, ParaRight, @@ -107,7 +109,7 @@ public: QuotationRight, RawString, SectionLeft, - SectionRight, // 60 + SectionRight, SectionHeadingLeft, SectionHeadingRight, SidebarLeft, @@ -117,7 +119,7 @@ public: SnippetIdentifier, SnippetLocation, String, - TableLeft, // 70 + TableLeft, TableRight, TableHeaderLeft, TableHeaderRight, @@ -127,7 +129,7 @@ public: TableItemRight, TableOfContents, Target, - UnhandledFormat, // 80 + UnhandledFormat, UnknownCommand, Last = UnknownCommand }; diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp index cdb8472e4f..53d8ea885d 100644 --- a/src/tools/qdoc/doc.cpp +++ b/src/tools/qdoc/doc.cpp @@ -1991,7 +1991,7 @@ void DocParser::append(const QString &string) Atom::Type lastType = priv->text.lastAtom()->type(); if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) priv->text.lastAtom()->chopString(); - priv->text << Atom(string); + priv->text << Atom(string); // The Atom type is Link. } void DocParser::append(Atom::Type type, const QString& p1, const QString& p2) @@ -2008,7 +2008,7 @@ void DocParser::append(const QString& p1, const QString& p2) if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) priv->text.lastAtom()->chopString(); if (p2.isEmpty()) - priv->text << Atom(p1); + priv->text << Atom(p1); // The Atom type is Link. else priv->text << LinkAtom(p1, p2); } diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index ca58be57c7..f08f84abae 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -327,7 +327,10 @@ void HtmlGenerator::generateQAPage() << "class=\"even\">Destination Module" << "Link Count\n"; for (int i = 0; i< strings.size(); ++i) { - out() << "" << strings.at(i) + QString fileName = generateLinksToLinksPage(strings.at(i), marker); + out() << "" + << "" + << strings.at(i) << "" << "" << counts.at(i) << "\n"; } @@ -339,7 +342,39 @@ void HtmlGenerator::generateQAPage() out() << "

" << protectEnc(t) << "

\n"; out() << "

" << protectEnc(depends) << "

\n"; } + generateFooter(); + endSubPage(); +} + +/*! + */ +QString HtmlGenerator::generateLinksToLinksPage(const QString& module, CodeMarker* marker) +{ + NamespaceNode* node = qdb_->primaryTreeRoot(); + QString fileName = "aaa-links-to-" + module + ".html"; + beginSubPage(node, fileName); + QString title = "Links from " + defaultModuleName() + " to " + module; + generateHeader(title, node, marker); + generateTitle(title, Text(), SmallSubTitle, node, marker); + out() << "

This is the complete list of links from " << defaultModuleName() + << " to " << module << ". "; + out() << "Click on a link to go directly to the actual link in the docs. "; + out() << "Then click on that link to check whether it goes to the correct place.

\n"; + TargetList* tlist = qdb_->getTargetList(module); + if (tlist) { + out() << "\n"; + foreach (TargetLoc* t, *tlist) { + // e.g.: Layout Management + out() << "\n"; + } + out() << "
"; + out() << "fileName_ << "#" << t->target_ << "\">"; + out() << t->text_ << ""; + out() << "
\n"; + } + generateFooter(); endSubPage(); + return fileName; } /*! @@ -360,6 +395,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::AbstractRight: break; case Atom::AutoLink: + case Atom::NavAutoLink: if (!inLink_ && !inContents_ && !inSectionHeading_) { const Node *node = 0; QString link = getAutoLink(atom, relative, &node); @@ -374,6 +410,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark if (link.isEmpty()) out() << protectEnc(atom->string()); else { + if (Generator::writeQaPages() && node && (atom->type() != Atom::NavAutoLink)) { + QString text = atom->string(); + QString target = qdb_->getNewLinkTarget(node, outFileName(), text); + out() << ""; + } beginLink(link, node, relative); generateLink(atom, marker); endLink(); @@ -856,6 +897,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "
"; break; case Atom::Link: + case Atom::NavLink: { inObsoleteLink = false; const Node *node = 0; @@ -864,6 +906,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string())); } else { + if (Generator::writeQaPages() && node && (atom->type() != Atom::NavLink)) { + QString text = atom->next()->next()->string(); + QString target = qdb_->getNewLinkTarget(node, outFileName(), text); + out() << ""; + } + /* + mws saw this on 17/10/2014. + Is this correct? Setting node to 0 means the + following test always fails. Did we decide to + no longer warn about linking to obsolete things? + */ node = 0; if (node && node->status() == Node::Obsolete) { if ((relative->parent() != node) && !relative->isObsolete()) { @@ -1698,11 +1751,11 @@ void HtmlGenerator::generateNavigationBar(const QString &title, return; if (!homepage.isEmpty()) navigationbar << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, homepage) + << Atom(Atom::NavAutoLink, homepage) << Atom(Atom::ListItemRight); if (!landingpage.isEmpty() && landingpage != title) navigationbar << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, landingpage) + << Atom(Atom::NavAutoLink, landingpage) << Atom(Atom::ListItemRight); if (node->isClass()) { @@ -1711,7 +1764,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title, if (!cppclassespage.isEmpty()) navigationbar << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, cppclassespage) + << Atom(Atom::NavLink, cppclassespage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, QLatin1String("C++ Classes")) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) @@ -1725,7 +1778,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title, else if (node->isQmlType() || node->isQmlBasicType()) { if (!qmltypespage.isEmpty()) navigationbar << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, qmltypespage) + << Atom(Atom::NavLink, qmltypespage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, QLatin1String("QML Types")) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) @@ -1737,7 +1790,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title, else { if (node->isExampleFile()) { navigationbar << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, node->parent()->name()) + << Atom(Atom::NavLink, node->parent()->name()) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, node->parent()->title()) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) @@ -3711,36 +3764,7 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod if (t.startsWith("mailto:")) return t; } - - QString ref; - - *node = qdb_->findNodeForAtom(atom, relative, ref); - if (!(*node)) - return QString(); - if (Generator::writeQaPages()) - qdb_->incrementLinkCount(*node); - - QString url = (*node)->url(); - if (!url.isEmpty()) { - if (ref.isEmpty()) - return url; - int hashtag = url.lastIndexOf(QChar('#')); - if (hashtag != -1) - url.truncate(hashtag); - return url + "#" + ref; - } - /* - Given that *node is not null, we now cconstruct a link - to the page that *node represents, and then if we found - a target on that page, we connect the target to the link - with '#'. - */ - QString link = linkForNode(*node, relative); - if (*node && (*node)->subType() == Node::Image) - link = "images/used-in-examples/" + link; - if (!ref.isEmpty()) - link += QLatin1Char('#') + ref; - return link; + return getAutoLink(atom, relative, node); } /*! @@ -3758,28 +3782,25 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node) { QString ref; - QString link; *node = qdb_->findNodeForAtom(atom, relative, ref); if (!(*node)) return QString(); - if (Generator::writeQaPages()) - qdb_->incrementLinkCount(*node); - - QString url = (*node)->url(); - if (!url.isEmpty()) { - if (ref.isEmpty()) - return url; - int hashtag = url.lastIndexOf(QChar('#')); + QString link = (*node)->url(); + if (link.isEmpty()) { + link = linkForNode(*node, relative); + if ((*node)->subType() == Node::Image) + link = "images/used-in-examples/" + link; + if (!ref.isEmpty()) + link += QLatin1Char('#') + ref; + } + else if (!ref.isEmpty()) { + int hashtag = link.lastIndexOf(QChar('#')); if (hashtag != -1) - url.truncate(hashtag); - return url + "#" + ref; + link.truncate(hashtag); + link += "#" + ref; } - - link = linkForNode(*node, relative); - if (!ref.isEmpty()) - link += QLatin1Char('#') + ref; return link; } diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index 825522a121..b8ead2bbec 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -90,6 +90,7 @@ public: protected: virtual void generateQAPage(); + QString generateLinksToLinksPage(const QString& module, CodeMarker* marker); virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker); diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h index 02d39e62e7..09bfbbfac3 100644 --- a/src/tools/qdoc/qdocdatabase.h +++ b/src/tools/qdoc/qdocdatabase.h @@ -392,6 +392,11 @@ class QDocDatabase QString getLinkCounts(QStringList& strings, QVector& counts) { return forest_.getLinkCounts(strings, counts); } + QString getNewLinkTarget(const Node* t, const QString& fileName, QString& text) { + return primaryTree()->getNewLinkTarget(t, fileName, text); + } + TargetList* getTargetList(const QString& t) { return primaryTree()->getTargetList(t); } + QStringList getTargetListKeys() { return primaryTree()->getTargetListKeys(); } private: friend class QDocIndexFiles; diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index f3a6ed78da..6610bd0db4 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -71,10 +71,14 @@ Tree::Tree(const QString& module, QDocDatabase* qdb) linkCount_(0), module_(module), qdb_(qdb), - root_(0, QString()) + root_(0, QString()), + targetListMap_(0) { root_.setModuleName(module_); root_.setTree(this); + if (Generator::writeQaPages()) { + targetListMap_ = new TargetListMap; + } } /*! @@ -100,6 +104,18 @@ Tree::~Tree() } nodesByTargetRef_.clear(); nodesByTargetTitle_.clear(); + if (Generator::writeQaPages() && targetListMap_) { + TargetListMap::iterator i = targetListMap_->begin(); + while (i != targetListMap_->end()) { + TargetList* tlist = i.value(); + if (tlist) { + foreach (TargetLoc* tloc, *tlist) + delete tloc; + } + delete tlist; + ++i; + } + } } /* API members */ @@ -1399,4 +1415,45 @@ const Node* Tree::checkForCollision(const QString& name) return findNode(QStringList(name), 0, 0, Node::DontCare); } +/*! + Generate a target of the form link-nnn, where the nnn is + the current link count for this tree. This target string + is returned. It will be output as an HTML anchor just before + an HTML link to the node \a t. + + The node \a t + */ +QString Tree::getNewLinkTarget(const Node* t, const QString& fileName, QString& text) +{ + QString target; + if (t) { + Tree* tree = t->tree(); + incrementLinkCount(); + if (tree != this) + tree->incrementLinkCount(); + target = QString("qa-target-%1").arg(-(linkCount())); + QString moduleName = tree->moduleName(); + TargetLoc* tloc = new TargetLoc(target, fileName, text); + TargetList* tList = 0; + TargetListMap::iterator i = targetListMap_->find(moduleName); + if (i == targetListMap_->end()) { + tList = new TargetList; + i = targetListMap_->insert(moduleName, tList); + } + else + tList = i.value(); + tList->append(tloc); + } + return target; +} + +/*! + Look up the target list for the specified \a module + and return a pointer to it. + */ +TargetList* Tree::getTargetList(const QString& module) +{ + return targetListMap_->value(module); +} + QT_END_NAMESPACE diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h index 75f751f976..9c55595a77 100644 --- a/src/tools/qdoc/tree.h +++ b/src/tools/qdoc/tree.h @@ -67,10 +67,22 @@ struct TargetRec Type type_; }; +struct TargetLoc +{ + public: + TargetLoc(const QString& t, const QString& fileName, const QString& text) + : target_(t), fileName_(fileName), text_(text) { } + QString target_; + QString fileName_; + QString text_; +}; + typedef QMultiMap TargetMap; typedef QMultiMap DocNodeMultiMap; typedef QMap QmlTypeMap; typedef QMultiMap ExampleNodeMap; +typedef QVector TargetList; +typedef QMap TargetListMap; class Tree { @@ -193,18 +205,21 @@ class Tree bool docsHaveBeenGenerated() const { return docsHaveBeenGenerated_; } void setTreeHasBeenAnalyzed() { treeHasBeenAnalyzed_ = true; } void setdocsHaveBeenGenerated() { docsHaveBeenGenerated_ = true; } + QString getNewLinkTarget(const Node* t, const QString& fileName, QString& text); + TargetList* getTargetList(const QString& module); + QStringList getTargetListKeys() { return targetListMap_->keys(); } public: const QString& moduleName() const { return module_; } const QString& indexFileName() const { return indexFileName_; } - void incrementLinkCount() { --linkCount_; } + long incrementLinkCount() { return --linkCount_; } void clearLinkCount() { linkCount_ = 0; } - int linkCount() const { return linkCount_; } + long linkCount() const { return linkCount_; } private: bool treeHasBeenAnalyzed_; bool docsHaveBeenGenerated_; - int linkCount_; + long linkCount_; QString module_; QString indexFileName_; QDocDatabase* qdb_; @@ -218,6 +233,7 @@ private: CNMap qmlModules_; QmlTypeMap qmlTypeMap_; ExampleNodeMap exampleNodeMap_; + TargetListMap* targetListMap_; }; QT_END_NAMESPACE -- cgit v1.2.3