Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtmoduleinfo.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qtmoduleinfo.h"
5#include "utils.h"
6
7#include <QDirListing>
8#include <QJsonDocument>
9#include <QJsonArray>
10#include <QDebug>
11
12#include <iostream>
13#include <algorithm>
14#include <unordered_map>
15
16using namespace Qt::StringLiterals;
17
18static QStringList toStringList(const QJsonArray &jsonArray)
19{
20 QStringList result;
21 for (const auto &item : jsonArray) {
22 if (item.isString())
23 result.append(item.toString());
24 }
25 return result;
26}
27
34
35using TranslationCatalogs = std::vector<TranslationCatalog>;
36
37static TranslationCatalogs readTranslationsCatalogs(const QString &translationsDir,
38 bool verbose,
39 QString *errorString)
40{
41 QFile file(translationsDir + QLatin1String("/catalogs.json"));
42 if (verbose) {
43 std::wcerr << "Trying to read translation catalogs from \""
44 << qUtf8Printable(file.fileName()) << "\".\n";
45 }
46 if (!file.open(QIODevice::ReadOnly)) {
47 *errorString = QLatin1String("Cannot open ") + file.fileName();
48 return {};
49 }
50
51 QJsonParseError jsonParseError;
52 QJsonDocument document = QJsonDocument::fromJson(file.readAll(), &jsonParseError);
53 if (jsonParseError.error != QJsonParseError::NoError) {
54 *errorString = jsonParseError.errorString();
55 return {};
56 }
57
58 if (!document.isArray()) {
59 *errorString = QLatin1String("Expected an array as root element of ") + file.fileName();
60 return {};
61 }
62
63 TranslationCatalogs catalogs;
64 for (const QJsonValueRef &item : document.array()) {
65 TranslationCatalog catalog;
66 catalog.name = item[QLatin1String("name")].toString();
67 catalog.repositories = toStringList(item[QLatin1String("repositories")].toArray());
68 catalog.modules = toStringList(item[QLatin1String("modules")].toArray());
69 if (verbose)
70 std::wcerr << "Found catalog \"" << qUtf8Printable(catalog.name) << "\".\n";
71 catalogs.emplace_back(std::move(catalog));
72 }
73
74 return catalogs;
75}
76
77static QtModule moduleFromJsonFile(const QString &filePath, QString *errorString)
78{
79 QFile file(filePath);
80 if (!file.open(QIODevice::ReadOnly)) {
81 *errorString = QLatin1String("Cannot open ") + file.fileName();
82 return {};
83 }
84
85 QJsonParseError jsonParseError;
86 QJsonDocument document = QJsonDocument::fromJson(file.readAll(), &jsonParseError);
87 if (jsonParseError.error != QJsonParseError::NoError) {
88 *errorString = jsonParseError.errorString();
89 return {};
90 }
91
92 if (!document.isObject()) {
93 *errorString = QLatin1String("Expected an object as root element of ") + file.fileName();
94 return {};
95 }
96
97 const QJsonObject obj = document.object();
98 QtModule module;
99 module.name = "Qt6"_L1 + obj[QLatin1String("name")].toString();
100 module.repository = obj[QLatin1String("repository")].toString();
101 module.internal = obj[QLatin1String("internal")].toBool();
102 module.pluginTypes = toStringList(obj[QLatin1String("plugin_types")].toArray());
103 return module;
104}
105
106static void dump(const QtModule &module)
107{
108 std::wcerr << "Found module \"" << qUtf8Printable(module.name) << "\".\n";
109 if (!module.pluginTypes.isEmpty())
110 qDebug().nospace() << " plugin types: " << module.pluginTypes;
111 if (!module.translationCatalog.isEmpty())
112 qDebug().nospace() << " translation catalog: "<< module.translationCatalog;
113}
114
115bool QtModuleInfoStore::populate(const QString &modulesDir, const QString &translationsDir,
116 bool verbose, QString *errorString)
117{
118 const TranslationCatalogs catalogs = readTranslationsCatalogs(translationsDir, verbose,
119 errorString);
120 if (!errorString->isEmpty()) {
121 std::wcerr << "Warning: Translations will not be available due to the following error."
122 << std::endl << *errorString << std::endl;
123 errorString->clear();
124 }
125 std::unordered_map<QString, QString> moduleToCatalogMap;
126 std::unordered_map<QString, QString> repositoryToCatalogMap;
127 for (const TranslationCatalog &catalog : catalogs) {
128 for (const QString &module : catalog.modules) {
129 moduleToCatalogMap.insert(std::make_pair(module, catalog.name));
130 }
131 for (const QString &repository : catalog.repositories) {
132 repositoryToCatalogMap.insert(std::make_pair(repository, catalog.name));
133 }
134 }
135
136 using F = QDirListing::IteratorFlag;
137 // Read modules, and assign a bit as ID.
138 for (const auto &dirEntry : QDirListing(modulesDir, {u"*.json"_s}, F::FilesOnly)) {
139 QtModule module = moduleFromJsonFile(dirEntry.filePath(), errorString);
140 if (!errorString->isEmpty())
141 return false;
142 if (module.internal && module.name.endsWith(QStringLiteral("Private")))
143 module.name.chop(7);
144 module.id = modules.size();
145 if (module.id == QtModule::InvalidId) {
146 *errorString = "Internal Error: too many modules for ModuleBitset to hold."_L1;
147 return false;
148 }
149
150 {
151 auto it = moduleToCatalogMap.find(module.name);
152 if (it != moduleToCatalogMap.end())
153 module.translationCatalog = it->second;
154 }
155 if (module.translationCatalog.isEmpty()) {
156 auto it = repositoryToCatalogMap.find(module.repository);
157 if (it != repositoryToCatalogMap.end())
158 module.translationCatalog = it->second;
159 }
160 if (verbose)
161 dump(module);
162 modules.emplace_back(std::move(module));
163 }
164
165 return true;
166}
167
168const QtModule &QtModuleInfoStore::moduleById(size_t id) const
169{
170 return modules.at(id);
171}
172
173size_t QtModuleInfoStore::moduleIdForPluginType(const QString &pluginType) const
174{
175 auto moduleHasPluginType = [&pluginType] (const QtModule &module) {
176 return module.pluginTypes.contains(pluginType);
177 };
178
179 auto it = std::find_if(modules.begin(), modules.end(), moduleHasPluginType);
180 if (it != modules.end())
181 return it->id ;
182
183 return QtModule::InvalidId;
184}
bool populate(const QString &modulesDir, const QString &translationsDir, bool verbose, QString *errorString)
const QtModule & moduleById(size_t id) const
size_t moduleIdForPluginType(const QString &pluginType) const
static QtModule moduleFromJsonFile(const QString &filePath, QString *errorString)
static TranslationCatalogs readTranslationsCatalogs(const QString &translationsDir, bool verbose, QString *errorString)
static QStringList toStringList(const QJsonArray &jsonArray)
static void dump(const QtModule &module)
bool internal
QStringList repositories