diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp index bd72fc106b..f73ac147b8 100644 --- a/src/tools/qdoc/config.cpp +++ b/src/tools/qdoc/config.cpp @@ -119,6 +119,7 @@ QString ConfigStrings::FILEEXTENSIONS = QStringLiteral("fileextensions"); QString ConfigStrings::IMAGEEXTENSIONS = QStringLiteral("imageextensions"); QString ConfigStrings::QMLONLY = QStringLiteral("qmlonly"); QString ConfigStrings::QMLTYPESPAGE = QStringLiteral("qmltypespage"); +QString ConfigStrings::WRITEQAPAGES = QStringLiteral("writeqapages"); /*! An entry in a stack, where each entry is a list diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h index c4d4f27a9e..a836448719 100644 --- a/src/tools/qdoc/config.h +++ b/src/tools/qdoc/config.h @@ -231,6 +231,7 @@ struct ConfigStrings static QString IMAGEEXTENSIONS; static QString QMLONLY; static QString QMLTYPESPAGE; + static QString WRITEQAPAGES; }; #define CONFIG_ALIAS ConfigStrings::ALIAS @@ -305,6 +306,7 @@ struct ConfigStrings #define CONFIG_IMAGEEXTENSIONS ConfigStrings::IMAGEEXTENSIONS #define CONFIG_QMLONLY ConfigStrings::QMLONLY #define CONFIG_QMLTYPESPAGE ConfigStrings::QMLTYPESPAGE +#define CONFIG_WRITEQAPAGES ConfigStrings::WRITEQAPAGES QT_END_NAMESPACE diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 6f53783aaf..db531e3936 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -64,7 +64,7 @@ QString Generator::outSubdir_; QStringList Generator::outFileNames_; QSet Generator::outputFormats; QHash Generator::outputPrefixes; -QString Generator::project; +QString Generator::project_; QStringList Generator::scriptDirs; QStringList Generator::scriptFiles; QString Generator::sinceTitles[] = @@ -94,6 +94,7 @@ bool Generator::autolinkErrors_ = false; bool Generator::redirectDocumentationToDevNull_ = false; Generator::QDocPass Generator::qdocPass_ = Generator::Neither; bool Generator::qdocSingleExec_ = false; +bool Generator::qdocWriteQaPages_ = false; bool Generator::useOutputSubdirs_ = true; void Generator::startDebugging(const QString& message) @@ -317,7 +318,7 @@ QString Generator::fileBase(const Node *node) const if (node->isExample() || node->isExampleFile()) { QString modPrefix(node->moduleName()); if (modPrefix.isEmpty()) { - modPrefix = project; + modPrefix = project_; } base.prepend(modPrefix.toLower() + QLatin1Char('-')); } @@ -1646,7 +1647,7 @@ void Generator::initialize(const Config &config) ++n; } - project = config.getString(CONFIG_PROJECT); + project_ = config.getString(CONFIG_PROJECT); QStringList prefixes = config.getStringList(CONFIG_OUTPUTPREFIXES); if (!prefixes.isEmpty()) { diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h index 306a1596ae..b1faf02ae9 100644 --- a/src/tools/qdoc/generator.h +++ b/src/tools/qdoc/generator.h @@ -95,8 +95,10 @@ public: static bool preparing() { return (qdocPass_ == Prepare); } static bool generating() { return (qdocPass_ == Generate); } static bool singleExec() { return qdocSingleExec_; } + static bool writeQaPages() { return qdocWriteQaPages_; } static void setSingleExec() { qdocSingleExec_ = true; } - static QString defaultModuleName() { return project; } + static void setWriteQaPages() { qdocWriteQaPages_ = true; } + static QString defaultModuleName() { return project_; } static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; } static bool useOutputSubdirs() { return useOutputSubdirs_; } @@ -105,6 +107,7 @@ protected: virtual void endSubPage(); virtual QString fileBase(const Node* node) const; virtual QString fileExtension() const = 0; + virtual void generateQAPage() { } virtual void generateAlsoList(const Node *node, CodeMarker *marker); virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker); virtual void generateBody(const Node *node, CodeMarker *marker); @@ -200,7 +203,7 @@ private: static QStringList imageDirs; static QStringList imageFiles; static QMap imgFileExts; - static QString project; + static QString project_; static QString outDir_; static QString outSubdir_; static QStringList outFileNames_; @@ -216,6 +219,7 @@ private: static bool redirectDocumentationToDevNull_; static QDocPass qdocPass_; static bool qdocSingleExec_; + static bool qdocWriteQaPages_; static bool useOutputSubdirs_; void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 91f5ec1fcb..cbd8c1ddef 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -280,6 +280,8 @@ void HtmlGenerator::generateDocs() qflagsHref_ = linkForNode(qflags,0); if (!preparing()) Generator::generateDocs(); + if (Generator::generating() && Generator::writeQaPages()) + generateQAPage(); if (!generating()) { QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-')); @@ -300,6 +302,46 @@ void HtmlGenerator::generateDocs() } } +/*! + Output the module's Quality Assurance page. + */ +void HtmlGenerator::generateQAPage() +{ + NamespaceNode* node = qdb_->primaryTreeRoot(); + beginSubPage(node, "aaa-" + defaultModuleName().toLower() + "-qa-page.html"); + CodeMarker* marker = CodeMarker::markerForFileName(node->location().filePath()); + QString title = "Quality Assurance Page for " + defaultModuleName(); + QString t = "Quality assurance information for checking the " + defaultModuleName() + " documentation."; + generateHeader(title, node, marker); + generateTitle(title, Text() << t, LargeSubTitle, node, marker); + + QStringList strings; + QVector counts; + QString depends = qdb_->getLinkCounts(strings, counts); + if (!strings.isEmpty()) { + t = "Intermodule Link Counts"; + QString ref = registerRef(t); + out() << "" << divNavTop << '\n'; + out() << "

" << protectEnc(t) << "

\n"; + out() << "" + << "\n"; + for (int i = 0; i< strings.size(); ++i) { + out() << "\n"; + } + out() << "
Destination ModuleLink Count
" << strings.at(i) + << "" << counts.at(i) + << "
\n"; + t = "The Optimal \"depends\" Variable"; + out() << "

" << protectEnc(t) << "

\n"; + t = "Consider replacing the depends variable in " + defaultModuleName().toLower() + + ".qdocconf with this one, if the two are not identical:"; + out() << "

" << protectEnc(t) << "

\n"; + out() << "

" << protectEnc(depends) << "

\n"; + } + endSubPage(); +} + /*! Generate html from an instance of Atom. */ @@ -3676,6 +3718,9 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod if (!(*node)) return QString(); + if (Generator::writeQaPages()) + qdb_->incrementLinkCount(*node); + QString url = (*node)->url(); if (!url.isEmpty()) { if (ref.isEmpty()) @@ -3720,6 +3765,9 @@ QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const if (!(*node)) return QString(); + if (Generator::writeQaPages()) + qdb_->incrementLinkCount(*node); + QString url = (*node)->url(); if (!url.isEmpty()) { if (ref.isEmpty()) diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index 616a989361..825522a121 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -89,6 +89,7 @@ public: static QString sinceTitle(int i) { return sinceTitles[i]; } protected: + virtual void generateQAPage(); virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker); diff --git a/src/tools/qdoc/location.cpp b/src/tools/qdoc/location.cpp index ca06eeb283..923901fc34 100644 --- a/src/tools/qdoc/location.cpp +++ b/src/tools/qdoc/location.cpp @@ -285,6 +285,15 @@ void Location::fatal(const QString& message, const QString& details) const exit(EXIT_FAILURE); } +/*! + Writes \a message and \a detals to stderr as a formatted + report message. + */ +void Location::report(const QString& message, const QString& details) const +{ + emitMessage(Report, message, details); +} + /*! Gets several parameters from the \a config, including tab size, program name, and a regular expression that @@ -371,7 +380,8 @@ void Location::emitMessage(MessageType type, result.prepend(tr(": error: ")); else if (type == Warning) result.prepend(tr(": warning: ")); - result.prepend(toString()); + if (type != Report) + result.prepend(toString()); fprintf(stderr, "%s\n", result.toLatin1().data()); fflush(stderr); } diff --git a/src/tools/qdoc/location.h b/src/tools/qdoc/location.h index eb4dbbae98..b6589fd6ab 100644 --- a/src/tools/qdoc/location.h +++ b/src/tools/qdoc/location.h @@ -81,6 +81,8 @@ public: const QString& details = QString()) const; void fatal(const QString& message, const QString& details = QString()) const; + void report(const QString& message, + const QString& details = QString()) const; static const Location null; @@ -94,7 +96,7 @@ public: static QString canonicalRelativePath(const QString &path); private: - enum MessageType { Warning, Error }; + enum MessageType { Warning, Error, Report }; struct StackEntry { diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp index 79fd174a08..186fd3195b 100644 --- a/src/tools/qdoc/main.cpp +++ b/src/tools/qdoc/main.cpp @@ -71,6 +71,7 @@ bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2) static bool highlighting = false; static bool showInternal = false; static bool singleExec = false; +static bool writeQaPages = false; static bool redirectDocumentationToDevNull = false; static bool noLinkErrors = false; static bool autolinkErrors = false; @@ -221,6 +222,7 @@ static void processQdocconfFile(const QString &fileName) config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false")); config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false")); config.setStringList(CONFIG_SINGLEEXEC, QStringList(singleExec ? "true" : "false")); + config.setStringList(CONFIG_WRITEQAPAGES, QStringList(writeQaPages ? "true" : "false")); config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false")); config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false")); config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false")); @@ -459,7 +461,6 @@ static void processQdocconfFile(const QString &fileName) codeParser->doneParsingHeaderFiles(); usedParsers.clear(); - //qDebug() << "CALL: resolveInheritance()"; qdb->resolveInheritance(); /* @@ -490,7 +491,6 @@ static void processQdocconfFile(const QString &fileName) targets, URLs, links, and other stuff that needs resolving. */ Generator::debug("Resolving stuff prior to generating docs"); - //qDebug() << "CALL: resolveIssues()"; qdb->resolveIssues(); } else { @@ -533,7 +533,6 @@ static void processQdocconfFile(const QString &fileName) one. */ Generator::debug("Generating docs"); - //qDebug() << "CALL: generateDocs()"; QSet::ConstIterator of = outputFormats.constBegin(); while (of != outputFormats.constEnd()) { Generator* generator = Generator::generatorForFormat(*of); @@ -543,8 +542,12 @@ static void processQdocconfFile(const QString &fileName) generator->generateDocs(); ++of; } +#if 0 + if (Generator::generating() && Generator::writeQaPages()) + qdb->printLinkCounts(project); +#endif + qdb->clearLinkCounts(); - //Generator::writeOutFileNames(); Generator::debug("Terminating qdoc classes"); if (Generator::debugging()) Generator::stopDebugging(project); @@ -681,6 +684,10 @@ int main(int argc, char **argv) singleExecOption.setDescription(QCoreApplication::translate("qdoc", "Run qdoc once over all the qdoc conf files.")); parser.addOption(singleExecOption); + QCommandLineOption writeQaPagesOption(QStringList() << QStringLiteral("write-qa-pages")); + writeQaPagesOption.setDescription(QCoreApplication::translate("qdoc", "Write QA pages.")); + parser.addOption(writeQaPagesOption); + parser.process(app); defines += parser.values(defineOption); @@ -688,6 +695,7 @@ int main(int argc, char **argv) highlighting = parser.isSet(highlightingOption); showInternal = parser.isSet(showInternalOption); singleExec = parser.isSet(singleExecOption); + writeQaPages = parser.isSet(writeQaPagesOption); redirectDocumentationToDevNull = parser.isSet(redirectDocumentationToDevNullOption); Config::generateExamples = !parser.isSet(noExamplesOption); foreach (const QString &indexDir, parser.values(indexDirOption)) { @@ -713,6 +721,8 @@ int main(int argc, char **argv) Generator::setQDocPass(Generator::Generate); if (parser.isSet(singleExecOption)) Generator::setSingleExec(); + if (parser.isSet(writeQaPagesOption)) + Generator::setWriteQaPages(); if (parser.isSet(logProgressOption)) Location::startLoggingProgress(); diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index a22244d174..4b4c88a176 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -274,7 +274,6 @@ const QVector& QDocForest::indexSearchOrder() */ NamespaceNode* QDocForest::newIndexTree(const QString& module) { - //qDebug() << " New index tree:" << module; primaryTree_ = new Tree(module, qdb_); forest_.insert(module, primaryTree_); return primaryTree_->root(); @@ -286,7 +285,6 @@ NamespaceNode* QDocForest::newIndexTree(const QString& module) */ void QDocForest::newPrimaryTree(const QString& module) { - //qDebug() << " New primary tree:" << module; primaryTree_ = new Tree(module, qdb_); } @@ -351,6 +349,61 @@ void QDocForest::mergeCollectionMaps(Node::Type nt, CNMultiMap& cnmm) } } +/*! + Print the list of module names ordered according + to how many successful searches each tree had. + */ +void QDocForest::printLinkCounts(const QString& project) +{ + Location::null.report(QString("%1: Link Counts").arg(project)); + QMultiMap m; + foreach (Tree* t, searchOrder()) { + if (t->linkCount() < 0) + m.insert(t->linkCount(), t->moduleName()); + } + QString depends = "depends +="; + QString module = project.toLower(); + QMultiMap::iterator i = m.begin(); + while (i != m.end()) { + QString line = " " + i.value(); + if (i.value() != module) + depends += " " + i.value(); + int pad = 30 - line.length(); + for (int k=0; k& counts) +{ + QMultiMap m; + foreach (Tree* t, searchOrder()) { + if (t->linkCount() < 0) + m.insert(t->linkCount(), t->moduleName()); + } + QString depends = "depends +="; + QString module = Generator::defaultModuleName().toLower(); + QMultiMap::iterator i = m.begin(); + while (i != m.end()) { + if (i.value() != module) { + counts.append(-(i.key())); + strings.append(i.value()); + depends += " " + i.value(); + } + ++i; + } + return depends; +} + /*! \class QDocDatabase This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a lot of maps and diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h index f6deeeece8..02d39e62e7 100644 --- a/src/tools/qdoc/qdocdatabase.h +++ b/src/tools/qdoc/qdocdatabase.h @@ -194,6 +194,13 @@ class QDocForest } void clearSearchOrder() { searchOrder_.clear(); } + void clearLinkCounts() + { + foreach (Tree* t, searchOrder()) + t->clearLinkCount(); + } + void printLinkCounts(const QString& project); + QString getLinkCounts(QStringList& strings, QVector& counts); private: void newPrimaryTree(const QString& module); @@ -379,6 +386,12 @@ class QDocDatabase void mergeCollections(Node::Type nt, CNMap& cnm, const Node* relative); void mergeCollections(CollectionNode* cn); void clearSearchOrder() { forest_.clearSearchOrder(); } + void incrementLinkCount(const Node* t) { t->tree()->incrementLinkCount(); } + void clearLinkCounts() { forest_.clearLinkCounts(); } + void printLinkCounts(const QString& t) { forest_.printLinkCounts(t); } + QString getLinkCounts(QStringList& strings, QVector& counts) { + return forest_.getLinkCounts(strings, counts); + } private: friend class QDocIndexFiles; diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index d4169f6242..f3a6ed78da 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -68,6 +68,7 @@ QT_BEGIN_NAMESPACE Tree::Tree(const QString& module, QDocDatabase* qdb) : treeHasBeenAnalyzed_(false), docsHaveBeenGenerated_(false), + linkCount_(0), module_(module), qdb_(qdb), root_(0, QString()) diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h index 5f11a81405..75f751f976 100644 --- a/src/tools/qdoc/tree.h +++ b/src/tools/qdoc/tree.h @@ -197,10 +197,14 @@ class Tree public: const QString& moduleName() const { return module_; } const QString& indexFileName() const { return indexFileName_; } + void incrementLinkCount() { --linkCount_; } + void clearLinkCount() { linkCount_ = 0; } + int linkCount() const { return linkCount_; } private: bool treeHasBeenAnalyzed_; bool docsHaveBeenGenerated_; + int linkCount_; QString module_; QString indexFileName_; QDocDatabase* qdb_;