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
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "../shared/collectionconfiguration.h"
8
9#include <QtCore/QBuffer>
10#include <QtCore/QDataStream>
11#include <QtCore/QDir>
12#include <QtCore/QFileInfo>
13#include <QtCore/QLibraryInfo>
14#include <QtCore/QRegularExpression>
15#include <QtCore/QTranslator>
16
17#include <QtGui/QGuiApplication>
18
19#include <QtHelp/QHelpEngineCore>
20
21
23
24class QHG {
25 Q_DECLARE_TR_FUNCTIONS(QHelpGenerator)
26};
27
28static const char QHP[] = "qhp";
29static const char QCH[] = "qch";
30
31static const char QHCP[] = "qhcp";
32static const char QHC[] = "qhc";
33
34namespace {
35 QString absoluteFilePath(const QString &basePath, const QString &fileName)
36 {
37 return QDir(basePath).absoluteFilePath(fileName);
38 }
39}
40
41int generateCollectionFile(const QByteArray &data, const QString &basePath, const QString outputFile)
42{
43 fputs(qPrintable(QHG::tr("Reading collection config file...\n")), stdout);
44 CollectionConfigReader config;
45 config.readData(data);
46 if (config.hasError()) {
47 fputs(qPrintable(QHG::tr("Collection config file error: %1\n")
48 .arg(config.errorString())), stderr);
49 return 1;
50 }
51
52 const QMap<QString, QString> &filesToGenerate = config.filesToGenerate();
53 for (auto it = filesToGenerate.cbegin(), end = filesToGenerate.cend(); it != end; ++it) {
54 fputs(qPrintable(QHG::tr("Generating help for %1...\n").arg(it.key())), stdout);
55 QHelpProjectData helpData;
56 if (!helpData.readData(absoluteFilePath(basePath, it.key()))) {
57 fprintf(stderr, "%s\n", qPrintable(helpData.errorMessage()));
58 return 1;
59 }
60
61 HelpGenerator helpGenerator;
62 if (!helpGenerator.generate(&helpData, absoluteFilePath(basePath, it.value()))) {
63 fprintf(stderr, "%s\n", qPrintable(helpGenerator.error()));
64 return 1;
65 }
66 }
67
68 fputs(qPrintable(QHG::tr("Creating collection file...\n")), stdout);
69
70 QFileInfo colFi(outputFile);
71 if (colFi.exists()) {
72 if (!colFi.dir().remove(colFi.fileName())) {
73 fputs(qPrintable(QHG::tr("The file %1 cannot be overwritten.\n")
74 .arg(outputFile)), stderr);
75 return 1;
76 }
77 }
78
79 QHelpEngineCore helpEngine(outputFile);
80 helpEngine.setReadOnly(false);
81 if (!helpEngine.setupData()) {
82 fprintf(stderr, "%s\n", qPrintable(helpEngine.error()));
83 return 1;
84 }
85
86 for (const QString &file : config.filesToRegister()) {
87 if (!helpEngine.registerDocumentation(absoluteFilePath(basePath, file))) {
88 fprintf(stderr, "%s\n", qPrintable(helpEngine.error()));
89 return 1;
90 }
91 }
92 if (!config.filesToRegister().isEmpty()) {
93 if (Q_UNLIKELY(qEnvironmentVariableIsSet("SOURCE_DATE_EPOCH"))) {
94 QDateTime dt;
95 dt.setTimeZone(QTimeZone::UTC);
96 dt.setSecsSinceEpoch(qEnvironmentVariableIntValue("SOURCE_DATE_EPOCH"));
98 } else {
100 }
101 }
102
103 if (!config.title().isEmpty())
104 CollectionConfiguration::setWindowTitle(helpEngine, config.title());
105
106 if (!config.homePage().isEmpty()) {
107 CollectionConfiguration::setDefaultHomePage(helpEngine,
108 config.homePage());
109 }
110
111 if (!config.startPage().isEmpty()) {
112 CollectionConfiguration::setLastShownPages(helpEngine,
113 QStringList(config.startPage()));
114 }
115
116 if (!config.currentFilter().isEmpty()) {
117 helpEngine.setCurrentFilter(config.currentFilter());
118 }
119
120 if (!config.cacheDirectory().isEmpty()) {
121 CollectionConfiguration::setCacheDir(helpEngine, config.cacheDirectory(),
122 config.cacheDirRelativeToCollection());
123 }
124
126 config.enableFilterFunctionality());
128 !config.hideFilterFunctionality());
130 config.enableDocumentationManager());
132 config.enableAddressBar());
134 !config.hideAddressBar());
135 uint time = QDateTime::currentMSecsSinceEpoch() / 1000;
136 if (Q_UNLIKELY(qEnvironmentVariableIsSet("SOURCE_DATE_EPOCH")))
137 time = qEnvironmentVariableIntValue("SOURCE_DATE_EPOCH");
138 CollectionConfiguration::setCreationTime(helpEngine, time);
140 config.fullTextSearchFallbackEnabled());
141
142 if (!config.applicationIcon().isEmpty()) {
143 QFile icon(absoluteFilePath(basePath, config.applicationIcon()));
144 if (!icon.open(QIODevice::ReadOnly)) {
145 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr);
146 return 1;
147 }
148 CollectionConfiguration::setApplicationIcon(helpEngine, icon.readAll());
149 }
150
151 if (config.aboutMenuTexts().size()) {
152 QByteArray ba;
153 QDataStream s(&ba, QIODevice::WriteOnly);
154 const QMap<QString, QString> &aboutMenuTexts = config.aboutMenuTexts();
155 for (auto it = aboutMenuTexts.cbegin(), end = aboutMenuTexts.cend(); it != end; ++it)
156 s << it.key() << it.value();
157 CollectionConfiguration::setAboutMenuTexts(helpEngine, ba);
158 }
159
160 if (!config.aboutIcon().isEmpty()) {
161 QFile icon(absoluteFilePath(basePath, config.aboutIcon()));
162 if (!icon.open(QIODevice::ReadOnly)) {
163 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr);
164 return 1;
165 }
166 CollectionConfiguration::setAboutIcon(helpEngine, icon.readAll());
167 }
168
169 if (config.aboutTextFiles().size()) {
170 QByteArray ba;
171 QDataStream s(&ba, QIODevice::WriteOnly);
172 QMap<QString, QByteArray> imgData;
173
174 QRegularExpression srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>"), QRegularExpression::InvertedGreedinessOption);
175 QRegularExpression imgRegExp(QLatin1String("(<img[^>]+>)"), QRegularExpression::InvertedGreedinessOption);
176
177 const QMap<QString, QString> &aboutMenuTexts = config.aboutTextFiles();
178 for (auto it = aboutMenuTexts.cbegin(), end = aboutMenuTexts.cend(); it != end; ++it) {
179 s << it.key();
180 QFileInfo fi(absoluteFilePath(basePath, it.value()));
181 QFile f(fi.absoluteFilePath());
182 if (!f.open(QIODevice::ReadOnly)) {
183 fputs(qPrintable(QHG::tr("Cannot open %1.\n").arg(f.fileName())), stderr);
184 return 1;
185 }
186 QByteArray data = f.readAll();
187 s << data;
188
189 QString contents = QString::fromUtf8(data);
190 int pos = 0;
191 QRegularExpressionMatch match;
192 while ((match = imgRegExp.match(contents, pos)).hasMatch()) {
193 QString imgTag = match.captured(1);
194 pos = match.capturedEnd();
195
196 if ((match = srcRegExp.match(imgTag)).hasMatch()) {
197 QString src = match.captured(2);
198 if (src.isEmpty())
199 src = match.captured(3);
200
201 QFile img(fi.absolutePath() + QDir::separator() + src);
202 if (img.open(QIODevice::ReadOnly)) {
203 if (!imgData.contains(src))
204 imgData.insert(src, img.readAll());
205 } else {
206 fputs(qPrintable(QHG::tr("Cannot open referenced image file %1.\n")
207 .arg(img.fileName())), stderr);
208 }
209 }
210 }
211 }
212 CollectionConfiguration::setAboutTexts(helpEngine, ba);
213 if (imgData.size()) {
214 QByteArray imageData;
215 QBuffer buffer(&imageData);
216 buffer.open(QIODevice::WriteOnly);
217 QDataStream out(&buffer);
218 out << imgData;
219 CollectionConfiguration::setAboutImages(helpEngine, imageData);
220 }
221 }
222 return 0;
223}
224
225int main(int argc, char *argv[])
226{
227 QString error;
228 QString outputFile;
229 QString inputFile;
230 QString basePath;
231 bool showHelp = false;
232 bool showVersion = false;
233 bool checkLinks = false;
234 bool silent = false;
235
236 // don't require a window manager even though we're a QGuiApplication
237 qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
238
239 QGuiApplication app(argc, argv);
240#ifndef Q_OS_WIN32
241 QTranslator translator;
242 QTranslator qtTranslator;
243 QTranslator qt_helpTranslator;
244 QString sysLocale = QLocale::system().name();
245 QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
246 if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir)
247 && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)
248 && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) {
249 app.installTranslator(&translator);
250 app.installTranslator(&qtTranslator);
251 app.installTranslator(&qt_helpTranslator);
252 }
253#endif // Q_OS_WIN32
254
255 for (int i = 1; i < argc; ++i) {
256 const QString arg = QString::fromLocal8Bit(argv[i]);
257 if (arg == QLatin1String("-o")) {
258 if (++i < argc) {
259 QFileInfo fi(QString::fromLocal8Bit(argv[i]));
260 outputFile = fi.absoluteFilePath();
261 } else {
262 error = QHG::tr("Missing output file name.");
263 }
264 } else if (arg == QLatin1String("-v")) {
265 showVersion = true;
266 } else if (arg == QLatin1String("-h")) {
267 showHelp = true;
268 } else if (arg == QLatin1String("-c")) {
269 checkLinks = true;
270 } else if (arg == QLatin1String("-s")) {
271 silent = true;
272 } else {
273 const QFileInfo fi(arg);
274 inputFile = fi.absoluteFilePath();
275 basePath = fi.absolutePath();
276 }
277 }
278
279 if (showVersion) {
280 fputs(qPrintable(QHG::tr("Qt Help Generator version 1.0 (Qt %1)\n")
281 .arg(QT_VERSION_STR)), stdout);
282 return 0;
283 }
284
285 enum InputType {
286 InputQhp,
287 InputQhcp,
288 InputUnknown
289 };
290
291 InputType inputType = InputUnknown;
292
293 if (!showHelp) {
294 if (inputFile.isEmpty()) {
295 error = QHG::tr("Missing input file name.");
296 } else {
297 const QFileInfo fi(inputFile);
298 if (fi.suffix() == QHP)
299 inputType = InputQhp;
300 else if (fi.suffix() == QHCP)
301 inputType = InputQhcp;
302
303 if (inputType == InputUnknown)
304 error = QHG::tr("Unknown input file type.");
305 }
306 }
307
308 const QString help = QHG::tr("\nUsage:\n\n"
309 "qhelpgenerator <file> [options]\n\n"
310 " -o <output-file> Generates a Qt compressed help\n"
311 " called <output-file> (*.qch) for the\n"
312 " Qt help project <file> (*.qhp).\n"
313 " Generates a Qt help collection\n"
314 " called <output-file> (*.qhc) for the\n"
315 " Qt help collection project <file> (*.qhcp).\n"
316 " If this option is not specified\n"
317 " a default name will be used\n"
318 " (*.qch for *.qhp and *.qhc for *.qhcp).\n"
319 " -c Checks whether all links in HTML files\n"
320 " point to files in this help project.\n"
321 " -s Suppresses status messages.\n"
322 " -v Displays the version of \n"
323 " qhelpgenerator.\n\n");
324
325 if (showHelp) {
326 fputs(qPrintable(help), stdout);
327 return 0;
328 } else if (!error.isEmpty()) {
329 fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help));
330 return 1;
331 }
332
333 // detect input file type (qhp or qhcp)
334
335 QFile file(inputFile);
336 if (!file.open(QIODevice::ReadOnly)) {
337 fputs(qPrintable(QHG::tr("Could not open %1.\n").arg(inputFile)), stderr);
338 return 1;
339 }
340
341 const QString outputExtension = inputType == InputQhp ? QCH : QHC;
342
343 if (outputFile.isEmpty()) {
344 if (inputType == InputQhcp || !checkLinks) {
345 QFileInfo fi(inputFile);
346 outputFile = basePath + QDir::separator()
347 + fi.baseName() + QLatin1Char('.') + outputExtension;
348 }
349 } else {
350 // check if the output dir exists -- create if it doesn't
351 QFileInfo fi(outputFile);
352 QDir parentDir = fi.dir();
353 if (!parentDir.exists()) {
354 if (!parentDir.mkpath(QLatin1String("."))) {
355 fputs(qPrintable(QHG::tr("Could not create output directory: %1\n")
356 .arg(parentDir.path())), stderr);
357 }
358 }
359 }
360
361 if (inputType == InputQhp) {
362 QHelpProjectData *helpData = new QHelpProjectData();
363 if (!helpData->readData(inputFile)) {
364 fprintf(stderr, "%s\n", qPrintable(helpData->errorMessage()));
365 return 1;
366 }
367
368 HelpGenerator generator(silent);
369 bool success = true;
370 if (checkLinks)
371 success = generator.checkLinks(*helpData);
372 if (success && !outputFile.isEmpty())
373 success = generator.generate(helpData, outputFile);
374 delete helpData;
375 if (!success) {
376 fprintf(stderr, "%s\n", qPrintable(generator.error()));
377 return 1;
378 }
379 } else {
380 const QByteArray data = file.readAll();
381 return generateCollectionFile(data, basePath, outputFile);
382
383 }
384
385 return 0;
386}
int main(int argc, char *argv[])
[2]
Definition buffer.cpp:77
static void setFullTextSearchFallbackEnabled(QHelpEngineCore &helpEngine, bool on)
static void setAddressBarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, bool enabled)
static void setAddressBarEnabled(QHelpEngineCore &helpEngine, bool enabled)
static void updateLastRegisterTime(QHelpEngineCore &helpEngine)
static void setFilterToolbarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, bool enabled)
bool checkLinks(const QHelpProjectData &helpData)
Definition main.cpp:24
The QHelpProjectData class stores all information found in a Qt help project file.
QHelpProjectData()
Constructs a Qt help project data structure.
static const char QHP[]
Definition main.cpp:28
static const char QHC[]
Definition main.cpp:32
int generateCollectionFile(const QByteArray &data, const QString &basePath, const QString outputFile)
Definition main.cpp:41
static const char QCH[]
Definition main.cpp:29
static const char QHCP[]
Definition main.cpp:31