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
helpenginewrapper.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
6#include "../shared/collectionconfiguration.h"
7
8#include <QtCore/QDateTime>
9#include <QtCore/QFileInfo>
10#include <QtCore/QFileSystemWatcher>
11#include <QtCore/QTimer>
12#include <QtHelp/QHelpContentModel>
13#include <QtHelp/QHelpEngine>
14#include <QtHelp/QHelpFilterEngine>
15#include <QtHelp/QHelpIndexModel>
16#include <QtHelp/QHelpLink>
17#include <QtHelp/QHelpSearchEngine>
18
19#include <map>
20#include <memory>
21
22QT_BEGIN_NAMESPACE
23
24using namespace Qt::StringLiterals;
25
26namespace {
27 const QString AppFontKey("appFont"_L1);
28 const QString AppWritingSystemKey("appWritingSystem"_L1);
29 const QString BookmarksKey("Bookmarks"_L1);
30 const QString BrowserFontKey("browserFont"_L1);
31 const QString BrowserWritingSystemKey("browserWritingSystem"_L1);
32 const QString HomePageKey("homepage"_L1);
33 const QString MainWindowKey("MainWindow"_L1);
34 const QString MainWindowGeometryKey("MainWindowGeometry"_L1);
35 const QString SearchWasAttachedKey("SearchWasAttached"_L1);
36 const QString StartOptionKey("StartOption"_L1);
37 const QString UseAppFontKey("useAppFont"_L1);
38 const QString UseBrowserFontKey("useBrowserFont"_L1);
39 const QString VersionKey("qtVersion%1$$$%2"_L1.arg(QLatin1StringView(QT_VERSION_STR)));
40 const QString ShowTabsKey("showTabs"_L1);
41 const QString TopicChooserGeometryKey("TopicChooserGeometry"_L1);
42} // anonymous namespace
43
45{
47public:
49private slots:
50 void forward();
51private:
53
54 const QString m_fileName;
55};
56
58{
60 friend class HelpEngineWrapper;
61 friend class TimeoutForwarder;
62private slots:
63 void qchFileChanged(const QString &fileName);
64
67 void documentationUpdated(const QString &namespaceName);
68
69private:
70 HelpEngineWrapperPrivate(const QString &collectionFile);
71
72 void initFileSystemWatchers();
73 void checkDocFilesWatched();
74 void qchFileChanged(const QString &fileName, bool fromTimeout);
75
76 static const int UpdateGracePeriod = 2000;
77
78 QHelpEngine * const m_helpEngine;
79 QFileSystemWatcher * const m_qchWatcher;
80 struct RecentSignal {
81 QDateTime timestamp;
82 std::unique_ptr<TimeoutForwarder> forwarder;
83 };
84 std::map<QString, RecentSignal> m_recentQchUpdates;
85};
86
87HelpEngineWrapper *HelpEngineWrapper::helpEngineWrapper = nullptr;
88
93
94HelpEngineWrapper &HelpEngineWrapper::instance(const QString &collectionFile)
95{
97 /*
98 * Note that this Singleton cannot be static, because it has to be
99 * deleted before the QApplication.
100 */
101 if (!helpEngineWrapper)
102 helpEngineWrapper = new HelpEngineWrapper(collectionFile);
103 return *helpEngineWrapper;
104}
105
107{
109 delete helpEngineWrapper;
110 helpEngineWrapper = nullptr;
111}
112
113HelpEngineWrapper::HelpEngineWrapper(const QString &collectionFile)
114 : d(new HelpEngineWrapperPrivate(collectionFile))
115{
117
118 /*
119 * Otherwise we will waste time if several new docs are found,
120 * because we will start to index them, only to be interrupted
121 * by the next request. Also, there is a nasty SQLITE bug that will
122 * cause the application to hang for minutes in that case.
123 * This call is reverted by initialDocSetupDone(), which must be
124 * called after the new docs have been installed.
125 */
126// TODO: probably remove it
127 disconnect(d->m_helpEngine, &QHelpEngineCore::setupFinished,
128 searchEngine(), &QHelpSearchEngine::scheduleIndexDocumentation);
129
130 connect(d, &HelpEngineWrapperPrivate::documentationRemoved,
131 this, &HelpEngineWrapper::documentationRemoved);
132 connect(d, &HelpEngineWrapperPrivate::documentationUpdated,
133 this, &HelpEngineWrapper::documentationUpdated);
134 connect(d->m_helpEngine, &QHelpEngineCore::setupFinished,
135 this, &HelpEngineWrapper::setupFinished);
136}
137
138HelpEngineWrapper::~HelpEngineWrapper()
139{
141 const QStringList &namespaces = d->m_helpEngine->registeredDocumentations();
142 for (const QString &nameSpace : namespaces) {
143 const QString &docFile
144 = d->m_helpEngine->documentationFileName(nameSpace);
145 d->m_qchWatcher->removePath(docFile);
146 }
147
148 delete d;
149}
150
152{
154// TODO: probably remove it
155 connect(d->m_helpEngine, &QHelpEngineCore::setupFinished,
156 searchEngine(), &QHelpSearchEngine::scheduleIndexDocumentation);
158}
159
160QHelpSearchEngine *HelpEngineWrapper::searchEngine() const
161{
163 return d->m_helpEngine->searchEngine();
164}
165
166QHelpContentModel *HelpEngineWrapper::contentModel() const
167{
169 return d->m_helpEngine->contentModel();
170}
171
172QHelpIndexModel *HelpEngineWrapper::indexModel() const
173{
175 return d->m_helpEngine->indexModel();
176}
177
178QHelpContentWidget *HelpEngineWrapper::contentWidget()
179{
181 return d->m_helpEngine->contentWidget();
182}
183
184QHelpIndexWidget *HelpEngineWrapper::indexWidget()
185{
187 return d->m_helpEngine->indexWidget();
188}
189
191{
193 return d->m_helpEngine->registeredDocumentations();
194}
195
196QString HelpEngineWrapper::documentationFileName(const QString &namespaceName) const
197{
199 return d->m_helpEngine->documentationFileName(namespaceName);
200}
201
203{
205 return d->m_helpEngine->collectionFile();
206}
207
208bool HelpEngineWrapper::registerDocumentation(const QString &docFile)
209{
211 d->checkDocFilesWatched();
212 if (!d->m_helpEngine->registerDocumentation(docFile))
213 return false;
214 d->m_qchWatcher->addPath(docFile);
215 d->checkDocFilesWatched();
216 return true;
217}
218
219bool HelpEngineWrapper::unregisterDocumentation(const QString &namespaceName)
220{
222 d->checkDocFilesWatched();
223 const QString &file = d->m_helpEngine->documentationFileName(namespaceName);
224 if (!d->m_helpEngine->unregisterDocumentation(namespaceName))
225 return false;
226 d->m_qchWatcher->removePath(file);
227 d->checkDocFilesWatched();
228 return true;
229}
230
232{
234 return d->m_helpEngine->setupData();
235}
236
237QUrl HelpEngineWrapper::findFile(const QUrl &url) const
238{
240 return d->m_helpEngine->findFile(url);
241}
242
243QByteArray HelpEngineWrapper::fileData(const QUrl &url) const
244{
246 return d->m_helpEngine->fileData(url);
247}
248
250{
252 return d->m_helpEngine->documentsForIdentifier(id);
253}
254
256{
258 return d->m_helpEngine->error();
259}
260
261QHelpFilterEngine *HelpEngineWrapper::filterEngine() const
262{
263 return d->m_helpEngine->filterEngine();
264}
265
266const QStringList HelpEngineWrapper::qtDocInfo(const QString &component) const
267{
269 return d->m_helpEngine->customValue(VersionKey.arg(component)).toString().
270 split(CollectionConfiguration::ListSeparator);
271}
272
273void HelpEngineWrapper::setQtDocInfo(const QString &component,
274 const QStringList &doc)
275{
277 d->m_helpEngine->setCustomValue(VersionKey.arg(component),
278 doc.join(CollectionConfiguration::ListSeparator));
279}
280
282{
284 return CollectionConfiguration::lastShownPages(*d->m_helpEngine);
285}
286
287void HelpEngineWrapper::setLastShownPages(const QStringList &lastShownPages)
288{
290 CollectionConfiguration::setLastShownPages(*d->m_helpEngine, lastShownPages);
291}
292
294{
296 return CollectionConfiguration::lastZoomFactors(*d->m_helpEngine);
297}
298
299void HelpEngineWrapper::setLastZoomFactors(const QStringList &lastZoomFactors)
300{
302 CollectionConfiguration::setLastZoomFactors(*d->m_helpEngine, lastZoomFactors);
303}
304
306{
308 return CollectionConfiguration::cacheDir(*d->m_helpEngine);
309}
310
316
317void HelpEngineWrapper::setCacheDir(const QString &cacheDir,
318 bool relativeToCollection)
319{
321 CollectionConfiguration::setCacheDir(*d->m_helpEngine, cacheDir,
322 relativeToCollection);
323}
324
330
337
343
349
355
357{
360}
361
367
369{
372}
373
379
386
388{
390 return CollectionConfiguration::aboutMenuTexts(*d->m_helpEngine);
391}
392
393void HelpEngineWrapper::setAboutMenuTexts(const QByteArray &texts)
394{
396 CollectionConfiguration::setAboutMenuTexts(*d->m_helpEngine, texts);
397}
398
400{
402 return CollectionConfiguration::aboutIcon(*d->m_helpEngine);
403}
404
405void HelpEngineWrapper::setAboutIcon(const QByteArray &icon)
406{
408 CollectionConfiguration::setAboutIcon(*d->m_helpEngine, icon);
409}
410
412{
414 return CollectionConfiguration::aboutImages(*d->m_helpEngine);
415}
416
417void HelpEngineWrapper::setAboutImages(const QByteArray &images)
418{
420 CollectionConfiguration::setAboutImages(*d->m_helpEngine, images);
421}
422
424{
426 return CollectionConfiguration::aboutTexts(*d->m_helpEngine);
427}
428
429void HelpEngineWrapper::setAboutTexts(const QByteArray &texts)
430{
432 CollectionConfiguration::setAboutTexts(*d->m_helpEngine, texts);
433}
434
436{
438 return CollectionConfiguration::windowTitle(*d->m_helpEngine);
439}
440
441void HelpEngineWrapper::setWindowTitle(const QString &windowTitle)
442{
444 CollectionConfiguration::setWindowTitle(*d->m_helpEngine, windowTitle);
445}
446
448{
450 return CollectionConfiguration::applicationIcon(*d->m_helpEngine);
451}
452
453void HelpEngineWrapper::setApplicationIcon(const QByteArray &icon)
454{
456 CollectionConfiguration::setApplicationIcon(*d->m_helpEngine, icon);
457}
458
460{
462 return d->m_helpEngine->customValue(MainWindowKey).toByteArray();
463}
464
465void HelpEngineWrapper::setMainWindow(const QByteArray &mainWindow)
466{
468 d->m_helpEngine->setCustomValue(MainWindowKey, mainWindow);
469}
470
472{
474 return d->m_helpEngine->customValue(MainWindowGeometryKey).toByteArray();
475}
476
477void HelpEngineWrapper::setMainWindowGeometry(const QByteArray &geometry)
478{
480 d->m_helpEngine->setCustomValue(MainWindowGeometryKey, geometry);
481}
482
484{
486 return d->m_helpEngine->customValue(BookmarksKey).toByteArray();
487}
488
489void HelpEngineWrapper::setBookmarks(const QByteArray &bookmarks)
490{
492 d->m_helpEngine->setCustomValue(BookmarksKey, bookmarks);
493}
494
496{
498 return CollectionConfiguration::lastTabPage(*d->m_helpEngine);
499}
500
502{
504 CollectionConfiguration::setLastTabPage(*d->m_helpEngine, lastPage);
505}
506
508{
510 return d->m_helpEngine->customValue(StartOptionKey, ShowLastPages).toInt();
511}
512
514{
516 d->m_helpEngine->setCustomValue(StartOptionKey, option);
517}
518
520{
522 const QString &homePage
523 = d->m_helpEngine->customValue(HomePageKey).toString();
524 if (!homePage.isEmpty())
525 return homePage;
526 return defaultHomePage();
527}
528
529void HelpEngineWrapper::setHomePage(const QString &page)
530{
532 d->m_helpEngine->setCustomValue(HomePageKey, page);
533
534}
535
537{
539 return CollectionConfiguration::defaultHomePage(*d->m_helpEngine);
540}
541
542void HelpEngineWrapper::setDefaultHomePage(const QString &page)
543{
545 CollectionConfiguration::setDefaultHomePage(*d->m_helpEngine, page);
546}
547
549{
551 return d->m_helpEngine->customValue(UseAppFontKey).isValid();
552}
553
555{
557 return d->m_helpEngine->customValue(UseAppFontKey).toBool();
558}
559
560void HelpEngineWrapper::setUseAppFont(bool useAppFont)
561{
563 d->m_helpEngine->setCustomValue(UseAppFontKey, useAppFont);
564}
565
567{
569 return d->m_helpEngine->customValue(UseBrowserFontKey, false).toBool();
570}
571
572void HelpEngineWrapper::setUseBrowserFont(bool useBrowserFont)
573{
575 d->m_helpEngine->setCustomValue(UseBrowserFontKey, useBrowserFont);
576}
577
579{
581 return qvariant_cast<QFont>(d->m_helpEngine->customValue(AppFontKey));
582}
583
584void HelpEngineWrapper::setAppFont(const QFont &font)
585{
587 d->m_helpEngine->setCustomValue(AppFontKey, font);
588}
589
591{
593 return static_cast<QFontDatabase::WritingSystem>(
594 d->m_helpEngine->customValue(AppWritingSystemKey).toInt());
595}
596
597void HelpEngineWrapper::setAppWritingSystem(QFontDatabase::WritingSystem system)
598{
600 d->m_helpEngine->setCustomValue(AppWritingSystemKey, system);
601}
602
604{
606 return qvariant_cast<QFont>(d->m_helpEngine->customValue(BrowserFontKey));
607}
608
609void HelpEngineWrapper::setBrowserFont(const QFont &font)
610{
612 d->m_helpEngine->setCustomValue(BrowserFontKey, font);
613}
614
616{
618 return static_cast<QFontDatabase::WritingSystem>(
619 d->m_helpEngine->customValue(BrowserWritingSystemKey).toInt());
620}
621
622void HelpEngineWrapper::setBrowserWritingSystem(QFontDatabase::WritingSystem system)
623{
625 d->m_helpEngine->setCustomValue(BrowserWritingSystemKey, system);
626}
627
629{
631 return d->m_helpEngine->customValue(ShowTabsKey, false).toBool();
632}
633
635{
637 d->m_helpEngine->setCustomValue(ShowTabsKey, show);
638}
639
645
647{
649 return d->m_helpEngine->customValue(TopicChooserGeometryKey).toByteArray();
650}
651
652void HelpEngineWrapper::setTopicChooserGeometry(const QByteArray &geometry)
653{
655 d->m_helpEngine->setCustomValue(TopicChooserGeometryKey, geometry);
656}
657
658QHelpEngineCore *HelpEngineWrapper::helpEngine() const
659{
660 return d->m_helpEngine;
661}
662
663
664// -- TimeoutForwarder
665
666TimeoutForwarder::TimeoutForwarder(const QString &fileName)
667 : m_fileName(fileName)
668{
670}
671
672void TimeoutForwarder::forward()
673{
675 HelpEngineWrapper::instance().d->qchFileChanged(m_fileName, true);
676}
677
678// -- HelpEngineWrapperPrivate
679
680HelpEngineWrapperPrivate::HelpEngineWrapperPrivate(const QString &collectionFile)
681 : m_helpEngine(new QHelpEngine(collectionFile, this)),
682 m_qchWatcher(new QFileSystemWatcher(this))
683{
685 m_helpEngine->setReadOnly(false);
686 m_helpEngine->setUsesFilterEngine(true);
687 initFileSystemWatchers();
688}
689
690void HelpEngineWrapperPrivate::initFileSystemWatchers()
691{
693 for (const QString &ns : m_helpEngine->registeredDocumentations())
694 m_qchWatcher->addPath(m_helpEngine->documentationFileName(ns));
695
696 connect(m_qchWatcher, &QFileSystemWatcher::fileChanged, this,
697 QOverload<const QString &>::of(&HelpEngineWrapperPrivate::qchFileChanged));
698 checkDocFilesWatched();
699}
700
701void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName)
702{
704 qchFileChanged(fileName, false);
705}
706
707void HelpEngineWrapperPrivate::checkDocFilesWatched()
708{
710 const int watchedFilesCount = m_qchWatcher->files().size();
711 const int docFilesCount = m_helpEngine->registeredDocumentations().size();
712 if (watchedFilesCount != docFilesCount) {
713 qWarning("Strange: Have %d docs, but %d are being watched",
714 watchedFilesCount, docFilesCount);
715 }
716}
717
718void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName,
719 bool fromTimeout)
720{
722
723 /*
724 * We don't use QHelpEngineCore::namespaceName(fileName), because the file
725 * may not exist anymore or contain a different namespace.
726 */
727 QString ns;
728 for (const QString &curNs : m_helpEngine->registeredDocumentations()) {
729 if (m_helpEngine->documentationFileName(curNs) == fileName) {
730 ns = curNs;
731 break;
732 }
733 }
734
735 /*
736 * We can't do an assertion here, because QFileSystemWatcher may send the
737 * signal more than once.
738 */
739 if (ns.isEmpty()) {
740 m_recentQchUpdates.erase(fileName);
741 return;
742 }
743
744 /*
745 * Since the QFileSystemWatcher typically sends the signal more than once,
746 * we repeatedly delay our reaction a bit until we think the last signal
747 * was sent.
748 */
749
750 const auto &it = m_recentQchUpdates.find(fileName);
751 const QDateTime now = QDateTime::currentDateTimeUtc();
752
753 // Case 1: This is the first recent signal for the file.
754 if (it == m_recentQchUpdates.end()) {
755 auto forwarder = std::make_unique<TimeoutForwarder>(fileName);
756 QTimer::singleShot(UpdateGracePeriod, forwarder.get(),
757 &TimeoutForwarder::forward);
758 m_recentQchUpdates.emplace(fileName,
759 RecentSignal{std::move(now), std::move(forwarder)});
760 return;
761 }
762
763 auto &[key, entry] = *it;
764
765 // Case 2: The last signal for this file has not expired yet.
766 if (entry.timestamp > now.addMSecs(-UpdateGracePeriod)) {
767 if (!fromTimeout)
768 entry.timestamp = now;
769 else
770 QTimer::singleShot(UpdateGracePeriod, entry.forwarder.get(),
771 &TimeoutForwarder::forward);
772 return;
773 }
774
775 // Case 3: The last signal for this file has expired.
776 if (m_helpEngine->unregisterDocumentation(ns)) {
777 if (!QFileInfo(fileName).exists()
778 || !m_helpEngine->registerDocumentation(fileName)) {
779 m_qchWatcher->removePath(fileName);
780 emit documentationRemoved(ns);
781 } else {
782 emit documentationUpdated(ns);
783 }
784 m_helpEngine->setupData();
785 }
786 m_recentQchUpdates.erase(it);
787}
788
789QT_END_NAMESPACE
790
791#include "helpenginewrapper.moc"
static bool filterFunctionalityEnabled(const QHelpEngineCore &helpEngine)
static void setLastTabPage(QHelpEngineCore &helpEngine, int lastPage)
static bool addressBarVisible(const QHelpEngineCore &helpEngine)
static bool addressBarEnabled(const QHelpEngineCore &helpEngine)
static void setAddressBarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, bool enabled)
static bool documentationManagerEnabled(const QHelpEngineCore &helpEngine)
static void setAddressBarEnabled(QHelpEngineCore &helpEngine, bool enabled)
static int lastTabPage(const QHelpEngineCore &helpEngine)
static bool cacheDirIsRelativeToCollection(const QHelpEngineCore &helpEngine)
static void setFilterToolbarVisible(QHelpEngineCore &helpEngine, bool visible)
static void setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, bool enabled)
static bool filterToolbarVisible(const QHelpEngineCore &helpEngine)
static bool fullTextSearchFallbackEnabled(const QHelpEngineCore &helpEngine)
void documentationUpdated(const QString &namespaceName)
void setHomePage(const QString &page)
QHelpEngineCore * helpEngine() const
QHelpFilterEngine * filterEngine() const
bool registerDocumentation(const QString &docFile)
const QString defaultHomePage() const
void setStartOption(int option)
QHelpSearchEngine * searchEngine() const
const QByteArray bookmarks() const
const QStringList lastShownPages() const
void setDefaultHomePage(const QString &page)
static void removeInstance()
const QString homePage() const
bool fullTextSearchFallbackEnabled() const
void setAddressBarEnabled(bool enabled)
QHelpIndexWidget * indexWidget()
bool cacheDirIsRelativeToCollection() const
const QString windowTitle() const
void setLastZoomFactors(const QStringList &lastZoomFactors)
void setFilterFunctionalityEnabled(bool enabled)
void setShowTabs(bool show)
const QStringList qtDocInfo(const QString &component) const
void setBookmarks(const QByteArray &bookmarks)
const QByteArray mainWindow() const
static HelpEngineWrapper & instance()
const QByteArray mainWindowGeometry() const
void setBrowserFont(const QFont &font)
const QByteArray topicChooserGeometry() const
bool addressBarEnabled() const
const QFont browserFont() const
void setAboutMenuTexts(const QByteArray &texts)
void setFilterToolbarVisible(bool visible)
const QByteArray aboutMenuTexts() const
const QString collectionFile() const
void setAppWritingSystem(QFontDatabase::WritingSystem system)
QByteArray fileData(const QUrl &url) const
void setBrowserWritingSystem(QFontDatabase::WritingSystem system)
void setAppFont(const QFont &font)
bool unregisterDocumentation(const QString &namespaceName)
bool addressBarVisible() const
void setAboutIcon(const QByteArray &icon)
void setUseBrowserFont(bool useBrowserFont)
void setCacheDir(const QString &cacheDir, bool relativeToCollection)
bool documentationManagerEnabled() const
QFontDatabase::WritingSystem browserWritingSystem() const
void setApplicationIcon(const QByteArray &icon)
const QStringList registeredDocumentations() const
QHelpContentWidget * contentWidget()
const QByteArray aboutTexts() const
QHelpIndexModel * indexModel() const
void setAboutImages(const QByteArray &images)
void setTopicChooserGeometry(const QByteArray &geometry)
bool filterFunctionalityEnabled() const
void setMainWindowGeometry(const QByteArray &geometry)
void setAboutTexts(const QByteArray &texts)
void setAddressBarVisible(bool visible)
void setLastTabPage(int lastPage)
const QString cacheDir() const
QUrl findFile(const QUrl &url) const
const QStringList lastZoomFactors() const
const QByteArray applicationIcon() const
const QByteArray aboutImages() const
QList< QHelpLink > documentsForIdentifier(const QString &id) const
QFontDatabase::WritingSystem appWritingSystem() const
void setQtDocInfo(const QString &component, const QStringList &doc)
void setDocumentationManagerEnabled(bool enabled)
void setWindowTitle(const QString &windowTitle)
bool filterToolbarVisible() const
const QByteArray aboutIcon() const
void setUseAppFont(bool useAppFont)
QHelpContentModel * contentModel() const
void setLastShownPages(const QStringList &lastShownPages)
void setMainWindow(const QByteArray &mainWindow)
QString documentationFileName(const QString &namespaceName) const
const QFont appFont() const
@ ShowLastPages
#define TRACE_OBJ
Definition tracer.h:34