// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qdocgenerator.h" #include #include using namespace Qt::Literals::StringLiterals; namespace QDocGenerator { // See definition of idstring and licenseid in https://spdx.org/spdx-specification-21-web-version static bool isSpdxLicenseId(const QString &str) { if (str.isEmpty()) return false; for (auto iter(str.cbegin()); iter != str.cend(); ++iter) { const QChar c = *iter; if (!((c >= QLatin1Char('A') && c <= QLatin1Char('Z')) || (c >= QLatin1Char('a') && c <= QLatin1Char('z')) || (c >= QLatin1Char('0') && c <= QLatin1Char('9')) || (c == QLatin1Char('-')) || (c == QLatin1Char('.')))) return false; } return true; } static QString languageJoin(const QStringList &list) { QString result; for (int i = 0; i < list.size(); ++i) { QString delimiter = u", "_s; if (i == list.size() - 1) // last item delimiter.clear(); else if (list.size() == 2) delimiter = u" and "_s; else if (list.size() > 2 && i == list.size() - 2) delimiter = u", and "_s; // oxford comma result += list[i] + delimiter; } return result; } // Embed source code between \badcode ... \endbadcode // Also, avoid '*/' breaking qdoc by passing the star as argument static void sourceCode(QTextStream &out, const QString &src) { out << "\\badcode *\n"; out << QString(src).replace(u"*/"_s, u"\\1/"_s); out << "\n\\endcode\n\n"; } static void generate(QTextStream &out, const Package &package, const QDir &baseDir) { out << "/*!\n\n"; for (const QString &part : package.qtParts) { out << "\\ingroup attributions-" << package.qdocModule << "-" << part << "\n"; out << "\\ingroup attributions-" << part << "\n"; } if (package.qtParts.contains("libs"_L1)) { // show up in xxx-index.html page of module out << "\\ingroup attributions-" << package.qdocModule << "\n"; // include in '\generatelist annotatedattributions' out << "\\page " << package.qdocModule << "-attribution-" << package.id << ".html\n"; out << "\\attribution\n"; } else { out << "\\page " << package.qdocModule << "-attribution-" << package.id << ".html \n"; } out << "\\target " << package.id << "\n\n"; out << "\\title " << package.name; if (!package.version.isEmpty()) out << ", version " << package.version; out << "\n\n\\brief " << package.license << "\n\n"; if (!package.description.isEmpty()) out << package.description << "\n\n"; if (!package.qtUsage.isEmpty()) out << package.qtUsage << "\n\n"; QStringList sourcePaths; if (package.files.isEmpty()) { sourcePaths << baseDir.relativeFilePath(package.path); } else { const QDir packageDir(package.path); for (const QString &filePath: package.files) { const QString absolutePath = packageDir.absoluteFilePath(filePath); sourcePaths << baseDir.relativeFilePath(absolutePath); } } out << "The sources can be found in " << languageJoin(sourcePaths) << ".\n\n"; const bool hasPackageVersion = !package.version.isEmpty(); const bool hasPackageDownloadLocation = !package.downloadLocation.isEmpty(); if (!package.homepage.isEmpty()) { out << "\\l{" << package.homepage << "}{Project Homepage}"; if (hasPackageVersion) out << ", "; } if (hasPackageVersion) { out << "upstream version: "; if (hasPackageDownloadLocation) out << "\\l{" << package.downloadLocation << "}{"; out << package.version; if (hasPackageDownloadLocation) out << "}"; } out << "\n\n"; QString copyright; if (!package.copyright.isEmpty()) copyright = package.copyright; else if (!package.copyrightFileContents.isEmpty()) copyright = package.copyrightFileContents; if (!copyright.isEmpty()) { out << "\n"; sourceCode(out, copyright); } if (isSpdxLicenseId(package.licenseId) && !package.licenseId.startsWith("LicenseRef-"_L1) && package.licenseId != "NONE"_L1) { out << "\\l{https://spdx.org/licenses/" << package.licenseId << ".html}" << "{" << package.license << "}.\n\n"; } else { out << package.license << ".\n\n"; } for (const QString &license : package.licenseFilesContents) sourceCode(out, license); out << "*/\n"; } void generate(QTextStream &out, const QList &packages, const QString &baseDirectory, LogLevel logLevel) { if (logLevel == VerboseLog) std::cerr << qPrintable(tr("Generating qdoc file...")) << std::endl; QDir baseDir(baseDirectory); for (const Package &package : packages) generate(out, package, baseDir); } } // namespace QDocGenerator