summaryrefslogtreecommitdiffstats
path: root/src/qdoc/manifestwriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/manifestwriter.cpp')
-rw-r--r--src/qdoc/manifestwriter.cpp422
1 files changed, 0 insertions, 422 deletions
diff --git a/src/qdoc/manifestwriter.cpp b/src/qdoc/manifestwriter.cpp
deleted file mode 100644
index f47e64ebb..000000000
--- a/src/qdoc/manifestwriter.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "manifestwriter.h"
-
-#include "config.h"
-#include "examplenode.h"
-#include "generator.h"
-#include "qdocdatabase.h"
-
-#include <QtCore/qmap.h>
-#include <QtCore/qset.h>
-#include <QtCore/qxmlstream.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
-
- For each attribute in a map of attributes, checks if the attribute is
- found in \a usedAttributes. If it is not found, issues a warning specific
- to the attribute.
- */
-void warnAboutUnusedAttributes(const QStringList &usedAttributes, const ExampleNode *example)
-{
- QMap<QString, QString> attributesToWarnFor;
- attributesToWarnFor.insert(QStringLiteral("imageUrl"),
- QStringLiteral("Example documentation should have at least one '\\image'"));
- attributesToWarnFor.insert(QStringLiteral("projectPath"),
- QStringLiteral("Example has no project file"));
-
- for (auto it = attributesToWarnFor.cbegin(); it != attributesToWarnFor.cend(); ++it) {
- if (!usedAttributes.contains(it.key()))
- example->doc().location().warning(example->name() + ": " + it.value());
- }
-}
-
-/*!
- \internal
-
- Write the description element. The description for an example is set
- with the \brief command. If no brief is available, the element is set
- to "No description available".
- */
-
-void writeDescription(QXmlStreamWriter *writer, const ExampleNode *example)
-{
- Q_ASSERT(writer && example);
- writer->writeStartElement("description");
- const Text brief = example->doc().briefText();
- if (!brief.isEmpty())
- writer->writeCDATA(brief.toString());
- else
- writer->writeCDATA(QString("No description available"));
- writer->writeEndElement(); // description
-}
-
-/*!
- \internal
-
- Returns a list of \a files that Qt Creator should open for the \a exampleName.
- */
-QMap<int, QString> getFilesToOpen(const QStringList &files, const QString &exampleName)
-{
- QMap<int, QString> filesToOpen;
- for (const QString &file : files) {
- QFileInfo fileInfo(file);
- QString fileName = fileInfo.fileName().toLower();
- // open .qml, .cpp and .h files with a
- // basename matching the example (project) name
- // QMap key indicates the priority -
- // the lowest value will be the top-most file
- if ((fileInfo.baseName().compare(exampleName, Qt::CaseInsensitive) == 0)) {
- if (fileName.endsWith(".qml"))
- filesToOpen.insert(0, file);
- else if (fileName.endsWith(".cpp"))
- filesToOpen.insert(1, file);
- else if (fileName.endsWith(".h"))
- filesToOpen.insert(2, file);
- }
- // main.qml takes precedence over main.cpp
- else if (fileName.endsWith("main.qml")) {
- filesToOpen.insert(3, file);
- } else if (fileName.endsWith("main.cpp")) {
- filesToOpen.insert(4, file);
- }
- }
-
- return filesToOpen;
-}
-
-/*!
- \internal
- \brief Writes the lists of files to open for the example.
-
- Writes out the \a filesToOpen and the full \a installPath through \a writer.
- */
-void writeFilesToOpen(QXmlStreamWriter &writer, const QString &installPath,
- const QMap<int, QString> &filesToOpen)
-{
- for (auto it = filesToOpen.constEnd(); it != filesToOpen.constBegin();) {
- writer.writeStartElement("fileToOpen");
- if (--it == filesToOpen.constBegin()) {
- writer.writeAttribute(QStringLiteral("mainFile"), QStringLiteral("true"));
- }
- writer.writeCharacters(installPath + it.value());
- writer.writeEndElement();
- }
-}
-
-/*!
- \class ManifestWriter
- \internal
- \brief The ManifestWriter is responsible for writing manifest files.
- */
-ManifestWriter::ManifestWriter()
-{
- Config &config = Config::instance();
- m_project = config.getString(CONFIG_PROJECT);
- m_outputDirectory = config.getOutputDir();
- m_qdb = QDocDatabase::qdocDB();
-
- const QString prefix = CONFIG_QHP + Config::dot + m_project + Config::dot;
- m_manifestDir =
- QLatin1String("qthelp://") + config.getString(prefix + QLatin1String("namespace"));
- m_manifestDir += QLatin1Char('/') + config.getString(prefix + QLatin1String("virtualFolder"))
- + QLatin1Char('/');
- readManifestMetaContent();
- m_examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH);
- if (!m_examplesPath.isEmpty())
- m_examplesPath += QLatin1Char('/');
-}
-
-template <typename F>
-void ManifestWriter::processManifestMetaContent(const QString &fullName, F matchFunc)
-{
- for (const auto &index : m_manifestMetaContent) {
- const auto &names = index.m_names;
- for (const QString &name : names) {
- bool match;
- qsizetype wildcard = name.indexOf(QChar('*'));
- switch (wildcard) {
- case -1: // no wildcard used, exact match required
- match = (fullName == name);
- break;
- case 0: // '*' matches all examples
- match = true;
- break;
- default: // match with wildcard at the end
- match = fullName.startsWith(name.left(wildcard));
- }
- if (match)
- matchFunc(index);
- }
- }
-}
-
-/*!
- This function outputs one or more manifest files in XML.
- They are used by Creator.
- */
-void ManifestWriter::generateManifestFiles()
-{
- generateManifestFile("examples", "example");
- generateManifestFile("demos", "demo");
- m_qdb->exampleNodeMap().clear();
- m_manifestMetaContent.clear();
-}
-
-/*!
- This function is called by generateManifestFiles(), once
- for each manifest file to be generated. \a manifest is the
- type of manifest file.
- */
-void ManifestWriter::generateManifestFile(const QString &manifest, const QString &element)
-{
- const ExampleNodeMap &exampleNodeMap = m_qdb->exampleNodeMap();
- if (exampleNodeMap.isEmpty())
- return;
-
- bool demos = (manifest == QLatin1String("demos"));
- if (!std::any_of(exampleNodeMap.cbegin(), exampleNodeMap.cend(),
- [demos](const ExampleNode *en) {
- return demos == en->name().startsWith("demos");
- }))
- return;
-
- const QString outputFileName = manifest + "-manifest.xml";
- QFile outputFile(m_outputDirectory + QLatin1Char('/') + outputFileName);
- if (!outputFile.open(QFile::WriteOnly | QFile::Text))
- return;
-
- QXmlStreamWriter writer(&outputFile);
- writer.setAutoFormatting(true);
- writer.writeStartDocument();
- writer.writeStartElement("instructionals");
- writer.writeAttribute("module", m_project);
- writer.writeStartElement(manifest);
-
- for (const auto &example : exampleNodeMap.values()) {
- QMap<QString, QString> usedAttributes;
- if (demos != example->name().startsWith("demos"))
- continue;
- m_tags.clear();
- const QString installPath = retrieveExampleInstallationPath(example);
- const QString fullName = m_project + QLatin1Char('/') + example->title();
-
- processManifestMetaContent(
- fullName, [&](const ManifestMetaFilter &filter) { m_tags += filter.m_tags; });
- includeTagsAddedWithMetaCommand(example);
- // omit from the manifest if explicitly marked broken
- if (m_tags.contains("broken"))
- continue;
-
- // attributes that are always written for the element
- usedAttributes.insert("name", example->title());
- usedAttributes.insert("docUrl", m_manifestDir + Generator::currentGenerator()->fileBase(example) + ".html");
-
- if (!example->projectFile().isEmpty())
- usedAttributes.insert("projectPath", installPath + example->projectFile());
- if (!example->imageFileName().isEmpty())
- usedAttributes.insert("imageUrl", m_manifestDir + example->imageFileName());
-
- processManifestMetaContent(fullName, [&](const ManifestMetaFilter &filter) {
- const auto attributes = filter.m_attributes;
- for (const auto &attribute : attributes) {
- const QLatin1Char div(':');
- QStringList attrList = attribute.split(div);
- if (attrList.count() == 1)
- attrList.append(QStringLiteral("true"));
- QString attrName = attrList.takeFirst();
- if (!usedAttributes.contains(attrName))
- usedAttributes.insert(attrName, attrList.join(div));
- }
- });
-
- // write the example/demo element
- writer.writeStartElement(element);
- for (auto it = usedAttributes.cbegin(); it != usedAttributes.cend(); ++it)
- writer.writeAttribute(it.key(), it.value());
-
- warnAboutUnusedAttributes(usedAttributes.keys(), example);
- writeDescription(&writer, example);
- addWordsFromModuleNamesAsTags();
- addTitleWordsToTags(example);
- cleanUpTags();
- writeTagsElement(&writer);
-
- const QString exampleName = example->name().mid(example->name().lastIndexOf('/') + 1);
- const auto files = example->files();
- const QMap<int, QString> filesToOpen = getFilesToOpen(files, exampleName);
- writeFilesToOpen(writer, installPath, filesToOpen);
-
- writer.writeEndElement(); // example/demo
- }
-
- writer.writeEndElement(); // examples
- writer.writeEndElement(); // instructionals
- writer.writeEndDocument();
- outputFile.close();
-}
-
-/*!
- \internal
-
- Populates the tags and writes the tags element, then clears the tags member.
- */
-void ManifestWriter::writeTagsElement(QXmlStreamWriter *writer)
-{
- Q_ASSERT(writer);
- if (m_tags.isEmpty())
- return;
-
- writer->writeStartElement("tags");
- QStringList sortedTags = m_tags.values();
- sortedTags.sort();
- writer->writeCharacters(sortedTags.join(","));
- writer->writeEndElement(); // tags
-}
-
-/*!
- \internal
-
- Clean up tags, exclude invalid and common words.
- */
-void ManifestWriter::cleanUpTags()
-{
- QSet<QString> cleanedTags;
-
- for (auto tag : m_tags) {
- if (tag.at(0) == '(')
- tag.remove(0, 1).chop(1);
- if (tag.endsWith(QLatin1Char(':')))
- tag.chop(1);
-
- if (tag.length() < 2 || tag.at(0).isDigit() || tag.at(0) == '-'
- || tag == QLatin1String("qt") || tag == QLatin1String("the")
- || tag == QLatin1String("and") || tag == QLatin1String("doc")
- || tag.startsWith(QLatin1String("example")) || tag.startsWith(QLatin1String("chapter")))
- continue;
- cleanedTags << tag;
- }
- m_tags = cleanedTags;
-}
-
-/*!
- \internal
-
- Add the example's title as tags.
- */
-void ManifestWriter::addTitleWordsToTags(const ExampleNode *example)
-{
- Q_ASSERT(example);
-
- const auto &titleWords = example->title().toLower().split(QLatin1Char(' '));
- m_tags += QSet<QString>(titleWords.cbegin(), titleWords.cend());
-}
-
-/*!
- \internal
-
- Add words from module name as tags
- QtQuickControls -> qt,quick,controls
- QtOpenGL -> qt,opengl
- QtQuick3D -> qt,quick3d
- */
-void ManifestWriter::addWordsFromModuleNamesAsTags()
-{
- // '?<=': positive lookbehind
- QRegularExpression re("([A-Z]+[a-z0-9]*((?<=3)D|GL)?)");
- qsizetype pos = 0;
- QRegularExpressionMatch match;
- while ((match = re.match(m_project, pos)).hasMatch()) {
- m_tags << match.captured(1).toLower();
- pos = match.capturedEnd();
- }
-}
-
-/*!
- \internal
-
- Include tags added via \meta {tag} {tag1[,tag2,...]}
- within \example topic.
- */
-void ManifestWriter::includeTagsAddedWithMetaCommand(const ExampleNode *example)
-{
- Q_ASSERT(example);
-
- const QStringMultiMap *metaTagMap = example->doc().metaTagMap();
- if (metaTagMap) {
- for (const auto &tag : metaTagMap->values("tag")) {
- const auto &tagList = tag.toLower().split(QLatin1Char(','), Qt::SkipEmptyParts);
- m_tags += QSet<QString>(tagList.constBegin(), tagList.constEnd());
- }
- }
-}
-
-/*!
- Reads metacontent - additional attributes and tags to apply
- when generating manifest files, read from config.
-
- The manifest metacontent map is cleared immediately after
- the manifest files have been generated.
- */
-void ManifestWriter::readManifestMetaContent()
-{
- Config &config = Config::instance();
- const QStringList names =
- config.getStringList(CONFIG_MANIFESTMETA + Config::dot + QStringLiteral("filters"));
-
- for (const auto &manifest : names) {
- ManifestMetaFilter filter;
- QString prefix = CONFIG_MANIFESTMETA + Config::dot + manifest + Config::dot;
- filter.m_names = config.getStringSet(prefix + QStringLiteral("names"));
- filter.m_attributes = config.getStringSet(prefix + QStringLiteral("attributes"));
- filter.m_tags = config.getStringSet(prefix + QStringLiteral("tags"));
- m_manifestMetaContent.append(filter);
- }
-}
-
-/*!
- Retrieve the install path for the \a example as specified with
- the \\meta command, or fall back to the one defined in .qdocconf.
- */
-QString ManifestWriter::retrieveExampleInstallationPath(const ExampleNode *example) const
-{
- QString installPath;
- if (example->doc().metaTagMap())
- installPath = example->doc().metaTagMap()->value(QLatin1String("installpath"));
- if (installPath.isEmpty())
- installPath = m_examplesPath;
- if (!installPath.isEmpty() && !installPath.endsWith(QLatin1Char('/')))
- installPath += QLatin1Char('/');
-
- return installPath;
-}
-
-QT_END_NAMESPACE