qdoc: Generate obsolete members page for QML types

Generation of the obsolete members page, for QML types
that have obsolete members, had not been implemented.
This update implements that missing feature. The link
to the page appears right below the link to the "All
Members" page.

Change-Id: I3e4bb2a68d5c8ef2bbe2e0c431eccf94ecb1fd3c
Task-number: QTBUG-40214
Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
This commit is contained in:
Martin Smith 2014-08-19 15:27:27 +02:00
parent a2c432e978
commit 6b12d781fa
8 changed files with 117 additions and 27 deletions

View File

@ -649,7 +649,7 @@ QString CodeMarker::macName(const Node *node, const QString &name)
/*! /*!
Returns an empty list of documentation sections. Returns an empty list of documentation sections.
*/ */
QList<Section> CodeMarker::qmlSections(QmlClassNode* , SynopsisStyle ) QList<Section> CodeMarker::qmlSections(QmlClassNode* , SynopsisStyle , Status )
{ {
return QList<Section>(); return QList<Section>();
} }

View File

@ -154,7 +154,9 @@ public:
virtual QList<Section> sections(const InnerNode *inner, virtual QList<Section> sections(const InnerNode *inner,
SynopsisStyle style, SynopsisStyle style,
Status status) = 0; Status status) = 0;
virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style); virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode,
SynopsisStyle style,
Status status = Okay);
virtual QStringList macRefsForNode(Node* node); virtual QStringList macRefsForNode(Node* node);
static void initialize(const Config& config); static void initialize(const Config& config);

View File

@ -261,8 +261,7 @@ void CodeParser::processCommonMetaCommand(const Location& location,
node->setStatus(Node::Main); node->setStatus(Node::Main);
} }
else if (command == COMMAND_OBSOLETE) { else if (command == COMMAND_OBSOLETE) {
if (node->status() != Node::Compat) node->setStatus(Node::Obsolete);
node->setStatus(Node::Obsolete);
} }
else if (command == COMMAND_NONREENTRANT) { else if (command == COMMAND_NONREENTRANT) {
node->setThreadSafeness(Node::NonReentrant); node->setThreadSafeness(Node::NonReentrant);

View File

@ -1094,7 +1094,7 @@ QString CppCodeMarker::addMarkUp(const QString &in,
the list of documentation sections for the children of the the list of documentation sections for the children of the
\a qmlClassNode. \a qmlClassNode.
*/ */
QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style) QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style, Status status)
{ {
QList<Section> sections; QList<Section> sections;
if (qmlClassNode) { if (qmlClassNode) {
@ -1144,32 +1144,32 @@ QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisSt
continue; continue;
} }
if ((*c)->type() == Node::QmlPropertyGroup) { if ((*c)->type() == Node::QmlPropertyGroup) {
insert(qmlproperties, *c, style, Okay); insert(qmlproperties, *c, style, status);
} }
else if ((*c)->type() == Node::QmlProperty) { else if ((*c)->type() == Node::QmlProperty) {
const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
if (pn->isAttached()) if (pn->isAttached())
insert(qmlattachedproperties,*c,style,Okay); insert(qmlattachedproperties,*c,style, status);
else { else {
insert(qmlproperties,*c,style,Okay); insert(qmlproperties,*c,style, status);
} }
} }
else if ((*c)->type() == Node::QmlSignal) { else if ((*c)->type() == Node::QmlSignal) {
const FunctionNode* sn = static_cast<const FunctionNode*>(*c); const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
if (sn->isAttached()) if (sn->isAttached())
insert(qmlattachedsignals,*c,style,Okay); insert(qmlattachedsignals,*c,style, status);
else else
insert(qmlsignals,*c,style,Okay); insert(qmlsignals,*c,style, status);
} }
else if ((*c)->type() == Node::QmlSignalHandler) { else if ((*c)->type() == Node::QmlSignalHandler) {
insert(qmlsignalhandlers,*c,style,Okay); insert(qmlsignalhandlers,*c,style, status);
} }
else if ((*c)->type() == Node::QmlMethod) { else if ((*c)->type() == Node::QmlMethod) {
const FunctionNode* mn = static_cast<const FunctionNode*>(*c); const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
if (mn->isAttached()) if (mn->isAttached())
insert(qmlattachedmethods,*c,style,Okay); insert(qmlattachedmethods,*c,style, status);
else else
insert(qmlmethods,*c,style,Okay); insert(qmlmethods,*c,style, status);
} }
++c; ++c;
} }
@ -1209,31 +1209,31 @@ QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisSt
continue; continue;
} }
if ((*c)->type() == Node::QmlPropertyGroup) { if ((*c)->type() == Node::QmlPropertyGroup) {
insert(qmlproperties,*c,style,Okay); insert(qmlproperties,*c,style, status);
} }
else if ((*c)->type() == Node::QmlProperty) { else if ((*c)->type() == Node::QmlProperty) {
const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
if (pn->isAttached()) if (pn->isAttached())
insert(qmlattachedproperties,*c,style,Okay); insert(qmlattachedproperties,*c,style, status);
else else
insert(qmlproperties,*c,style,Okay); insert(qmlproperties,*c,style, status);
} }
else if ((*c)->type() == Node::QmlSignal) { else if ((*c)->type() == Node::QmlSignal) {
const FunctionNode* sn = static_cast<const FunctionNode*>(*c); const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
if (sn->isAttached()) if (sn->isAttached())
insert(qmlattachedsignals,*c,style,Okay); insert(qmlattachedsignals,*c,style, status);
else else
insert(qmlsignals,*c,style,Okay); insert(qmlsignals,*c,style, status);
} }
else if ((*c)->type() == Node::QmlSignalHandler) { else if ((*c)->type() == Node::QmlSignalHandler) {
insert(qmlsignalhandlers,*c,style,Okay); insert(qmlsignalhandlers,*c,style, status);
} }
else if ((*c)->type() == Node::QmlMethod) { else if ((*c)->type() == Node::QmlMethod) {
const FunctionNode* mn = static_cast<const FunctionNode*>(*c); const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
if (mn->isAttached()) if (mn->isAttached())
insert(qmlattachedmethods,*c,style,Okay); insert(qmlattachedmethods,*c,style, status);
else else
insert(qmlmethods,*c,style,Okay); insert(qmlmethods,*c,style, status);
} }
++c; ++c;
} }

View File

@ -78,7 +78,9 @@ public:
virtual QList<Section> sections(const InnerNode *innerNode, virtual QList<Section> sections(const InnerNode *innerNode,
SynopsisStyle style, SynopsisStyle style,
Status status); Status status);
virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style); virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode,
SynopsisStyle style,
Status status = Okay);
private: private:
QString addMarkUp(const QString& protectedCode, QString addMarkUp(const QString& protectedCode,

View File

@ -1352,10 +1352,17 @@ void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
generateQmlRequisites(qcn, marker); generateQmlRequisites(qcn, marker);
QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker); QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker);
if (!allQmlMembersLink.isEmpty()) { QString obsoleteLink = generateQmlMemberFile(qcn, marker, CodeMarker::Obsolete);
if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
out() << "<ul>\n"; out() << "<ul>\n";
out() << "<li><a href=\"" << allQmlMembersLink << "\">" if (!allQmlMembersLink.isEmpty()) {
<< "List of all members, including inherited members</a></li>\n"; out() << "<li><a href=\"" << allQmlMembersLink << "\">"
<< "List of all members, including inherited members</a></li>\n";
}
if (!obsoleteLink.isEmpty()) {
out() << "<li><a href=\"" << obsoleteLink << "\">"
<< "Obsolete members</a></li>\n";
}
out() << "</ul>\n"; out() << "</ul>\n";
} }
@ -2572,6 +2579,84 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner,
return fileName; return fileName;
} }
/*!
Generates a separate file where certain members of the QML
type \a qcn are listed. The \a marker is used to generate
the section lists, which are then traversed and output here.
Note that this function currently only handles correctly the
case where \a status is \c {CodeMarker::Obsolete}.
*/
QString HtmlGenerator::generateQmlMemberFile(QmlClassNode* qcn,
CodeMarker *marker,
CodeMarker::Status status)
{
QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary, status);
QMutableListIterator<Section> j(sections);
while (j.hasNext()) {
if (j.next().members.size() == 0)
j.remove();
}
if (sections.isEmpty())
return QString();
QString title = "Obsolete Members for " + qcn->name();
QString fileName = fileBase(qcn) + "-obsolete." + fileExtension();
if (status == CodeMarker::Obsolete) {
QString link;
if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty())
link = QString("../" + Generator::outputSubdir() + QLatin1Char('/'));
link += fileName;
qcn->setObsoleteLink(link);
}
beginSubPage(qcn, fileName);
generateHeader(title, qcn, marker);
generateTitle(title, Text(), SmallSubTitle, qcn, marker);
out() << "<p><b>The following members of QML type "
<< "<a href=\"" << linkForNode(qcn, 0) << "\">"
<< protectEnc(qcn->name()) << "</a>"
<< " are obsolete.</b> "
<< "They are provided to keep old source code working. "
<< "We strongly advise against using them in new code.</p>\n";
QList<Section>::const_iterator s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<a name=\"" << registerRef((*s).name.toLower())
<< "\"></a>" << divNavTop << '\n';
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateQmlSummary(*s, qcn, marker);
++s;
}
sections = marker->qmlSections(qcn, CodeMarker::Detailed, status);
QMutableListIterator<Section> k(sections);
while (k.hasNext()) {
if (k.next().members.size() == 0)
k.remove();
}
if (sections.isEmpty())
return QString();
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.constBegin();
while (m != (*s).members.constEnd()) {
generateDetailedQmlMember(*m, qcn, marker);
out() << "<br/>\n";
++m;
}
++s;
}
generateFooter();
endSubPage();
return fileName;
}
void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classMap) void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classMap)
{ {
if (classMap.isEmpty()) if (classMap.isEmpty())

View File

@ -159,6 +159,9 @@ private:
QString generateLowStatusMemberFile(InnerNode *inner, QString generateLowStatusMemberFile(InnerNode *inner,
CodeMarker *marker, CodeMarker *marker,
CodeMarker::Status status); CodeMarker::Status status);
QString generateQmlMemberFile(QmlClassNode* qcn,
CodeMarker *marker,
CodeMarker::Status status);
void generateClassHierarchy(const Node *relative, NodeMap &classMap); void generateClassHierarchy(const Node *relative, NodeMap &classMap);
void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeMap& nodeMap); void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeMap& nodeMap);
void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeList& nodes); void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeList& nodes);

View File

@ -407,8 +407,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
node->setStatus(Node::Internal); node->setStatus(Node::Internal);
} }
else if (command == COMMAND_OBSOLETE) { else if (command == COMMAND_OBSOLETE) {
if (node->status() != Node::Compat) node->setStatus(Node::Obsolete);
node->setStatus(Node::Obsolete);
} }
else if (command == COMMAND_PAGEKEYWORDS) { else if (command == COMMAND_PAGEKEYWORDS) {
// Not done yet. Do we need this? // Not done yet. Do we need this?