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#include "tracer.h"
4
5#include <QtCore/QDir>
6#include <QtCore/QFileInfo>
7#include <QtCore/QLibraryInfo>
8#include <QtCore/QLocale>
9#include <QtCore/QScopedPointer>
10#include <QtCore/QStringList>
11#include <QtCore/QTranslator>
12#include <QtCore/QUrl>
13
14#include <QtWidgets/QApplication>
15#include <QtGui/QDesktopServices>
16
17#include <QtHelp/QHelpEngine>
18#include <QtHelp/QHelpSearchEngine>
19
20#include <QtSql/QSqlDatabase>
21
22#if defined(BROWSER_QTWEBKIT)
23#include <QtGui/QFont>
24#include <QWebSettings>
25#endif
26
27#include "../shared/collectionconfiguration.h"
29#include "mainwindow.h"
30#include "cmdlineparser.h"
31
32// #define TRACING_REQUESTED
33
35
36using namespace Qt::StringLiterals;
37
38namespace {
39
40void
41updateLastPagesOnUnregister(QHelpEngineCore& helpEngine, const QString& nsName)
42{
44 int lastPage = CollectionConfiguration::lastTabPage(helpEngine);
45 QStringList currentPages = CollectionConfiguration::lastShownPages(helpEngine);
46 if (!currentPages.isEmpty()) {
47 QStringList zoomList = CollectionConfiguration::lastZoomFactors(helpEngine);
48 while (zoomList.size() < currentPages.size())
49 zoomList.append(CollectionConfiguration::DefaultZoomFactor);
50
51 for (int i = currentPages.size(); --i >= 0;) {
52 if (QUrl(currentPages.at(i)).host() == nsName) {
53 zoomList.removeAt(i);
54 currentPages.removeAt(i);
55 lastPage = (lastPage == (i + 1)) ? 1 : lastPage;
56 }
57 }
58
59 CollectionConfiguration::setLastShownPages(helpEngine, currentPages);
61 CollectionConfiguration::setLastZoomFactors(helpEngine, zoomList);
62 }
63}
64
65void stripNonexistingDocs(QHelpEngineCore& collection)
66{
68 const QStringList &namespaces = collection.registeredDocumentations();
69 for (const QString &ns : namespaces) {
70 QFileInfo fi(collection.documentationFileName(ns));
71 if (!fi.exists() || !fi.isFile())
72 collection.unregisterDocumentation(ns);
73 }
74}
75
76QString indexFilesFolder(const QString &collectionFile)
77{
79 QString indexFilesFolder = ".fulltextsearch"_L1;
80 if (!collectionFile.isEmpty()) {
81 QFileInfo fi(collectionFile);
82 indexFilesFolder = u'.' + fi.fileName().left(fi.fileName().lastIndexOf(".qhc"_L1));
83 }
84 return indexFilesFolder;
85}
86
87/*
88 * Returns the expected absolute file path of the cached collection file
89 * correspondinging to the given collection's file.
90 * It may or may not exist yet.
91 */
92QString constructCachedCollectionFilePath(const QHelpEngineCore &collection)
93{
95 const QString &filePath = collection.collectionFile();
96 const QString &fileName = QFileInfo(filePath).fileName();
97 const QString &cacheDir = CollectionConfiguration::cacheDir(collection);
98 const QString &dir = !cacheDir.isEmpty()
99 && CollectionConfiguration::cacheDirIsRelativeToCollection(collection)
100 ? QFileInfo(filePath).dir().absolutePath()
101 + QDir::separator() + cacheDir
102 : MainWindow::collectionFileDirectory(false, cacheDir);
103 return dir + QDir::separator() + fileName;
104}
105
106bool synchronizeDocs(QHelpEngineCore &collection,
107 QHelpEngineCore &cachedCollection,
108 CmdLineParser &cmd)
109{
111 const QDateTime &lastCollectionRegisterTime =
112 CollectionConfiguration::lastRegisterTime(collection);
113 if (!lastCollectionRegisterTime.isValid() || lastCollectionRegisterTime
114 < CollectionConfiguration::lastRegisterTime(cachedCollection))
115 return true;
116
117 const QStringList &docs = collection.registeredDocumentations();
118 const QStringList &cachedDocs = cachedCollection.registeredDocumentations();
119
120 /*
121 * Ensure that the cached collection contains all docs that
122 * the collection contains.
123 */
124 for (const QString &doc : docs) {
125 if (!cachedDocs.contains(doc)) {
126 const QString &docFile = collection.documentationFileName(doc);
127 if (!cachedCollection.registerDocumentation(docFile)) {
128 cmd.showMessage(QCoreApplication::translate("Assistant",
129 "Error registering documentation file '%1': %2").
130 arg(docFile).arg(cachedCollection.error()), true);
131 return false;
132 }
133 }
134 }
135
137
138 return true;
139}
140
141bool removeSearchIndex(const QString &collectionFile)
142{
144 const QString path =
145 QFileInfo(collectionFile).path() + u'/' + indexFilesFolder(collectionFile);
146
147 QDir dir(path);
148 if (!dir.exists())
149 return false;
150
151 const QStringList &list = dir.entryList(QDir::Files | QDir::Hidden);
152 for (const QString &item : list)
153 dir.remove(item);
154 return true;
155}
156
157QCoreApplication* createApplication(int &argc, char *argv[])
158{
160#ifndef Q_OS_WIN
161 // Look for arguments that imply command-line mode.
162 const char * cmdModeArgs[] = {
163 "-help", "-register", "-unregister", "-remove-search-index",
164 "-rebuild-search-index"
165 };
166 for (int i = 1; i < argc; ++i) {
167 for (size_t j = 0; j < sizeof cmdModeArgs/sizeof *cmdModeArgs; ++j) {
168 if (strcmp(argv[i], cmdModeArgs[j]) == 0)
169 return new QCoreApplication(argc, argv);
170 }
171 }
172#endif
173 QApplication *app = new QApplication(argc, argv);
174 app->connect(app, &QGuiApplication::lastWindowClosed, app,
175 &QCoreApplication::quit);
176 return app;
177}
178
179bool registerDocumentation(QHelpEngineCore &collection, CmdLineParser &cmd,
180 bool printSuccess)
181{
183 if (!collection.registerDocumentation(cmd.helpFile())) {
184 cmd.showMessage(QCoreApplication::translate("Assistant",
185 "Could not register documentation file\n%1\n\nReason:\n%2")
186 .arg(cmd.helpFile()).arg(collection.error()), true);
187 return false;
188 }
189 if (printSuccess)
190 cmd.showMessage(QCoreApplication::translate("Assistant",
191 "Documentation successfully registered."),
192 false);
194 return true;
195}
196
197bool unregisterDocumentation(QHelpEngineCore &collection,
198 const QString &namespaceName, CmdLineParser &cmd, bool printSuccess)
199{
201 if (!collection.unregisterDocumentation(namespaceName)) {
202 cmd.showMessage(QCoreApplication::translate("Assistant",
203 "Could not unregister documentation"
204 " file\n%1\n\nReason:\n%2").
205 arg(cmd.helpFile()).arg(collection.error()), true);
206 return false;
207 }
208 updateLastPagesOnUnregister(collection, namespaceName);
209 if (printSuccess)
210 cmd.showMessage(QCoreApplication::translate("Assistant",
211 "Documentation successfully unregistered."),
212 false);
213 return true;
214}
215
216void setupTranslation(const QString &fileName, const QString &dir)
217{
218 QTranslator *translator = new QTranslator(QCoreApplication::instance());
219 if (translator->load(QLocale(), fileName, "_"_L1, dir))
220 QCoreApplication::installTranslator(translator);
221}
222
223void setupTranslations()
224{
226 const QString &resourceDir
227 = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
228 setupTranslation("assistant"_L1, resourceDir);
229 setupTranslation("qt"_L1, resourceDir);
230 setupTranslation("qt_help"_L1, resourceDir);
231}
232
233} // Anonymous namespace.
234
240
242{
243 /*
244 * Create the collection objects that we need. We always have the
245 * cached collection file. Depending on whether the user specified
246 * one, we also may have an input collection file.
247 */
248 const QString collectionFile = cmd->collectionFile();
249 const bool collectionFileGiven = !collectionFile.isEmpty();
250 QScopedPointer<QHelpEngineCore> collection;
251 if (collectionFileGiven) {
252 collection.reset(new QHelpEngineCore(collectionFile));
253 if (!collection->setupData()) {
254 cmd->showMessage(QCoreApplication::translate("Assistant",
255 "Error reading collection file '%1': %2.")
256 .arg(collectionFile).arg(collection->error()), true);
257 return ExitFailure;
258 }
259 }
260 const QString &cachedCollectionFile = collectionFileGiven
261 ? constructCachedCollectionFilePath(*collection)
262 : MainWindow::defaultHelpCollectionFileName();
263 if (collectionFileGiven && !QFileInfo(cachedCollectionFile).exists()
264 && !collection->copyCollectionFile(cachedCollectionFile)) {
265 cmd->showMessage(QCoreApplication::translate("Assistant",
266 "Error creating collection file '%1': %2.")
267 .arg(cachedCollectionFile).arg(collection->error()), true);
268 return ExitFailure;
269 }
270 QHelpEngineCore cachedCollection(cachedCollectionFile);
271 if (!cachedCollection.setupData()) {
272 cmd->showMessage(QCoreApplication::translate("Assistant",
273 "Error reading collection file '%1': %2.")
274 .arg(cachedCollectionFile)
275 .arg(cachedCollection.error()), true);
276 return ExitFailure;
277 }
278
279 stripNonexistingDocs(cachedCollection);
280 if (collectionFileGiven) {
281 if (CollectionConfiguration::isNewer(*collection, cachedCollection))
283 cachedCollection);
284 if (!synchronizeDocs(*collection, cachedCollection, *cmd))
285 return ExitFailure;
286 }
287
289 const QStringList &cachedDocs =
290 cachedCollection.registeredDocumentations();
291 const QString &namespaceName =
292 QHelpEngineCore::namespaceName(cmd->helpFile());
294 if (collectionFileGiven
295 && !registerDocumentation(*collection, *cmd, true))
296 return ExitFailure;
297 if (!cachedDocs.contains(namespaceName)
298 && !registerDocumentation(cachedCollection, *cmd, !collectionFileGiven))
299 return ExitFailure;
300 return ExitSuccess;
301 }
303 if (collectionFileGiven
304 && !unregisterDocumentation(*collection, namespaceName, *cmd, true))
305 return ExitFailure;
306 if (cachedDocs.contains(namespaceName)
307 && !unregisterDocumentation(cachedCollection, namespaceName,
308 *cmd, !collectionFileGiven))
309 return ExitFailure;
310 return ExitSuccess;
311 }
312 }
313
314 if (cmd->removeSearchIndex()) {
315 return removeSearchIndex(cachedCollectionFile)
316 ? ExitSuccess : ExitFailure;
317 }
318
319 if (!QSqlDatabase::isDriverAvailable("QSQLITE"_L1)) {
320 cmd->showMessage(QCoreApplication::translate("Assistant",
321 "Cannot load sqlite database driver!"),
322 true);
323 return ExitFailure;
324 }
325
326 if (!cmd->currentFilter().isEmpty()) {
327 if (collectionFileGiven)
328 collection->setCurrentFilter(cmd->currentFilter());
329 cachedCollection.setCurrentFilter(cmd->currentFilter());
330 }
331
332 if (collectionFileGiven)
333 cmd->setCollectionFile(cachedCollectionFile);
334
335 return NoExit;
336}
337
338int main(int argc, char *argv[])
339{
341 QScopedPointer<QCoreApplication> a(createApplication(argc, argv));
342#if QT_CONFIG(library)
343 a->addLibraryPath(a->applicationDirPath() + "/plugins"_L1);
344#endif
345 setupTranslations();
346
347#if defined(BROWSER_QTWEBKIT)
348 if (qobject_cast<QApplication *>(a.data())) {
349 QFont f;
350 f.setStyleHint(QFont::SansSerif);
351 QWebSettings::globalSettings()->setFontFamily(QWebSettings::StandardFont, f.defaultFamily());
352 }
353#endif // BROWSER_QTWEBKIT
354
355 // Parse arguments.
356 CmdLineParser cmd(a->arguments());
357 CmdLineParser::Result res = cmd.parse();
358 if (res == CmdLineParser::Help)
359 return 0;
360 else if (res == CmdLineParser::Error)
361 return -1;
362
363 const ExitStatus status = preliminarySetup(&cmd);
364 switch (status) {
365 case ExitFailure: return EXIT_FAILURE;
366 case ExitSuccess: return EXIT_SUCCESS;
367 default: break;
368 }
369
370 MainWindow *w = new MainWindow(&cmd);
371 w->show();
372
373 /*
374 * We need to be careful here: The main window has to be deleted before
375 * the help engine wrapper, which has to be deleted before the
376 * QApplication.
377 */
378 const int retval = a->exec();
379 delete w;
381 return retval;
382}
int main(int argc, char *argv[])
[2]
Definition buffer.cpp:77
RegisterState registerRequest() const
bool removeSearchIndex() const
static bool isNewer(const QHelpEngineCore &newer, const QHelpEngineCore &older)
static void setLastTabPage(QHelpEngineCore &helpEngine, int lastPage)
static void copyConfiguration(const QHelpEngineCore &source, QHelpEngineCore &target)
static void updateLastRegisterTime(QHelpEngineCore &helpEngine)
static int lastTabPage(const QHelpEngineCore &helpEngine)
static void removeInstance()
static ExitStatus preliminarySetup(CmdLineParser *cmd)
Definition main.cpp:241
ExitStatus
Definition main.cpp:235
@ ExitSuccess
Definition main.cpp:236
@ ExitFailure
Definition main.cpp:237
@ NoExit
Definition main.cpp:238
#define TRACE_OBJ
Definition tracer.h:34