qdoc: Give documenter more control of linking
This update enables using the module name as the parameter in square brackets for the \l command. You will use this when your link goes to the wrong page. e.g. Suppose this link command went to a page in QtGui instead of the page where it is meant to go in QtQuick: \l { mytarget } { the text for my link } When a link goes to a page in the wrong module, it means the target exists in more than one module and because qdoc searches the modules in sequence and stops when it finds a match, it might match the wrong target. This would be a collision in the single tree version of qdoc, but now qdoc builds a separate tree for each module. Since you know which module you want your link to go to, put the module name in square brackets as the first parameter, like this: \l [QtQuick] { mytarget } { the text for my link } Now qdoc will only search for mytarget in the tree for the QtQuick module. The \target command can now be used anywhere. It has not been tested in all possible locations, but it works in the places where people have asked why it doesn't work there. There will be a further update to complete this task for implementing the other types of parameters that can be in the square brackets. Task-number: QTBUG-39221 Change-Id: I2db4fdd0319ff272ec1d2fa9dc396f14599d80f9 Reviewed-by: Martin Smith <martin.smith@digia.com>
This commit is contained in:
parent
b6ba4ac00d
commit
d8062f117b
@ -374,22 +374,51 @@ void Atom::dump() const
|
||||
contains some search parameters.
|
||||
*/
|
||||
LinkAtom::LinkAtom(const QString& p1, const QString& p2)
|
||||
: Atom(Link, p1), qml_(false), goal_(Node::NoType), domain_(0)
|
||||
: Atom(p1), genus_(DontCare), goal_(Node::NoType), domain_(0)
|
||||
{
|
||||
QStringList params = p2.toLower().split(QLatin1Char(' '));
|
||||
foreach (const QString& p, params) {
|
||||
if (p == "qml")
|
||||
qml_ = true;
|
||||
else {
|
||||
if (!domain_) {
|
||||
domain_ = QDocDatabase::qdocDB()->findTree(p);
|
||||
if (domain_)
|
||||
continue;
|
||||
}
|
||||
if (goal_ == Node::NoType)
|
||||
goal_ = Node::goal(p);
|
||||
if (!domain_) {
|
||||
domain_ = QDocDatabase::qdocDB()->findTree(p);
|
||||
if (domain_)
|
||||
continue;
|
||||
}
|
||||
if (goal_ == Node::NoType) {
|
||||
goal_ = Node::goal(p);
|
||||
if (goal_ != Node::NoType)
|
||||
continue;
|
||||
}
|
||||
if (p == "qml")
|
||||
genus_ = QML;
|
||||
else if (p == "cpp")
|
||||
genus_ = CPP;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Standard copy constructor of LinkAtom \a t.
|
||||
*/
|
||||
LinkAtom::LinkAtom(const LinkAtom& t)
|
||||
: Atom(Link, t.string()),
|
||||
genus_(t.genus_),
|
||||
goal_(t.goal_),
|
||||
domain_(t.domain_)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
/*!
|
||||
Special copy constructor of LinkAtom \a t, where
|
||||
where the new LinkAtom will not be the first one
|
||||
in the list.
|
||||
*/
|
||||
LinkAtom::LinkAtom(Atom* previous, const LinkAtom& t)
|
||||
: Atom(previous, Link, t.string()),
|
||||
genus_(t.genus_),
|
||||
goal_(t.goal_),
|
||||
domain_(t.domain_)
|
||||
{
|
||||
previous->next_ = this;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -44,10 +44,12 @@
|
||||
|
||||
#include <qstringlist.h>
|
||||
#include "node.h"
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Tree;
|
||||
class LinkAtom;
|
||||
|
||||
class Atom
|
||||
{
|
||||
@ -63,7 +65,7 @@ public:
|
||||
BriefRight,
|
||||
C,
|
||||
CaptionLeft,
|
||||
CaptionRight,
|
||||
CaptionRight, // 10
|
||||
Code,
|
||||
CodeBad,
|
||||
CodeNew,
|
||||
@ -73,7 +75,7 @@ public:
|
||||
DivLeft,
|
||||
DivRight,
|
||||
EndQmlText,
|
||||
FootnoteLeft,
|
||||
FootnoteLeft, // 20
|
||||
FootnoteRight,
|
||||
FormatElse,
|
||||
FormatEndif,
|
||||
@ -83,7 +85,7 @@ public:
|
||||
GeneratedList,
|
||||
GuidLink,
|
||||
HR,
|
||||
Image,
|
||||
Image, // 30
|
||||
ImageText,
|
||||
ImportantLeft,
|
||||
ImportantRight,
|
||||
@ -93,7 +95,7 @@ public:
|
||||
LegaleseLeft,
|
||||
LegaleseRight,
|
||||
LineBreak,
|
||||
Link,
|
||||
Link, // 40
|
||||
LinkNode,
|
||||
ListLeft,
|
||||
ListItemNumber,
|
||||
@ -103,7 +105,7 @@ public:
|
||||
ListItemRight,
|
||||
ListRight,
|
||||
Nop,
|
||||
NoteLeft,
|
||||
NoteLeft, // 50
|
||||
NoteRight,
|
||||
ParaLeft,
|
||||
ParaRight,
|
||||
@ -113,7 +115,7 @@ public:
|
||||
QuotationRight,
|
||||
RawString,
|
||||
SectionLeft,
|
||||
SectionRight,
|
||||
SectionRight, // 60
|
||||
SectionHeadingLeft,
|
||||
SectionHeadingRight,
|
||||
SidebarLeft,
|
||||
@ -123,7 +125,7 @@ public:
|
||||
SnippetIdentifier,
|
||||
SnippetLocation,
|
||||
String,
|
||||
TableLeft,
|
||||
TableLeft, // 70
|
||||
TableRight,
|
||||
TableHeaderLeft,
|
||||
TableHeaderRight,
|
||||
@ -133,11 +135,21 @@ public:
|
||||
TableItemRight,
|
||||
TableOfContents,
|
||||
Target,
|
||||
UnhandledFormat,
|
||||
UnhandledFormat, // 80
|
||||
UnknownCommand,
|
||||
Last = UnknownCommand
|
||||
};
|
||||
|
||||
enum NodeGenus { DontCare, CPP, QML };
|
||||
|
||||
friend class LinkAtom;
|
||||
|
||||
Atom(const QString& string)
|
||||
: next_(0), type_(Link)
|
||||
{
|
||||
strs << string;
|
||||
}
|
||||
|
||||
Atom(Type type, const QString& string = "")
|
||||
: next_(0), type_(type)
|
||||
{
|
||||
@ -186,8 +198,10 @@ public:
|
||||
const QString& string(int i) const { return strs[i]; }
|
||||
int count() const { return strs.size(); }
|
||||
void dump() const;
|
||||
const QStringList& strings() const { return strs; }
|
||||
|
||||
virtual bool qml() const { return false; }
|
||||
virtual bool isLinkAtom() const { return false; }
|
||||
virtual NodeGenus genus() const { return DontCare; }
|
||||
virtual bool specifiesDomain() const { return false; }
|
||||
virtual Tree* domain() const { return 0; }
|
||||
virtual Node::Type goal() const { return Node::NoType; }
|
||||
@ -202,15 +216,18 @@ class LinkAtom : public Atom
|
||||
{
|
||||
public:
|
||||
LinkAtom(const QString& p1, const QString& p2);
|
||||
LinkAtom(const LinkAtom& t);
|
||||
LinkAtom(Atom* previous, const LinkAtom& t);
|
||||
virtual ~LinkAtom() { }
|
||||
|
||||
virtual bool qml() const { return qml_; }
|
||||
virtual bool isLinkAtom() const { return true; }
|
||||
virtual NodeGenus genus() const { return genus_; }
|
||||
virtual bool specifiesDomain() const { return (domain_ != 0); }
|
||||
virtual Tree* domain() const { return domain_; }
|
||||
virtual Node::Type goal() const { return goal_; }
|
||||
|
||||
protected:
|
||||
bool qml_;
|
||||
NodeGenus genus_;
|
||||
Node::Type goal_;
|
||||
Tree* domain_;
|
||||
};
|
||||
|
@ -765,7 +765,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
|
||||
case Atom::AutoLink:
|
||||
if (!noLinks && !inLink_ && !inContents_ && !inSectionHeading_) {
|
||||
const Node* node = 0;
|
||||
QString link = getLink(atom, relative, &node);
|
||||
QString link = getAutoLink(atom, relative, &node);
|
||||
if (!link.isEmpty()) {
|
||||
beginLink(link);
|
||||
generateLink(atom, marker);
|
||||
@ -1308,13 +1308,11 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
|
||||
case Atom::Link:
|
||||
{
|
||||
const Node *node = 0;
|
||||
QString myLink = getLink(atom, relative, &node);
|
||||
//if (myLink.isEmpty())
|
||||
//myLink = getCollisionLink(atom);
|
||||
if (myLink.isEmpty() && !noLinkErrors())
|
||||
QString link = getLink(atom, relative, &node);
|
||||
if (link.isEmpty() && !noLinkErrors())
|
||||
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
|
||||
else if (!inSectionHeading_)
|
||||
beginLink(myLink);
|
||||
beginLink(link);
|
||||
skipAhead = 1;
|
||||
}
|
||||
break;
|
||||
@ -3722,6 +3720,129 @@ QString DitaXmlGenerator::fileName(const Node* node)
|
||||
return Generator::fileName(node);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called for links, i.e. for words that
|
||||
are marked with the qdoc link command. For autolinks
|
||||
that are not marked with the qdoc link command, qdoc
|
||||
calls getAutoLink().
|
||||
|
||||
Return the link represented by the \a atom, and set \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString DitaXmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
|
||||
atom->string().startsWith("http:") ||
|
||||
atom->string().startsWith("https:") ||
|
||||
atom->string().startsWith("ftp:") ||
|
||||
atom->string().startsWith("mailto:"))) {
|
||||
return atom->string(); // It's some kind of protocol.
|
||||
}
|
||||
|
||||
QString ref;
|
||||
QString link;
|
||||
QStringList path = atom->string().split("#");
|
||||
QString first = path.first().trimmed();
|
||||
|
||||
*node = 0;
|
||||
if (first.isEmpty())
|
||||
*node = relative; // search for a target on the current page.
|
||||
else {
|
||||
if (first.endsWith(".html")) { // The target is an html file.
|
||||
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
|
||||
}
|
||||
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(first, relative);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(first, relative);
|
||||
if (!(*node))
|
||||
*node = qdb_->findDocNodeByTitle(first);
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(first, ref);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
return final;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(*node))
|
||||
return link; // empty
|
||||
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
|
||||
if (!path.isEmpty()) {
|
||||
ref = qdb_->findTarget(path.first(), *node);
|
||||
if (ref.isEmpty())
|
||||
return link; // empty
|
||||
}
|
||||
|
||||
/*
|
||||
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 '#'.
|
||||
*/
|
||||
link = linkForNode(*node, relative);
|
||||
if (*node && (*node)->subType() == Node::Image)
|
||||
link = "images/used-in-examples/" + link;
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
return link;
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called for autolinks, i.e. for words that
|
||||
are not marked with the qdoc link command that qdoc has
|
||||
reason to believe should be links. For links marked with
|
||||
the qdoc link command, qdoc calls getLink().
|
||||
|
||||
Return the link represented by the \a atom, and set \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString DitaXmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
QString ref;
|
||||
QString link;
|
||||
QString target = atom->string().trimmed();
|
||||
*node = 0;
|
||||
|
||||
if (target.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(target, relative);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(target, relative);
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findDocNodeByTitle(target);
|
||||
}
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(target, ref);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
return final;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*node))
|
||||
return link; // empty
|
||||
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
|
||||
link = linkForNode(*node, relative);
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative)
|
||||
{
|
||||
if (node == 0 || node == relative)
|
||||
@ -3832,103 +3953,6 @@ const QPair<QString,QString> DitaXmlGenerator::anchorForNode(const Node* node)
|
||||
return anchorPair;
|
||||
}
|
||||
|
||||
QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const Node** node)
|
||||
{
|
||||
QString link;
|
||||
*node = 0;
|
||||
inObsoleteLink = false;
|
||||
|
||||
if (atom->string().contains(QLatin1Char(':')) &&
|
||||
(atom->string().startsWith("file:")
|
||||
|| atom->string().startsWith("http:")
|
||||
|| atom->string().startsWith("https:")
|
||||
|| atom->string().startsWith("ftp:")
|
||||
|| atom->string().startsWith("mailto:"))) {
|
||||
|
||||
link = atom->string();
|
||||
}
|
||||
else {
|
||||
QStringList path;
|
||||
if (atom->string().contains('#'))
|
||||
path = atom->string().split('#');
|
||||
else
|
||||
path.append(atom->string());
|
||||
|
||||
QString ref;
|
||||
QString first = path.first().trimmed();
|
||||
|
||||
if (first.isEmpty())
|
||||
*node = relative;
|
||||
else if (first.endsWith(".html"))
|
||||
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
|
||||
else if (first.endsWith("()")) // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(first, relative);
|
||||
else {
|
||||
*node = qdb_->resolveTarget(first, relative);
|
||||
if (!(*node))
|
||||
*node = qdb_->findDocNodeByTitle(first);
|
||||
if (!*node)
|
||||
*node = qdb_->findUnambiguousTarget(first, ref);
|
||||
}
|
||||
|
||||
if (*node) {
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
else
|
||||
path.removeFirst();
|
||||
}
|
||||
else
|
||||
*node = relative;
|
||||
|
||||
if (*node && (*node)->status() == Node::Obsolete) {
|
||||
if (relative && (relative->parent() != *node) &&
|
||||
(relative->status() != Node::Obsolete)) {
|
||||
bool porting = false;
|
||||
if (relative->isDocNode()) {
|
||||
const DocNode* fake = static_cast<const DocNode*>(relative);
|
||||
if (fake->title().startsWith("Porting"))
|
||||
porting = true;
|
||||
}
|
||||
QString name = relative->plainFullName();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!path.isEmpty()) {
|
||||
ref = qdb_->findTarget(path.first(), *node);
|
||||
if (ref.isEmpty())
|
||||
break;
|
||||
path.removeFirst();
|
||||
}
|
||||
|
||||
if (path.isEmpty()) {
|
||||
link = linkForNode(*node, relative);
|
||||
if (*node && (*node)->subType() == Node::Image)
|
||||
link = "images/used-in-examples/" + link;
|
||||
if (!ref.isEmpty()) {
|
||||
if (link.isEmpty())
|
||||
link = outFileName();
|
||||
QString guid = lookupGuid(link, ref);
|
||||
link += QLatin1Char('#') + guid;
|
||||
}
|
||||
else if (!link.isEmpty() && *node && (link.endsWith(".xml") || link.endsWith(".dita"))) {
|
||||
link += QLatin1Char('#') + (*node)->guid();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!link.isEmpty() && link[0] == '#') {
|
||||
link.prepend(outFileName());
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
void DitaXmlGenerator::generateStatus(const Node* node, CodeMarker* marker)
|
||||
{
|
||||
Text text;
|
||||
|
@ -425,12 +425,14 @@ private:
|
||||
void generateLink(const Atom* atom, CodeMarker* marker);
|
||||
void generateStatus(const Node* node, CodeMarker* marker);
|
||||
|
||||
QString getLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
QString getAutoLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
|
||||
QString registerRef(const QString& ref);
|
||||
virtual QString fileBase(const Node *node) const;
|
||||
QString fileName(const Node *node);
|
||||
static int hOffset(const Node *node);
|
||||
static bool isThreeColumnEnumValueTable(const Atom *atom);
|
||||
QString getLink(const Atom *atom, const Node *relative, const Node **node);
|
||||
#ifdef GENERATE_MAC_REFS
|
||||
void generateMacRef(const Node* node, CodeMarker* marker);
|
||||
#endif
|
||||
|
@ -475,6 +475,7 @@ private:
|
||||
void startSection(Doc::Sections unit, int cmd);
|
||||
void endSection(int unit, int endCmd);
|
||||
void parseAlso();
|
||||
void append(const QString &string);
|
||||
void append(Atom::Type type, const QString& string = QString());
|
||||
void append(Atom::Type type, const QString& p1, const QString& p2);
|
||||
void append(const QString& p1, const QString& p2);
|
||||
@ -968,8 +969,9 @@ void DocParser::parse(const QString& source,
|
||||
break;
|
||||
case CMD_L:
|
||||
enterPara();
|
||||
if (isLeftBracketAhead())
|
||||
if (isLeftBracketAhead()) {
|
||||
p2 = getBracketedArgument();
|
||||
}
|
||||
if (isLeftBraceAhead()) {
|
||||
p1 = getArgument();
|
||||
append(p1, p2);
|
||||
@ -990,6 +992,7 @@ void DocParser::parse(const QString& source,
|
||||
append(Atom::String, cleanLink(p1));
|
||||
append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
|
||||
}
|
||||
p2.clear();
|
||||
break;
|
||||
case CMD_LEGALESE:
|
||||
leavePara();
|
||||
@ -1001,7 +1004,7 @@ void DocParser::parse(const QString& source,
|
||||
if (openCommand(cmd)) {
|
||||
enterPara();
|
||||
p1 = getArgument();
|
||||
append(Atom::Link, p1);
|
||||
append(p1);
|
||||
append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
|
||||
skipSpacesOrOneEndl();
|
||||
}
|
||||
@ -1981,6 +1984,14 @@ void DocParser::append(Atom::Type type, const QString &string)
|
||||
priv->text << Atom(type, string);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void DocParser::append(Atom::Type type, const QString& p1, const QString& p2)
|
||||
{
|
||||
Atom::Type lastType = priv->text.lastAtom()->type();
|
||||
@ -1995,7 +2006,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(Atom::Link, p1, p2);
|
||||
priv->text << Atom(p1);
|
||||
else
|
||||
priv->text << LinkAtom(p1, p2);
|
||||
}
|
||||
|
@ -3648,6 +3648,112 @@ QString HtmlGenerator::refForNode(const Node *node)
|
||||
|
||||
#define DEBUG_ABSTRACT 0
|
||||
|
||||
/*!
|
||||
This function is called for links, i.e. for words that
|
||||
are marked with the qdoc link command. For autolinks
|
||||
that are not marked with the qdoc link command, the
|
||||
getAutoLink() function is called
|
||||
|
||||
It returns the string for a link found by using the data
|
||||
in the \a atom to search the database. It also sets \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
const QString& t = atom->string();
|
||||
if (t.at(0) == QChar('h')) {
|
||||
if (t.startsWith("http:") || t.startsWith("https:"))
|
||||
return t;
|
||||
}
|
||||
else if (t.at(0) == QChar('f')) {
|
||||
if (t.startsWith("file:") || t.startsWith("ftp:"))
|
||||
return t;
|
||||
}
|
||||
else if (t.at(0) == QChar('m')) {
|
||||
if (t.startsWith("mailto:"))
|
||||
return t;
|
||||
}
|
||||
|
||||
QString ref;
|
||||
|
||||
*node = qdb_->findNode(atom, relative, ref);
|
||||
if (!(*node))
|
||||
return QString();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called for autolinks, i.e. for words that
|
||||
are not marked with the qdoc link command that qdoc has
|
||||
reason to believe should be links. For links marked with
|
||||
the qdoc link command, the getLink() function is called.
|
||||
|
||||
It returns the string for a link found by using the data
|
||||
in the \a atom to search the database. It also sets \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
QString ref;
|
||||
QString link;
|
||||
QString target = atom->string().trimmed();
|
||||
*node = 0;
|
||||
|
||||
if (target.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(target, relative);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(target, relative);
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findDocNodeByTitle(target);
|
||||
}
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(target, ref);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
return final;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*node))
|
||||
return link; // empty
|
||||
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
|
||||
link = linkForNode(*node, relative);
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Construct the link string for the \a node and return it.
|
||||
The \a relative node is use to decide the link we are
|
||||
@ -3847,137 +3953,6 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
|
||||
return anchorPair;
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called for links, i.e. for words that
|
||||
are marked with the qdoc link command. For autolinks
|
||||
that are not marked with the qdoc link command, qdoc
|
||||
calls getAutoLink().
|
||||
|
||||
Return the link represented by the \a atom, and set \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
|
||||
atom->string().startsWith("http:") ||
|
||||
atom->string().startsWith("https:") ||
|
||||
atom->string().startsWith("ftp:") ||
|
||||
atom->string().startsWith("mailto:"))) {
|
||||
return atom->string(); // It's some kind of protocol.
|
||||
}
|
||||
|
||||
QString ref;
|
||||
QString link;
|
||||
QString first;
|
||||
QStringList path;
|
||||
|
||||
*node = 0;
|
||||
if (atom->string().contains('#')) {
|
||||
path = atom->string().split('#');
|
||||
first = path.first().trimmed();
|
||||
path.removeFirst();
|
||||
}
|
||||
else
|
||||
first = atom->string();
|
||||
|
||||
if (first.isEmpty())
|
||||
*node = relative; // search for a target on the current page.
|
||||
else {
|
||||
if (first.endsWith(".html")) { // The target is an html file.
|
||||
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
|
||||
//Node* n = qdb_->findHtmlFileNode(atom);
|
||||
}
|
||||
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(first, relative);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(first, relative);
|
||||
if (!(*node))
|
||||
*node = qdb_->findDocNodeByTitle(first);
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(first, ref);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
return final;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(*node))
|
||||
return link; // empty
|
||||
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
|
||||
if (!path.isEmpty()) {
|
||||
ref = qdb_->findTarget(path.first(), *node);
|
||||
if (ref.isEmpty())
|
||||
return link; // empty
|
||||
}
|
||||
|
||||
/*
|
||||
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 '#'.
|
||||
*/
|
||||
link = linkForNode(*node, relative);
|
||||
if (*node && (*node)->subType() == Node::Image)
|
||||
link = "images/used-in-examples/" + link;
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
return link;
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is called for autolinks, i.e. for words that
|
||||
are not marked with the qdoc link command that qdoc has
|
||||
reason to believe should be links. For links marked with
|
||||
the qdoc link command, qdoc calls getLink().
|
||||
|
||||
Return the link represented by the \a atom, and set \a node
|
||||
to point to the target node for that link. \a relative points
|
||||
to the node holding the qdoc comment where the link command
|
||||
was found.
|
||||
*/
|
||||
QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
|
||||
{
|
||||
QString ref;
|
||||
QString link;
|
||||
QString path = atom->string().trimmed();
|
||||
*node = 0;
|
||||
|
||||
if (path.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
*node = qdb_->resolveFunctionTarget(path, relative);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(path, relative);
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findDocNodeByTitle(path);
|
||||
}
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(path, ref);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
return final;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*node))
|
||||
return link; // empty
|
||||
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
|
||||
link = linkForNode(*node, relative);
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
return link;
|
||||
}
|
||||
|
||||
void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
|
||||
{
|
||||
Text text;
|
||||
|
@ -211,13 +211,14 @@ private:
|
||||
void generateLink(const Atom *atom, CodeMarker *marker);
|
||||
void generateStatus(const Node *node, CodeMarker *marker);
|
||||
|
||||
QString getLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
QString getAutoLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
|
||||
QString registerRef(const QString& ref);
|
||||
virtual QString fileBase(const Node *node) const;
|
||||
QString fileName(const Node *node);
|
||||
static int hOffset(const Node *node);
|
||||
static bool isThreeColumnEnumValueTable(const Atom *atom);
|
||||
QString getLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
QString getAutoLink(const Atom *atom, const Node *relative, const Node** node);
|
||||
#ifdef GENERATE_MAC_REFS
|
||||
void generateMacRef(const Node *node, CodeMarker *marker);
|
||||
#endif
|
||||
|
@ -292,7 +292,7 @@ static void processQdocconfFile(const QString &fileName)
|
||||
Location::initialize(config);
|
||||
config.load(fileName);
|
||||
QString project = config.getString(CONFIG_PROJECT).toLower();
|
||||
//qDebug() << "\nSTART PROJECT:" << project;
|
||||
//qDebug() << "\nStart project:" << project;
|
||||
/*
|
||||
Add the defines to the configuration variables.
|
||||
*/
|
||||
|
@ -686,6 +686,14 @@ bool Node::isInternal() const
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a pointer to the Tree this node is in.
|
||||
*/
|
||||
Tree* Node::tree() const
|
||||
{
|
||||
return (parent() ? parent()->tree() : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a pointer to the root of the Tree this node is in.
|
||||
*/
|
||||
|
@ -248,7 +248,7 @@ public:
|
||||
virtual bool wasSeen() const { return false; }
|
||||
virtual void appendGroupName(const QString& ) { }
|
||||
virtual QString element() const { return QString(); }
|
||||
virtual Tree* tree() const { return 0; }
|
||||
virtual Tree* tree() const;
|
||||
bool isIndexNode() const { return indexNodeFlag_; }
|
||||
Type type() const { return nodeType_; }
|
||||
virtual SubType subType() const { return NoSubType; }
|
||||
@ -440,7 +440,7 @@ public:
|
||||
NamespaceNode(InnerNode* parent, const QString& name);
|
||||
virtual ~NamespaceNode() { }
|
||||
virtual bool isNamespace() const { return true; }
|
||||
virtual Tree* tree() const { return tree_; }
|
||||
virtual Tree* tree() const { return (parent() ? parent()->tree() : tree_); }
|
||||
void setTree(Tree* t) { tree_ = t; }
|
||||
|
||||
private:
|
||||
|
@ -384,7 +384,7 @@ void QDocForest::newPrimaryTree(const QString& module)
|
||||
point, but it only makes sense in the primary tree, which is
|
||||
searched first. After the primary tree is searched, \a relative
|
||||
is set to 0 for searching the index trees. When relative is 0,
|
||||
the root node of the index tree is the starting point.
|
||||
the root nodes of the index trees are the starting points.
|
||||
*/
|
||||
const Node* QDocForest::resolveTarget(const QString& target, const Node* relative)
|
||||
{
|
||||
@ -395,11 +395,6 @@ const Node* QDocForest::resolveTarget(const QString& target, const Node* relativ
|
||||
const Node* n = t->findNode(path, relative, flags);
|
||||
if (n)
|
||||
return n;
|
||||
#if 0
|
||||
n = t->findDocNodeByTitle(target);
|
||||
if (n)
|
||||
return n;
|
||||
#endif
|
||||
relative = 0;
|
||||
}
|
||||
return 0;
|
||||
@ -1567,67 +1562,86 @@ void QDocDatabase::mergeCollections(CollectionNode* cn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This function is called when the \a{atom} might be a link
|
||||
atom. It handles the optional, square bracket parameters
|
||||
for the link command.
|
||||
*/
|
||||
Node* QDocDatabase::findNode(const Atom* atom)
|
||||
{
|
||||
QStringList path(atom->string());
|
||||
if (atom->specifiesDomain()) {
|
||||
return atom->domain()->findNodeByNameAndType(path, atom->goal());
|
||||
}
|
||||
qDebug() << "FINDNODE:" << path << atom->goal();
|
||||
return forest_.findNodeByNameAndType(path, atom->goal());
|
||||
}
|
||||
|
||||
const DocNode* QDocDatabase::findDocNodeByTitle(const Atom* atom)
|
||||
{
|
||||
return forest_.findDocNodeByTitle(atom->string());
|
||||
}
|
||||
|
||||
/*!
|
||||
Searches for the node that matches the path in \a atom. The
|
||||
\a relative node is used if the first leg of the path is
|
||||
empty, i.e. if the path begins with a hashtag. The function
|
||||
also sets \a ref if there remains an unused leg in the path
|
||||
after the node is found. The node is returned as well as the
|
||||
\a ref. If the returned node pointer is null, \a ref is not
|
||||
valid.
|
||||
*/
|
||||
const Node* QDocDatabase::findNode(const Atom* atom, const Node* relative, QString& ref)
|
||||
{
|
||||
const Node* node = 0;
|
||||
QStringList path = atom->string().split("#");
|
||||
QString first = path.first().trimmed();
|
||||
path.removeFirst();
|
||||
|
||||
if (first.isEmpty())
|
||||
node = relative; // search for a target on the current page.
|
||||
else if (atom->specifiesDomain()) {
|
||||
qDebug() << "Processing LinkAtom";
|
||||
if (first.endsWith(".html")) { // The target is an html file.
|
||||
node = atom->domain()->findNodeByNameAndType(QStringList(first), Node::Document);
|
||||
}
|
||||
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
node = atom->domain()->resolveFunctionTarget(first, 0); //relative);
|
||||
}
|
||||
else {
|
||||
node = atom->domain()->resolveTarget(first, 0); // relative);
|
||||
if (!node)
|
||||
node = atom->domain()->findUnambiguousTarget(first, ref); // ref
|
||||
if (!node && path.isEmpty())
|
||||
node = atom->domain()->findDocNodeByTitle(first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (first.endsWith(".html")) { // The target is an html file.
|
||||
node = findNodeByNameAndType(QStringList(first), Node::Document); // ref
|
||||
}
|
||||
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
|
||||
node = resolveFunctionTarget(first, relative);
|
||||
}
|
||||
else {
|
||||
node = resolveTarget(first, relative); // ref
|
||||
if (!node)
|
||||
node = findUnambiguousTarget(first, ref); // ref
|
||||
if (!node && path.isEmpty())
|
||||
node = findDocNodeByTitle(first);
|
||||
}
|
||||
}
|
||||
if (node && ref.isEmpty()) {
|
||||
if (!node->url().isEmpty())
|
||||
return node;
|
||||
if (!path.isEmpty()) {
|
||||
ref = findTarget(path.first(), node);
|
||||
if (ref.isEmpty())
|
||||
node = 0;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#if 0
|
||||
void getAllGroups(CNMM& t);
|
||||
void getAllModules(CNMM& t);
|
||||
void getAllQmlModules(CNMM& t);
|
||||
|
||||
/*!
|
||||
For each tree in the forest, get the group map from the tree.
|
||||
Insert each pair from the group map into the collection node
|
||||
multimap \a t.
|
||||
*/
|
||||
void QDocForest::getAllGroups(CNMM& t)
|
||||
{
|
||||
foreach (Tree* t, searchOrder()) {
|
||||
const GroupMap& gm = t->groups();
|
||||
if (!gm.isEmpty()) {
|
||||
GroupMap::const_iterator i = gm.begin();
|
||||
while (i != gm.end()) {
|
||||
t.insert(i.key(), i.value());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
For each tree in the forest, get the module map from the tree.
|
||||
Insert each pair from the module map into the collection node
|
||||
multimap \a t.
|
||||
*/
|
||||
void QDocForest::getAllModules(CNMM& t)
|
||||
{
|
||||
foreach (Tree* t, searchOrder()) {
|
||||
const ModuleMap& mm = t->modules();
|
||||
if (!mm.isEmpty()) {
|
||||
ModuleMap::const_iterator i = mm.begin();
|
||||
while (i != mm.end()) {
|
||||
t.insert(i.key(), i.value());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
For each tree in the forest, get the QML module map from the
|
||||
tree. Insert each pair from the QML module map into the
|
||||
collection node multimap \a t.
|
||||
*/
|
||||
void QDocForest::getAllQmlModules(CNMM& t)
|
||||
{
|
||||
foreach (Tree* t, searchOrder()) {
|
||||
const QmlModuleMap& qmm = t->groups();
|
||||
if (!qmm.isEmpty()) {
|
||||
QmlModuleMap::const_iterator i = qmm.begin();
|
||||
while (i != qmm.end()) {
|
||||
t.insert(i.key(), i.value());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -249,7 +249,9 @@ class QDocDatabase
|
||||
void findAllSince(InnerNode *node);
|
||||
|
||||
public:
|
||||
// special collection access functions
|
||||
/*******************************************************************
|
||||
special collection access functions
|
||||
********************************************************************/
|
||||
NodeMap& getCppClasses();
|
||||
NodeMap& getMainClasses();
|
||||
NodeMap& getCompatibilityClasses();
|
||||
@ -266,9 +268,9 @@ class QDocDatabase
|
||||
const NodeMap& getQmlTypeMap(const QString& key);
|
||||
const NodeMultiMap& getSinceMap(const QString& key);
|
||||
|
||||
/* convenience functions
|
||||
Many of these will be either eliminated or replaced.
|
||||
*/
|
||||
/*******************************************************************
|
||||
Many of these will be either eliminated or replaced.
|
||||
********************************************************************/
|
||||
void resolveInheritance() { primaryTree()->resolveInheritance(); }
|
||||
void resolveQmlInheritance(InnerNode* root);
|
||||
void resolveIssues();
|
||||
@ -298,6 +300,14 @@ class QDocDatabase
|
||||
}
|
||||
/*******************************************************************/
|
||||
|
||||
/*******************************************************************
|
||||
The functions declared below handle the parameters in '[' ']'.
|
||||
********************************************************************/
|
||||
Node* findNode(const Atom* atom);
|
||||
const Node* findNode(const Atom* atom, const Node* relative, QString& ref);
|
||||
const DocNode* findDocNodeByTitle(const Atom* atom);
|
||||
/*******************************************************************/
|
||||
|
||||
/*******************************************************************
|
||||
The functions declared below are called for all trees.
|
||||
********************************************************************/
|
||||
|
@ -54,6 +54,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static Node* top = 0;
|
||||
|
||||
/*!
|
||||
\class QDocIndexFiles
|
||||
|
||||
@ -110,11 +112,13 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
|
||||
foreach (const QString& indexFile, indexFiles) {
|
||||
QString msg = "Loading index file: " + indexFile;
|
||||
Location::logToStdErr(msg);
|
||||
//qDebug() << " LOAD INDEX FILE:" << indexFile;
|
||||
//qDebug() << msg;
|
||||
readIndexFile(indexFile);
|
||||
}
|
||||
}
|
||||
|
||||
static bool readingRoot = true;
|
||||
|
||||
/*!
|
||||
Reads and parses the index file at \a path.
|
||||
*/
|
||||
@ -146,6 +150,7 @@ void QDocIndexFiles::readIndexFile(const QString& path)
|
||||
basesList_.clear();
|
||||
relatedList_.clear();
|
||||
|
||||
readingRoot = true;
|
||||
NamespaceNode* root = qdb_->newIndexTree(project_);
|
||||
|
||||
// Scan all elements in the XML file, constructing a map that contains
|
||||
@ -154,6 +159,7 @@ void QDocIndexFiles::readIndexFile(const QString& path)
|
||||
while (!child.isNull()) {
|
||||
readIndexSection(child, root, indexUrl);
|
||||
child = child.nextSiblingElement();
|
||||
readingRoot = true;
|
||||
}
|
||||
|
||||
// Now that all the base classes have been found for this index,
|
||||
@ -167,13 +173,16 @@ void QDocIndexFiles::readIndexFile(const QString& path)
|
||||
appropriate node(s).
|
||||
*/
|
||||
void QDocIndexFiles::readIndexSection(const QDomElement& element,
|
||||
InnerNode* parent,
|
||||
Node* current,
|
||||
const QString& indexUrl)
|
||||
{
|
||||
QString name = element.attribute("name");
|
||||
QString href = element.attribute("href");
|
||||
Node* node;
|
||||
Location location;
|
||||
InnerNode* parent = 0;
|
||||
if (current->isInnerNode())
|
||||
parent = static_cast<InnerNode*>(current);
|
||||
|
||||
QString filePath;
|
||||
int lineNo = 0;
|
||||
@ -462,15 +471,15 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
|
||||
location = Location(parent->name().toLower() + ".html");
|
||||
}
|
||||
else if (element.nodeName() == "keyword") {
|
||||
qdb_->insertTarget(name, TargetRec::Keyword, parent, 1);
|
||||
qdb_->insertTarget(name, TargetRec::Keyword, current, 1);
|
||||
return;
|
||||
}
|
||||
else if (element.nodeName() == "target") {
|
||||
qdb_->insertTarget(name, TargetRec::Target, parent, 2);
|
||||
qdb_->insertTarget(name, TargetRec::Target, current, 2);
|
||||
return;
|
||||
}
|
||||
else if (element.nodeName() == "contents") {
|
||||
qdb_->insertTarget(name, TargetRec::Contents, parent, 3);
|
||||
qdb_->insertTarget(name, TargetRec::Contents, current, 3);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -560,26 +569,15 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
|
||||
node->setReconstitutedBrief(briefAttr);
|
||||
}
|
||||
|
||||
if (node->isInnerNode()) {
|
||||
InnerNode* inner = static_cast<InnerNode*>(node);
|
||||
// zzz
|
||||
bool useParent = (element.nodeName() == "namespace" && name.isEmpty());
|
||||
if (element.hasChildNodes()) {
|
||||
QDomElement child = element.firstChildElement();
|
||||
while (!child.isNull()) {
|
||||
if (element.nodeName() == "class") {
|
||||
readIndexSection(child, inner, indexUrl);
|
||||
}
|
||||
else if (element.nodeName() == "qmlclass") {
|
||||
readIndexSection(child, inner, indexUrl);
|
||||
}
|
||||
else if (element.nodeName() == "page") {
|
||||
readIndexSection(child, inner, indexUrl);
|
||||
}
|
||||
else if (element.nodeName() == "namespace" && !name.isEmpty()) {
|
||||
// The root node in the index is a namespace with an empty name.
|
||||
readIndexSection(child, inner, indexUrl);
|
||||
}
|
||||
else {
|
||||
if (useParent)
|
||||
readIndexSection(child, parent, indexUrl);
|
||||
}
|
||||
else
|
||||
readIndexSection(child, node, indexUrl);
|
||||
child = child.nextSiblingElement();
|
||||
}
|
||||
}
|
||||
@ -1143,6 +1141,42 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
For our pages, we canonicalize the target, keyword and content
|
||||
item names so that they can be used by qdoc for other sets of
|
||||
documentation.
|
||||
|
||||
The reason we do this here is that we don't want to ruin
|
||||
externally composed indexes, containing non-qdoc-style target names
|
||||
when reading in indexes.
|
||||
|
||||
targets and keywords are now allowed in any node, not just inner nodes.
|
||||
*/
|
||||
|
||||
if (node->doc().hasTargets()) {
|
||||
bool external = false;
|
||||
if (node->type() == Node::Document) {
|
||||
const DocNode* docNode = static_cast<const DocNode*>(node);
|
||||
if (docNode->subType() == Node::ExternalPage)
|
||||
external = true;
|
||||
}
|
||||
foreach (const Atom* target, node->doc().targets()) {
|
||||
QString targetName = target->string();
|
||||
if (!external)
|
||||
targetName = Doc::canonicalTitle(targetName);
|
||||
writer.writeStartElement("target");
|
||||
writer.writeAttribute("name", targetName);
|
||||
writer.writeEndElement(); // target
|
||||
}
|
||||
}
|
||||
if (node->doc().hasKeywords()) {
|
||||
foreach (const Atom* keyword, node->doc().keywords()) {
|
||||
writer.writeStartElement("keyword");
|
||||
writer.writeAttribute("name", Doc::canonicalTitle(keyword->string()));
|
||||
writer.writeEndElement(); // keyword
|
||||
}
|
||||
}
|
||||
|
||||
// Inner nodes and function nodes contain child nodes of some sort, either
|
||||
// actual child nodes or function parameters. For these, we close the
|
||||
// opening tag, create child elements, then add a closing tag for the
|
||||
@ -1151,36 +1185,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
|
||||
if (node->isInnerNode()) {
|
||||
const InnerNode* inner = static_cast<const InnerNode*>(node);
|
||||
|
||||
// For internal pages, we canonicalize the target, keyword and content
|
||||
// item names so that they can be used by qdoc for other sets of
|
||||
// documentation.
|
||||
// The reason we do this here is that we don't want to ruin
|
||||
// externally composed indexes, containing non-qdoc-style target names
|
||||
// when reading in indexes.
|
||||
|
||||
if (inner->doc().hasTargets()) {
|
||||
bool external = false;
|
||||
if (inner->type() == Node::Document) {
|
||||
const DocNode* docNode = static_cast<const DocNode*>(inner);
|
||||
if (docNode->subType() == Node::ExternalPage)
|
||||
external = true;
|
||||
}
|
||||
foreach (const Atom* target, inner->doc().targets()) {
|
||||
QString targetName = target->string();
|
||||
if (!external)
|
||||
targetName = Doc::canonicalTitle(targetName);
|
||||
writer.writeStartElement("target");
|
||||
writer.writeAttribute("name", targetName);
|
||||
writer.writeEndElement(); // target
|
||||
}
|
||||
}
|
||||
if (inner->doc().hasKeywords()) {
|
||||
foreach (const Atom* keyword, inner->doc().keywords()) {
|
||||
writer.writeStartElement("keyword");
|
||||
writer.writeAttribute("name", Doc::canonicalTitle(keyword->string()));
|
||||
writer.writeEndElement(); // keyword
|
||||
}
|
||||
}
|
||||
if (inner->doc().hasTableOfContents()) {
|
||||
for (int i = 0; i < inner->doc().tableOfContents().size(); ++i) {
|
||||
Atom* item = inner->doc().tableOfContents()[i];
|
||||
@ -1336,6 +1340,47 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
|
||||
generateIndexSections(writer, child, generateInternalNodes);
|
||||
}
|
||||
}
|
||||
|
||||
if (node == top) {
|
||||
/*
|
||||
We wait until the end of the index file to output the group, module,
|
||||
and QML module elements. By outputting them at the end, when we read
|
||||
the index file back in, all the group, module, and QML module member
|
||||
elements will have already been created. It is then only necessary to
|
||||
create the group, module, or QML module element and add each member to
|
||||
its member list.
|
||||
*/
|
||||
const CNMap& groups = qdb_->groups();
|
||||
if (!groups.isEmpty()) {
|
||||
CNMap::ConstIterator g = groups.constBegin();
|
||||
while (g != groups.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
|
||||
const CNMap& modules = qdb_->modules();
|
||||
if (!modules.isEmpty()) {
|
||||
CNMap::ConstIterator g = modules.constBegin();
|
||||
while (g != modules.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
|
||||
const CNMap& qmlModules = qdb_->qmlModules();
|
||||
if (!qmlModules.isEmpty()) {
|
||||
CNMap::ConstIterator g = qmlModules.constBegin();
|
||||
while (g != qmlModules.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.writeEndElement();
|
||||
}
|
||||
}
|
||||
@ -1368,45 +1413,8 @@ void QDocIndexFiles::generateIndex(const QString& fileName,
|
||||
writer.writeAttribute("version", qdb_->version());
|
||||
writer.writeAttribute("project", g->config()->getString(CONFIG_PROJECT));
|
||||
|
||||
generateIndexSections(writer, qdb_->primaryTreeRoot(), generateInternalNodes);
|
||||
|
||||
/*
|
||||
We wait until the end of the index file to output the group, module,
|
||||
and QML module elements. By outputting them at the end, when we read
|
||||
the index file back in, all the group, module, and QML module member
|
||||
elements will have already been created. It is then only necessary to
|
||||
create the group, module, or QML module element and add each member to
|
||||
its member list.
|
||||
*/
|
||||
const CNMap& groups = qdb_->groups();
|
||||
if (!groups.isEmpty()) {
|
||||
CNMap::ConstIterator g = groups.constBegin();
|
||||
while (g != groups.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
|
||||
const CNMap& modules = qdb_->modules();
|
||||
if (!modules.isEmpty()) {
|
||||
CNMap::ConstIterator g = modules.constBegin();
|
||||
while (g != modules.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
|
||||
const CNMap& qmlModules = qdb_->qmlModules();
|
||||
if (!qmlModules.isEmpty()) {
|
||||
CNMap::ConstIterator g = qmlModules.constBegin();
|
||||
while (g != qmlModules.constEnd()) {
|
||||
if (generateIndexSection(writer, g.value(), generateInternalNodes))
|
||||
writer.writeEndElement();
|
||||
++g;
|
||||
}
|
||||
}
|
||||
top = qdb_->primaryTreeRoot();
|
||||
generateIndexSections(writer, top, generateInternalNodes);
|
||||
|
||||
writer.writeEndElement(); // INDEX
|
||||
writer.writeEndElement(); // QDOCINDEX
|
||||
|
@ -72,7 +72,7 @@ class QDocIndexFiles
|
||||
bool generateInternalNodes = false);
|
||||
|
||||
void readIndexFile(const QString& path);
|
||||
void readIndexSection(const QDomElement& element, InnerNode* parent, const QString& indexUrl);
|
||||
void readIndexSection(const QDomElement& element, Node* current, const QString& indexUrl);
|
||||
void resolveIndex();
|
||||
bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
||||
void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
||||
|
@ -111,6 +111,22 @@ Text& Text::operator<<(const Atom& atom)
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Special output operator for LinkAtom. It makes a copy of
|
||||
the LinkAtom \a atom and connects the cop;y to the list
|
||||
in this Text.
|
||||
*/
|
||||
Text& Text::operator<<(const LinkAtom& atom)
|
||||
{
|
||||
if (first == 0) {
|
||||
first = new LinkAtom(atom);
|
||||
last = first;
|
||||
}
|
||||
else
|
||||
last = new LinkAtom(last, atom);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Text& Text::operator<<(const Text& text)
|
||||
{
|
||||
const Atom* atom = text.firstAtom();
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
Text& operator<<(Atom::Type atomType);
|
||||
Text& operator<<(const QString& string);
|
||||
Text& operator<<(const Atom& atom);
|
||||
Text& operator<<(const LinkAtom& atom);
|
||||
Text& operator<<(const Text& text);
|
||||
void stripFirstAtom();
|
||||
void stripLastAtom();
|
||||
|
@ -563,20 +563,6 @@ Node* Tree::findNodeByNameAndType(const QStringList& path, Node::Type type) cons
|
||||
{
|
||||
return findNodeRecursive(path, 0, root(), type);
|
||||
}
|
||||
#if 0
|
||||
/*!
|
||||
Find the node with the specified \a path name that is of
|
||||
the specified \a type and \a subtype. Begin the search at
|
||||
the \a start node. If the \a start node is 0, begin the
|
||||
search at the tree root. \a subtype is not used unless
|
||||
\a type is \c{Document}.
|
||||
*/
|
||||
Node* Tree::findHtmlFileNode(const QStringList& path) const
|
||||
{
|
||||
return findNodeRecursive(path, 0, root());
|
||||
}
|
||||
#endif
|
||||
/* internal members */
|
||||
|
||||
/*!
|
||||
Recursive search for a node identified by \a path. Each
|
||||
@ -624,7 +610,7 @@ Node* Tree::findNodeRecursive(const QStringList& path,
|
||||
}
|
||||
else if (n->name() == name) {
|
||||
if (pathIndex+1 >= path.size()) {
|
||||
if (n->type() == type)
|
||||
if ((n->type() == type) || (type == Node::NoType))
|
||||
return n;
|
||||
continue;
|
||||
}
|
||||
@ -815,6 +801,23 @@ void Tree::insertTarget(const QString& name, TargetRec::Type type, Node* node, i
|
||||
nodesByTarget_.insert(name, target);
|
||||
}
|
||||
|
||||
/*!
|
||||
Searches this tree for a node named \a target and returns
|
||||
a pointer to it if found. The \a start node is the starting
|
||||
point, but it only makes sense if \a start is in this tree.
|
||||
If \a start is not in this tree, \a start is set to 0 before
|
||||
beginning the search to ensure that the search starts at the
|
||||
root.
|
||||
*/
|
||||
const Node* Tree::resolveTarget(const QString& target, const Node* start)
|
||||
{
|
||||
QStringList path = target.split("::");
|
||||
int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
|
||||
if (start && start->tree() != this)
|
||||
start = 0;
|
||||
return findNode(path, start, flags);
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
void Tree::resolveTargets(InnerNode* root)
|
||||
|
@ -114,6 +114,7 @@ class Tree
|
||||
NameCollisionNode* findCollisionNode(const QString& name) const;
|
||||
QString findTarget(const QString& target, const Node* node) const;
|
||||
void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
|
||||
const Node* resolveTarget(const QString& target, const Node* start);
|
||||
void resolveTargets(InnerNode* root);
|
||||
const Node* findUnambiguousTarget(const QString& target, QString& ref);
|
||||
const DocNode* findDocNodeByTitle(const QString& title) const;
|
||||
|
Loading…
Reference in New Issue
Block a user