summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2018-08-31 16:00:32 +0200
committerEike Ziller <eike.ziller@qt.io>2018-09-04 11:21:18 +0000
commit2c17fbe8dd9fdc619efdeceeddf68ad68f6dfcc1 (patch)
tree36439c95706d27a6c5f4ff9212bda25fe2125651 /src
parent25400751a4b4cd03758862b8365f57e8afed7985 (diff)
downloadqt-creator-2c17fbe8dd9fdc619efdeceeddf68ad68f6dfcc1.tar.gz
Make Core independent from QtHelp
We don't want various plugins to depend on the Help plugin, but we also do not want Core to depend on QtHelp. For example when turning the Help plugin off, documentation should actually no longer be registered through QtHelp. So we need parts of the interface in Core, which must then be delegated to the actual implementation in Help. As positive side-effects the interface in Core will be slimmer, and the code in the Help plugin can later be simplified, too, because then we don't have the "Core" and the "Gui" help engines separated in different plugins anymore, which should remove the need for some setup indirections. Task-number: QTCREATORBUG-20381 Change-Id: I634c5811c45d6a3dfd6ddc682cae270e38384cbf Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp10
-rw-r--r--src/plugins/coreplugin/coreplugin.h2
-rw-r--r--src/plugins/coreplugin/coreplugin.pro3
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs3
-rw-r--r--src/plugins/coreplugin/helpmanager.cpp522
-rw-r--r--src/plugins/coreplugin/helpmanager.h89
-rw-r--r--src/plugins/coreplugin/helpmanager_implementation.h49
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp4
-rw-r--r--src/plugins/coreplugin/mainwindow.h2
-rw-r--r--src/plugins/designer/formeditorw.cpp4
-rw-r--r--src/plugins/help/docsettingspage.cpp5
-rw-r--r--src/plugins/help/filtersettingspage.cpp14
-rw-r--r--src/plugins/help/help.pro2
-rw-r--r--src/plugins/help/help.qbs1
-rw-r--r--src/plugins/help/helpindexfilter.cpp9
-rw-r--r--src/plugins/help/helpmanager.cpp497
-rw-r--r--src/plugins/help/helpmanager.h93
-rw-r--r--src/plugins/help/helpplugin.cpp53
-rw-r--r--src/plugins/help/helpplugin.h3
-rw-r--r--src/plugins/help/localhelpmanager.cpp3
-rw-r--r--src/plugins/qtsupport/exampleslistmodel.cpp16
21 files changed, 786 insertions, 598 deletions
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index 67d2e33495..e2fa72999b 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -69,10 +69,13 @@ using namespace Core;
using namespace Core::Internal;
using namespace Utils;
+static CorePlugin *m_instance = nullptr;
+
CorePlugin::CorePlugin()
{
qRegisterMetaType<Id>();
qRegisterMetaType<Core::Search::TextPosition>();
+ m_instance = this;
}
CorePlugin::~CorePlugin()
@@ -89,6 +92,11 @@ CorePlugin::~CorePlugin()
setCreatorTheme(nullptr);
}
+CorePlugin *CorePlugin::instance()
+{
+ return m_instance;
+}
+
struct CoreArguments {
QColor overrideColor;
Id themeId;
@@ -226,7 +234,6 @@ void CorePlugin::extensionsInitialized()
bool CorePlugin::delayedInitialize()
{
- HelpManager::setupHelpManager();
m_locator->delayedInitialize();
IWizardFactory::allWizardFactories(); // scan for all wizard factories
return true;
@@ -290,6 +297,5 @@ ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown()
{
Find::aboutToShutdown();
m_mainWindow->aboutToShutdown();
- HelpManager::aboutToShutdown();
return SynchronousShutdown;
}
diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h
index b427bdd4d1..cc0d8c75d2 100644
--- a/src/plugins/coreplugin/coreplugin.h
+++ b/src/plugins/coreplugin/coreplugin.h
@@ -53,6 +53,8 @@ public:
CorePlugin();
~CorePlugin() override;
+ static CorePlugin *instance();
+
bool initialize(const QStringList &arguments, QString *errorMessage = nullptr) override;
void extensionsInitialized() override;
bool delayedInitialize() override;
diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro
index 53b3943476..b722987beb 100644
--- a/src/plugins/coreplugin/coreplugin.pro
+++ b/src/plugins/coreplugin/coreplugin.pro
@@ -5,8 +5,6 @@ QT += \
qml \
sql
-qtHaveModule(help): QT += help
-
# embedding build time information prevents repeatedly binary exact versions from same source code
isEmpty(QTC_SHOW_BUILD_DATE): QTC_SHOW_BUILD_DATE = $$(QTC_SHOW_BUILD_DATE)
!isEmpty(QTC_SHOW_BUILD_DATE): DEFINES += QTC_SHOW_BUILD_DATE
@@ -195,6 +193,7 @@ HEADERS += corejsextensions.h \
designmode.h \
editortoolbar.h \
helpmanager.h \
+ helpmanager_implementation.h \
outputpanemanager.h \
navigationsubwidget.h \
sidebarwidget.h \
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index c19b5d6845..885aeba1e3 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -9,7 +9,7 @@ Project {
QtcPlugin {
Depends {
name: "Qt"
- submodules: ["widgets", "xml", "network", "qml", "sql", "help", "printsupport"]
+ submodules: ["widgets", "xml", "network", "qml", "sql", "printsupport"]
}
Depends {
@@ -86,6 +86,7 @@ Project {
"generatedfile.h",
"helpmanager.cpp",
"helpmanager.h",
+ "helpmanager_implementation.h",
"icontext.cpp",
"icontext.h",
"icore.cpp",
diff --git a/src/plugins/coreplugin/helpmanager.cpp b/src/plugins/coreplugin/helpmanager.cpp
index 51a2c426d7..a27b1499b3 100644
--- a/src/plugins/coreplugin/helpmanager.cpp
+++ b/src/plugins/coreplugin/helpmanager.cpp
@@ -23,526 +23,82 @@
**
****************************************************************************/
-#include "helpmanager.h"
+#include "helpmanager_implementation.h"
-#include <coreplugin/icore.h>
-#include <coreplugin/progressmanager/progressmanager.h>
-#include <utils/algorithm.h>
-#include <utils/filesystemwatcher.h>
+#include "coreplugin.h"
+
+#include <extensionsystem/pluginspec.h>
#include <utils/qtcassert.h>
-#include <utils/runextensions.h>
-#include <QDateTime>
-#include <QDebug>
-#include <QDir>
-#include <QFileInfo>
-#include <QFutureWatcher>
-#include <QStringList>
#include <QUrl>
-#ifdef QT_HELP_LIB
-
-#include <QHelpEngineCore>
-
-#include <QMutexLocker>
-#include <QSqlDatabase>
-#include <QSqlDriver>
-#include <QSqlError>
-#include <QSqlQuery>
-
-static const char kUserDocumentationKey[] = "Help/UserDocumentation";
-static const char kUpdateDocumentationTask[] = "UpdateDocumentationTask";
-
namespace Core {
+namespace HelpManager {
-struct HelpManagerPrivate
-{
- HelpManagerPrivate() = default;
- ~HelpManagerPrivate();
-
- const QStringList documentationFromInstaller();
- void readSettings();
- void writeSettings();
- void cleanUpDocumentation();
-
- bool m_needsSetup = true;
- QHelpEngineCore *m_helpEngine = nullptr;
- Utils::FileSystemWatcher *m_collectionWatcher = nullptr;
-
- // data for delayed initialization
- QSet<QString> m_filesToRegister;
- QSet<QString> m_nameSpacesToUnregister;
- QHash<QString, QVariant> m_customValues;
+// makes sure that plugins can connect to HelpManager signals even if the Help plugin is not loaded
+Q_GLOBAL_STATIC(Signals, m_signals)
- QSet<QString> m_userRegisteredFiles;
+static Implementation *m_instance = nullptr;
- QMutex m_helpengineMutex;
- QFuture<bool> m_registerFuture;
-};
-
-static HelpManager *m_instance = nullptr;
-static HelpManagerPrivate *d = nullptr;
-
-static const char linksForKeyQuery[] = "SELECT d.Title, f.Name, e.Name, "
- "d.Name, a.Anchor FROM IndexTable a, FileNameTable d, FolderTable e, "
- "NamespaceTable f WHERE a.FileId=d.FileId AND d.FolderId=e.Id AND "
- "a.NamespaceId=f.Id AND a.Name='%1'";
-
-// -- DbCleaner
-
-struct DbCleaner
+static bool checkInstance()
{
- DbCleaner(const QString &dbName) : name(dbName) {}
- ~DbCleaner() { QSqlDatabase::removeDatabase(name); }
- QString name;
-};
-
-// -- HelpManager
-
-HelpManager::HelpManager(QObject *parent) :
- QObject(parent)
-{
- QTC_CHECK(!m_instance);
- m_instance = this;
- d = new HelpManagerPrivate;
-}
-
-HelpManager::~HelpManager()
-{
- delete d;
- m_instance = nullptr;
-}
-
-HelpManager *HelpManager::instance()
-{
- Q_ASSERT(m_instance);
- return m_instance;
+ auto plugin = Internal::CorePlugin::instance();
+ // HelpManager API can only be used after the actual implementation has been created by the
+ // Help plugin, so check that the plugins have all been created. That is the case
+ // when the Core plugin is initialized.
+ QTC_CHECK(plugin && plugin->pluginSpec()
+ && plugin->pluginSpec()->state() >= ExtensionSystem::PluginSpec::Initialized);
+ return m_instance != nullptr;
}
-QString HelpManager::collectionFilePath()
+Signals *Signals::instance()
{
- return QDir::cleanPath(ICore::userResourcePath()
- + QLatin1String("/helpcollection.qhc"));
+ return m_signals;
}
-void HelpManager::registerDocumentation(const QStringList &files)
+Implementation::Implementation()
{
- if (d->m_needsSetup) {
- for (const QString &filePath : files)
- d->m_filesToRegister.insert(filePath);
- return;
- }
-
- QFuture<bool> future = Utils::runAsync(&HelpManager::registerDocumentationNow, files);
- Utils::onResultReady(future, m_instance, [](bool docsChanged){
- if (docsChanged) {
- d->m_helpEngine->setupData();
- emit m_instance->documentationChanged();
- }
- });
- ProgressManager::addTask(future, tr("Update Documentation"),
- kUpdateDocumentationTask);
-}
-
-void HelpManager::registerDocumentationNow(QFutureInterface<bool> &futureInterface,
- const QStringList &files)
-{
- QMutexLocker locker(&d->m_helpengineMutex);
-
- futureInterface.setProgressRange(0, files.count());
- futureInterface.setProgressValue(0);
-
- QHelpEngineCore helpEngine(collectionFilePath());
- helpEngine.setupData();
- bool docsChanged = false;
- QStringList nameSpaces = helpEngine.registeredDocumentations();
- for (const QString &file : files) {
- if (futureInterface.isCanceled())
- break;
- futureInterface.setProgressValue(futureInterface.progressValue() + 1);
- const QString &nameSpace = helpEngine.namespaceName(file);
- if (nameSpace.isEmpty())
- continue;
- if (!nameSpaces.contains(nameSpace)) {
- if (helpEngine.registerDocumentation(file)) {
- nameSpaces.append(nameSpace);
- docsChanged = true;
- } else {
- qWarning() << "Error registering namespace '" << nameSpace
- << "' from file '" << file << "':" << helpEngine.error();
- }
- } else {
- const QLatin1String key("CreationDate");
- const QString &newDate = helpEngine.metaData(file, key).toString();
- const QString &oldDate = helpEngine.metaData(
- helpEngine.documentationFileName(nameSpace), key).toString();
- if (QDateTime::fromString(newDate, Qt::ISODate)
- > QDateTime::fromString(oldDate, Qt::ISODate)) {
- if (helpEngine.unregisterDocumentation(nameSpace)) {
- docsChanged = true;
- helpEngine.registerDocumentation(file);
- }
- }
- }
- }
- futureInterface.reportResult(docsChanged);
-}
-
-void HelpManager::unregisterDocumentation(const QStringList &nameSpaces)
-{
- if (d->m_needsSetup) {
- for (const QString &name : nameSpaces)
- d->m_nameSpacesToUnregister.insert(name);
- return;
- }
-
- QMutexLocker locker(&d->m_helpengineMutex);
- bool docsChanged = false;
- for (const QString &nameSpace : nameSpaces) {
- const QString filePath = d->m_helpEngine->documentationFileName(nameSpace);
- if (d->m_helpEngine->unregisterDocumentation(nameSpace)) {
- docsChanged = true;
- d->m_userRegisteredFiles.remove(filePath);
- } else {
- qWarning() << "Error unregistering namespace '" << nameSpace
- << "' from file '" << filePath
- << "': " << d->m_helpEngine->error();
- }
- }
- locker.unlock();
- if (docsChanged)
- emit m_instance->documentationChanged();
-}
-
-void HelpManager::registerUserDocumentation(const QStringList &filePaths)
-{
- for (const QString &filePath : filePaths)
- d->m_userRegisteredFiles.insert(filePath);
- registerDocumentation(filePaths);
-}
-
-QSet<QString> HelpManager::userDocumentationPaths()
-{
- return d->m_userRegisteredFiles;
+ QTC_CHECK(!m_instance);
+ m_instance = this;
}
-static QUrl buildQUrl(const QString &ns, const QString &folder,
- const QString &relFileName, const QString &anchor)
+Implementation::~Implementation()
{
- QUrl url;
- url.setScheme(QLatin1String("qthelp"));
- url.setAuthority(ns);
- url.setPath(QLatin1Char('/') + folder + QLatin1Char('/') + relFileName);
- url.setFragment(anchor);
- return url;
+ m_instance = nullptr;
}
-// This should go into Qt 4.8 once we start using it for Qt Creator
-QMap<QString, QUrl> HelpManager::linksForKeyword(const QString &key)
+void registerDocumentation(const QStringList &files)
{
- QMap<QString, QUrl> links;
- QTC_ASSERT(!d->m_needsSetup, return links);
-
- const QLatin1String sqlite("QSQLITE");
- const QLatin1String name("HelpManager::linksForKeyword");
-
- DbCleaner cleaner(name);
- QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
- if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
- const QStringList &registeredDocs = d->m_helpEngine->registeredDocumentations();
- for (const QString &nameSpace : registeredDocs) {
- db.setDatabaseName(d->m_helpEngine->documentationFileName(nameSpace));
- if (db.open()) {
- QSqlQuery query = QSqlQuery(db);
- query.setForwardOnly(true);
- query.exec(QString::fromLatin1(linksForKeyQuery).arg(key));
- while (query.next()) {
- QString title = query.value(0).toString();
- if (title.isEmpty()) // generate a title + corresponding path
- title = key + QLatin1String(" : ") + query.value(3).toString();
- links.insertMulti(title, buildQUrl(query.value(1).toString(),
- query.value(2).toString(), query.value(3).toString(),
- query.value(4).toString()));
- }
- }
- }
- }
- return links;
+ if (checkInstance())
+ m_instance->registerDocumentation(files);
}
-QMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &id)
+void unregisterDocumentation(const QStringList &nameSpaces)
{
- QMap<QString, QUrl> empty;
- QTC_ASSERT(!d->m_needsSetup, return empty);
- return d->m_helpEngine->linksForIdentifier(id);
+ if (checkInstance())
+ m_instance->unregisterDocumentation(nameSpaces);
}
-QUrl HelpManager::findFile(const QUrl &url)
+QMap<QString, QUrl> linksForIdentifier(const QString &id)
{
- QTC_ASSERT(!d->m_needsSetup, return QUrl());
- return d->m_helpEngine->findFile(url);
+ return checkInstance() ? m_instance->linksForIdentifier(id) : QMap<QString, QUrl>();
}
-QByteArray HelpManager::fileData(const QUrl &url)
+QByteArray fileData(const QUrl &url)
{
- QTC_ASSERT(!d->m_needsSetup, return QByteArray());
- return d->m_helpEngine->fileData(url);
+ return checkInstance() ? m_instance->fileData(url) : QByteArray();
}
-void HelpManager::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocation location)
+void handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocation location)
{
- emit m_instance->helpRequested(url, location);
+ if (checkInstance())
+ m_instance->handleHelpRequest(url, location);
}
-void HelpManager::handleHelpRequest(const QString &url, HelpViewerLocation location)
+void handleHelpRequest(const QString &url, HelpViewerLocation location)
{
handleHelpRequest(QUrl(url), location);
}
-QStringList HelpManager::registeredNamespaces()
-{
- QTC_ASSERT(!d->m_needsSetup, return QStringList());
- return d->m_helpEngine->registeredDocumentations();
-}
-
-QString HelpManager::namespaceFromFile(const QString &file)
-{
- QTC_ASSERT(!d->m_needsSetup, return QString());
- return d->m_helpEngine->namespaceName(file);
-}
-
-QString HelpManager::fileFromNamespace(const QString &nameSpace)
-{
- QTC_ASSERT(!d->m_needsSetup, return QString());
- return d->m_helpEngine->documentationFileName(nameSpace);
-}
-
-void HelpManager::setCustomValue(const QString &key, const QVariant &value)
-{
- if (d->m_needsSetup) {
- d->m_customValues.insert(key, value);
- return;
- }
- if (d->m_helpEngine->setCustomValue(key, value))
- emit m_instance->collectionFileChanged();
-}
-
-QVariant HelpManager::customValue(const QString &key, const QVariant &value)
-{
- QTC_ASSERT(!d->m_needsSetup, return QVariant());
- return d->m_helpEngine->customValue(key, value);
-}
-
-HelpManager::Filters HelpManager::filters()
-{
- QTC_ASSERT(!d->m_needsSetup, return Filters());
-
- Filters filters;
- const QStringList &customFilters = d->m_helpEngine->customFilters();
- for (const QString &filter : customFilters)
- filters.insert(filter, d->m_helpEngine->filterAttributes(filter));
- return filters;
-}
-
-HelpManager::Filters HelpManager::fixedFilters()
-{
- Filters fixedFilters;
- QTC_ASSERT(!d->m_needsSetup, return fixedFilters);
-
- const QLatin1String sqlite("QSQLITE");
- const QLatin1String name("HelpManager::fixedCustomFilters");
-
- DbCleaner cleaner(name);
- QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
- if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
- const QStringList &registeredDocs = d->m_helpEngine->registeredDocumentations();
- for (const QString &nameSpace : registeredDocs) {
- db.setDatabaseName(d->m_helpEngine->documentationFileName(nameSpace));
- if (db.open()) {
- QSqlQuery query = QSqlQuery(db);
- query.setForwardOnly(true);
- query.exec(QLatin1String("SELECT Name FROM FilterNameTable"));
- while (query.next()) {
- const QString &filter = query.value(0).toString();
- fixedFilters.insert(filter, d->m_helpEngine->filterAttributes(filter));
- }
- }
- }
- }
- return fixedFilters;
-}
-
-HelpManager::Filters HelpManager::userDefinedFilters()
-{
- QTC_ASSERT(!d->m_needsSetup, return Filters());
-
- Filters all = filters();
- const Filters &fixed = fixedFilters();
- for (Filters::const_iterator it = fixed.constBegin(); it != fixed.constEnd(); ++it)
- all.remove(it.key());
- return all;
-}
-
-void HelpManager::removeUserDefinedFilter(const QString &filter)
-{
- QTC_ASSERT(!d->m_needsSetup, return);
-
- if (d->m_helpEngine->removeCustomFilter(filter))
- emit m_instance->collectionFileChanged();
-}
-
-void HelpManager::addUserDefinedFilter(const QString &filter, const QStringList &attr)
-{
- QTC_ASSERT(!d->m_needsSetup, return);
-
- if (d->m_helpEngine->addCustomFilter(filter, attr))
- emit m_instance->collectionFileChanged();
-}
-
-void HelpManager::aboutToShutdown()
-{
- if (d && d->m_registerFuture.isRunning()) {
- d->m_registerFuture.cancel();
- d->m_registerFuture.waitForFinished();
- }
-}
-
-// -- private
-
-void HelpManager::setupHelpManager()
-{
- if (!d->m_needsSetup)
- return;
- d->m_needsSetup = false;
-
- d->readSettings();
-
- // create the help engine
- d->m_helpEngine = new QHelpEngineCore(collectionFilePath(), m_instance);
- d->m_helpEngine->setupData();
-
- for (const QString &filePath : d->documentationFromInstaller())
- d->m_filesToRegister.insert(filePath);
-
- d->cleanUpDocumentation();
-
- if (!d->m_nameSpacesToUnregister.isEmpty()) {
- unregisterDocumentation(d->m_nameSpacesToUnregister.toList());
- d->m_nameSpacesToUnregister.clear();
- }
-
- if (!d->m_filesToRegister.isEmpty()) {
- registerDocumentation(d->m_filesToRegister.toList());
- d->m_filesToRegister.clear();
- }
-
- QHash<QString, QVariant>::const_iterator it;
- for (it = d->m_customValues.constBegin(); it != d->m_customValues.constEnd(); ++it)
- setCustomValue(it.key(), it.value());
-
- emit m_instance->setupFinished();
-}
-
-void HelpManagerPrivate::cleanUpDocumentation()
-{
- // mark documentation for removal for which there is no documentation file anymore
- // mark documentation for removal that is neither user registered, nor marked for registration
- const QStringList &registeredDocs = m_helpEngine->registeredDocumentations();
- for (const QString &nameSpace : registeredDocs) {
- const QString filePath = m_helpEngine->documentationFileName(nameSpace);
- if (!QFileInfo::exists(filePath)
- || (!m_filesToRegister.contains(filePath)
- && !m_userRegisteredFiles.contains(filePath))) {
- m_nameSpacesToUnregister.insert(nameSpace);
- }
- }
-}
-
-HelpManagerPrivate::~HelpManagerPrivate()
-{
- writeSettings();
- delete m_helpEngine;
- m_helpEngine = nullptr;
-}
-
-const QStringList HelpManagerPrivate::documentationFromInstaller()
-{
- QSettings *installSettings = ICore::settings();
- const QStringList documentationPaths = installSettings->value(QLatin1String("Help/InstalledDocumentation"))
- .toStringList();
- QStringList documentationFiles;
- for (const QString &path : documentationPaths) {
- QFileInfo pathInfo(path);
- if (pathInfo.isFile() && pathInfo.isReadable()) {
- documentationFiles << pathInfo.absoluteFilePath();
- } else if (pathInfo.isDir()) {
- const QFileInfoList files(QDir(path).entryInfoList(QStringList(QLatin1String("*.qch")),
- QDir::Files | QDir::Readable));
- for (const QFileInfo &fileInfo : files)
- documentationFiles << fileInfo.absoluteFilePath();
- }
- }
- return documentationFiles;
-}
-
-void HelpManagerPrivate::readSettings()
-{
- m_userRegisteredFiles = ICore::settings()->value(QLatin1String(kUserDocumentationKey))
- .toStringList().toSet();
-}
-
-void HelpManagerPrivate::writeSettings()
-{
- const QStringList list = m_userRegisteredFiles.toList();
- ICore::settings()->setValue(QLatin1String(kUserDocumentationKey), list);
-}
-
-} // Core
-
-#else // QT_HELP_LIB
-
-namespace Core {
-
-HelpManager *HelpManager::instance() { return nullptr; }
-
-QString HelpManager::collectionFilePath() { return QString(); }
-
-void HelpManager::registerDocumentation(const QStringList &) {}
-void HelpManager::registerDocumentationNow(QFutureInterface<bool> &, const QStringList &) {}
-void HelpManager::unregisterDocumentation(const QStringList &) {}
-
-void HelpManager::registerUserDocumentation(const QStringList &) {}
-QSet<QString> HelpManager::userDocumentationPaths() { return {}; }
-
-QMap<QString, QUrl> HelpManager::linksForKeyword(const QString &) { return {}; }
-QMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &) { return {}; }
-
-QUrl HelpManager::findFile(const QUrl &) { return QUrl();}
-QByteArray HelpManager::fileData(const QUrl &) { return QByteArray();}
-
-QStringList HelpManager::registeredNamespaces() { return {}; }
-QString HelpManager::namespaceFromFile(const QString &) { return QString(); }
-QString HelpManager::fileFromNamespace(const QString &) { return QString(); }
-
-void HelpManager::setCustomValue(const QString &, const QVariant &) {}
-QVariant HelpManager::customValue(const QString &, const QVariant &) { return QVariant(); }
-
-HelpManager::Filters filters() { return {}; }
-HelpManager::Filters fixedFilters() { return {}; }
-
-HelpManager::Filters userDefinedFilters() { return {}; }
-
-void HelpManager::removeUserDefinedFilter(const QString &) {}
-void HelpManager::addUserDefinedFilter(const QString &, const QStringList &) {}
-
-void HelpManager::handleHelpRequest(const QUrl &, HelpManager::HelpViewerLocation) {}
-void HelpManager::handleHelpRequest(const QString &, HelpViewerLocation) {}
-
-HelpManager::HelpManager(QObject *) {}
-HelpManager::~HelpManager() = default;
-void HelpManager::aboutToShutdown() {}
-void HelpManager::setupHelpManager() {}
-
-} // namespace Core
-
-#endif // QT_HELP_LIB
+} // HelpManager
+} // Core
diff --git a/src/plugins/coreplugin/helpmanager.h b/src/plugins/coreplugin/helpmanager.h
index f3e2db5ea3..60bb412752 100644
--- a/src/plugins/coreplugin/helpmanager.h
+++ b/src/plugins/coreplugin/helpmanager.h
@@ -28,85 +28,44 @@
#include "core_global.h"
#include <QObject>
-#include <QStringList>
-#include <QVariant>
#include <QMap>
-#include <QHash>
-#include <QFutureInterface>
-QT_FORWARD_DECLARE_CLASS(QUrl)
+QT_BEGIN_NAMESPACE
+class QStringList;
+class QUrl;
+QT_END_NAMESPACE
namespace Core {
-struct HelpManagerPrivate;
-namespace Internal {
-class CorePlugin;
-class MainWindow;
-}
+namespace HelpManager {
-class CORE_EXPORT HelpManager : public QObject
+class CORE_EXPORT Signals : public QObject
{
Q_OBJECT
public:
- enum HelpViewerLocation {
- SideBySideIfPossible = 0,
- SideBySideAlways = 1,
- HelpModeAlways = 2,
- ExternalHelpAlways = 3
- };
-
- using Filters = QHash<QString, QStringList>;
-
- static HelpManager *instance();
- static QString collectionFilePath();
-
- static void registerDocumentation(const QStringList &fileNames);
- static void unregisterDocumentation(const QStringList &nameSpaces);
-
- static void registerUserDocumentation(const QStringList &filePaths);
- static QSet<QString> userDocumentationPaths();
-
- static QUrl findFile(const QUrl &url);
- static QByteArray fileData(const QUrl &url);
-
-
- static QMap<QString, QUrl> linksForKeyword(const QString &key);
- static QMap<QString, QUrl> linksForIdentifier(const QString &id);
- static QStringList registeredNamespaces();
- static QString namespaceFromFile(const QString &file);
- static QString fileFromNamespace(const QString &nameSpace);
- static void setCustomValue(const QString &key, const QVariant &value);
- static QVariant customValue(const QString &key, const QVariant &value = QVariant());
- static Filters filters();
- static Filters fixedFilters();
- static Filters userDefinedFilters();
- static void removeUserDefinedFilter(const QString &filter);
- static void addUserDefinedFilter(const QString &filter, const QStringList &attr);
-
- static void aboutToShutdown();
-
-public slots:
- static void handleHelpRequest(const QUrl &url,
- Core::HelpManager::HelpViewerLocation location = HelpModeAlways);
- static void handleHelpRequest(const QString &url,
- Core::HelpManager::HelpViewerLocation location = HelpModeAlways);
+ static Signals *instance();
signals:
void setupFinished();
void documentationChanged();
- void collectionFileChanged();
- void helpRequested(const QUrl &url, Core::HelpManager::HelpViewerLocation location);
-
-private:
- explicit HelpManager(QObject *parent = nullptr);
- ~HelpManager() override;
+};
- static void setupHelpManager();
- static void registerDocumentationNow(QFutureInterface<bool> &futureInterface,
- const QStringList &fileNames);
- friend class Core::Internal::CorePlugin; // setupHelpManager
- friend class Core::Internal::MainWindow; // constructor/destructor
+enum HelpViewerLocation {
+ SideBySideIfPossible = 0,
+ SideBySideAlways = 1,
+ HelpModeAlways = 2,
+ ExternalHelpAlways = 3
};
-} // Core
+CORE_EXPORT void registerDocumentation(const QStringList &fileNames);
+CORE_EXPORT void unregisterDocumentation(const QStringList &nameSpaces);
+
+CORE_EXPORT QMap<QString, QUrl> linksForIdentifier(const QString &id);
+CORE_EXPORT QByteArray fileData(const QUrl &url);
+
+CORE_EXPORT void handleHelpRequest(const QUrl &url, HelpViewerLocation location = HelpModeAlways);
+CORE_EXPORT void handleHelpRequest(const QString &url, HelpViewerLocation location = HelpModeAlways);
+
+} // HelpManager
+} // Core
diff --git a/src/plugins/coreplugin/helpmanager_implementation.h b/src/plugins/coreplugin/helpmanager_implementation.h
new file mode 100644
index 0000000000..76e7a1a807
--- /dev/null
+++ b/src/plugins/coreplugin/helpmanager_implementation.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "helpmanager.h"
+
+namespace Core {
+
+namespace HelpManager {
+
+class CORE_EXPORT Implementation
+{
+protected:
+ Implementation();
+ virtual ~Implementation();
+
+public:
+ virtual void registerDocumentation(const QStringList &fileNames) = 0;
+ virtual void unregisterDocumentation(const QStringList &nameSpaces) = 0;
+ virtual QMap<QString, QUrl> linksForIdentifier(const QString &id) = 0;
+ virtual QByteArray fileData(const QUrl &url) = 0;
+ virtual void handleHelpRequest(const QUrl &url, HelpViewerLocation location = HelpModeAlways) = 0;
+};
+
+} // HelpManager
+} // Core
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 68af2e6f89..6b86a9ca22 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -31,7 +31,6 @@
#include "fancytabwidget.h"
#include "documentmanager.h"
#include "generalsettings.h"
-#include "helpmanager.h"
#include "idocumentfactory.h"
#include "messagemanager.h"
#include "modemanager.h"
@@ -110,7 +109,6 @@ MainWindow::MainWindow() :
m_progressManager(new ProgressManagerPrivate),
m_jsExpander(new JsExpander),
m_vcsManager(new VcsManager),
- m_helpManager(new HelpManager),
m_modeStack(new FancyTabWidget(this)),
m_generalSettings(new GeneralSettings),
m_systemSettings(new SystemSettings),
@@ -281,8 +279,6 @@ MainWindow::~MainWindow()
delete m_modeManager;
m_modeManager = nullptr;
- delete m_helpManager;
- m_helpManager = nullptr;
delete m_jsExpander;
m_jsExpander = nullptr;
}
diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h
index 7f49a772a4..8f9939ee8f 100644
--- a/src/plugins/coreplugin/mainwindow.h
+++ b/src/plugins/coreplugin/mainwindow.h
@@ -45,7 +45,6 @@ namespace Core {
class EditorManager;
class ExternalToolManager;
-class HelpManager;
class IDocument;
class JsExpander;
class MessageManager;
@@ -154,7 +153,6 @@ private:
JsExpander *m_jsExpander = nullptr;
VcsManager *m_vcsManager = nullptr;
ModeManager *m_modeManager = nullptr;
- HelpManager *m_helpManager = nullptr;
FancyTabWidget *m_modeStack = nullptr;
NavigationWidget *m_leftNavigationWidget = nullptr;
NavigationWidget *m_rightNavigationWidget = nullptr;
diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp
index b3e64ec2b0..4d091d6d27 100644
--- a/src/plugins/designer/formeditorw.cpp
+++ b/src/plugins/designer/formeditorw.cpp
@@ -365,8 +365,8 @@ void FormEditorData::fullInit()
m_formeditor->setIntegration(m_integration);
// Connect Qt Designer help request to HelpManager.
QObject::connect(m_integration, &QtCreatorIntegration::creatorHelpRequested,
- HelpManager::instance(),
- [](const QUrl &url) { HelpManager::instance()->handleHelpRequest(url, HelpManager::HelpModeAlways); });
+ HelpManager::Signals::instance(),
+ [](const QUrl &url) { HelpManager::handleHelpRequest(url, HelpManager::HelpModeAlways); });
/**
* This will initialize our TabOrder, Signals and slots and Buddy editors.
diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp
index 93fbdb2621..6ca884ceb2 100644
--- a/src/plugins/help/docsettingspage.cpp
+++ b/src/plugins/help/docsettingspage.cpp
@@ -25,6 +25,7 @@
#include "docsettingspage.h"
#include "helpconstants.h"
+#include "helpmanager.h"
#include <coreplugin/helpmanager.h>
#include <utils/algorithm.h>
@@ -42,8 +43,6 @@
#include <algorithm>
-using namespace Core;
-
namespace Help {
namespace Internal {
@@ -245,7 +244,7 @@ void DocSettingsPage::addDocumentation()
void DocSettingsPage::apply()
{
- HelpManager::unregisterDocumentation(m_filesToUnregister.keys());
+ Core::HelpManager::unregisterDocumentation(m_filesToUnregister.keys());
QStringList files;
auto it = m_filesToRegisterUserManaged.constBegin();
while (it != m_filesToRegisterUserManaged.constEnd()) {
diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp
index adbab36c6e..83d0d365f7 100644
--- a/src/plugins/help/filtersettingspage.cpp
+++ b/src/plugins/help/filtersettingspage.cpp
@@ -26,6 +26,7 @@
#include "filtersettingspage.h"
#include "helpconstants.h"
+#include "helpmanager.h"
#include <filternamedialog.h>
@@ -36,7 +37,6 @@
#include <QMessageBox>
using namespace Help::Internal;
-using namespace Core;
FilterSettingsPage::FilterSettingsPage()
{
@@ -61,8 +61,10 @@ QWidget *FilterSettingsPage::widget()
this, &FilterSettingsPage::addFilter);
connect(m_ui.filterRemoveButton, &QPushButton::clicked,
this, &FilterSettingsPage::removeFilter);
- connect(HelpManager::instance(), &HelpManager::documentationChanged,
- this, &FilterSettingsPage::updateFilterPage);
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &FilterSettingsPage::updateFilterPage);
}
return m_widget;
}
@@ -219,8 +221,10 @@ void FilterSettingsPage::apply()
void FilterSettingsPage::finish()
{
- disconnect(HelpManager::instance(), &HelpManager::documentationChanged,
- this, &FilterSettingsPage::updateFilterPage);
+ disconnect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &FilterSettingsPage::updateFilterPage);
delete m_widget;
}
diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro
index ffe71b6f18..a967663078 100644
--- a/src/plugins/help/help.pro
+++ b/src/plugins/help/help.pro
@@ -17,6 +17,7 @@ HEADERS += \
helpfindsupport.h \
helpindexfilter.h \
localhelpmanager.h \
+ helpmanager.h \
helpmode.h \
helpplugin.h \
helpviewer.h \
@@ -39,6 +40,7 @@ SOURCES += \
helpfindsupport.cpp \
helpindexfilter.cpp \
localhelpmanager.cpp \
+ helpmanager.cpp \
helpmode.cpp \
helpplugin.cpp \
helpviewer.cpp \
diff --git a/src/plugins/help/help.qbs b/src/plugins/help/help.qbs
index 56f5c4fbd0..38eda44aa6 100644
--- a/src/plugins/help/help.qbs
+++ b/src/plugins/help/help.qbs
@@ -36,6 +36,7 @@ QtcPlugin {
"helpconstants.h",
"helpfindsupport.cpp", "helpfindsupport.h",
"helpindexfilter.cpp", "helpindexfilter.h",
+ "helpmanager.cpp", "helpmanager.h",
"helpmode.cpp", "helpmode.h",
"helpplugin.cpp", "helpplugin.h",
"helpviewer.cpp", "helpviewer.h",
diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp
index b662c9be01..568b32a03f 100644
--- a/src/plugins/help/helpindexfilter.cpp
+++ b/src/plugins/help/helpindexfilter.cpp
@@ -27,6 +27,7 @@
#include "centralwidget.h"
#include "helpicons.h"
+#include "helpmanager.h"
#include "topicchooser.h"
#include <coreplugin/icore.h>
@@ -54,10 +55,12 @@ HelpIndexFilter::HelpIndexFilter()
setShortcutString("?");
m_icon = Utils::Icons::BOOKMARK.icon();
- connect(HelpManager::instance(), &HelpManager::setupFinished,
- this, &HelpIndexFilter::invalidateCache);
- connect(HelpManager::instance(), &HelpManager::documentationChanged,
+ connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::setupFinished,
this, &HelpIndexFilter::invalidateCache);
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &HelpIndexFilter::invalidateCache);
connect(HelpManager::instance(), &HelpManager::collectionFileChanged,
this, &HelpIndexFilter::invalidateCache);
}
diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp
new file mode 100644
index 0000000000..34be168bcb
--- /dev/null
+++ b/src/plugins/help/helpmanager.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "helpmanager.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <utils/algorithm.h>
+#include <utils/filesystemwatcher.h>
+#include <utils/qtcassert.h>
+#include <utils/runextensions.h>
+
+#include <QDateTime>
+#include <QDebug>
+#include <QDir>
+#include <QFileInfo>
+#include <QFutureWatcher>
+#include <QStringList>
+#include <QUrl>
+
+#include <QHelpEngineCore>
+
+#include <QMutexLocker>
+#include <QSqlDatabase>
+#include <QSqlDriver>
+#include <QSqlError>
+#include <QSqlQuery>
+
+using namespace Core;
+
+static const char kUserDocumentationKey[] = "Help/UserDocumentation";
+static const char kUpdateDocumentationTask[] = "UpdateDocumentationTask";
+
+namespace Help {
+namespace Internal {
+
+struct HelpManagerPrivate
+{
+ HelpManagerPrivate() = default;
+ ~HelpManagerPrivate();
+
+ const QStringList documentationFromInstaller();
+ void readSettings();
+ void writeSettings();
+ void cleanUpDocumentation();
+
+ bool m_needsSetup = true;
+ QHelpEngineCore *m_helpEngine = nullptr;
+ Utils::FileSystemWatcher *m_collectionWatcher = nullptr;
+
+ // data for delayed initialization
+ QSet<QString> m_filesToRegister;
+ QSet<QString> m_nameSpacesToUnregister;
+ QHash<QString, QVariant> m_customValues;
+
+ QSet<QString> m_userRegisteredFiles;
+
+ QMutex m_helpengineMutex;
+ QFuture<bool> m_registerFuture;
+};
+
+static HelpManager *m_instance = nullptr;
+static HelpManagerPrivate *d = nullptr;
+
+static const char linksForKeyQuery[] = "SELECT d.Title, f.Name, e.Name, "
+ "d.Name, a.Anchor FROM IndexTable a, FileNameTable d, FolderTable e, "
+ "NamespaceTable f WHERE a.FileId=d.FileId AND d.FolderId=e.Id AND "
+ "a.NamespaceId=f.Id AND a.Name='%1'";
+
+// -- DbCleaner
+
+struct DbCleaner
+{
+ DbCleaner(const QString &dbName) : name(dbName) {}
+ ~DbCleaner() { QSqlDatabase::removeDatabase(name); }
+ QString name;
+};
+
+// -- HelpManager
+
+HelpManager::HelpManager(QObject *parent) :
+ QObject(parent)
+{
+ QTC_CHECK(!m_instance);
+ m_instance = this;
+ d = new HelpManagerPrivate;
+}
+
+HelpManager::~HelpManager()
+{
+ delete d;
+ m_instance = nullptr;
+}
+
+HelpManager *HelpManager::instance()
+{
+ Q_ASSERT(m_instance);
+ return m_instance;
+}
+
+QString HelpManager::collectionFilePath()
+{
+ return QDir::cleanPath(ICore::userResourcePath()
+ + QLatin1String("/helpcollection.qhc"));
+}
+
+void HelpManager::registerDocumentation(const QStringList &files)
+{
+ if (d->m_needsSetup) {
+ for (const QString &filePath : files)
+ d->m_filesToRegister.insert(filePath);
+ return;
+ }
+
+ QFuture<bool> future = Utils::runAsync(&HelpManager::registerDocumentationNow, files);
+ Utils::onResultReady(future, this, [](bool docsChanged){
+ if (docsChanged) {
+ d->m_helpEngine->setupData();
+ emit Core::HelpManager::Signals::instance()->documentationChanged();
+ }
+ });
+ ProgressManager::addTask(future, tr("Update Documentation"),
+ kUpdateDocumentationTask);
+}
+
+void HelpManager::registerDocumentationNow(QFutureInterface<bool> &futureInterface,
+ const QStringList &files)
+{
+ QMutexLocker locker(&d->m_helpengineMutex);
+
+ futureInterface.setProgressRange(0, files.count());
+ futureInterface.setProgressValue(0);
+
+ QHelpEngineCore helpEngine(collectionFilePath());
+ helpEngine.setupData();
+ bool docsChanged = false;
+ QStringList nameSpaces = helpEngine.registeredDocumentations();
+ for (const QString &file : files) {
+ if (futureInterface.isCanceled())
+ break;
+ futureInterface.setProgressValue(futureInterface.progressValue() + 1);
+ const QString &nameSpace = helpEngine.namespaceName(file);
+ if (nameSpace.isEmpty())
+ continue;
+ if (!nameSpaces.contains(nameSpace)) {
+ if (helpEngine.registerDocumentation(file)) {
+ nameSpaces.append(nameSpace);
+ docsChanged = true;
+ } else {
+ qWarning() << "Error registering namespace '" << nameSpace
+ << "' from file '" << file << "':" << helpEngine.error();
+ }
+ } else {
+ const QLatin1String key("CreationDate");
+ const QString &newDate = helpEngine.metaData(file, key).toString();
+ const QString &oldDate = helpEngine.metaData(
+ helpEngine.documentationFileName(nameSpace), key).toString();
+ if (QDateTime::fromString(newDate, Qt::ISODate)
+ > QDateTime::fromString(oldDate, Qt::ISODate)) {
+ if (helpEngine.unregisterDocumentation(nameSpace)) {
+ docsChanged = true;
+ helpEngine.registerDocumentation(file);
+ }
+ }
+ }
+ }
+ futureInterface.reportResult(docsChanged);
+}
+
+void HelpManager::unregisterDocumentation(const QStringList &nameSpaces)
+{
+ if (d->m_needsSetup) {
+ for (const QString &name : nameSpaces)
+ d->m_nameSpacesToUnregister.insert(name);
+ return;
+ }
+
+ QMutexLocker locker(&d->m_helpengineMutex);
+ bool docsChanged = false;
+ for (const QString &nameSpace : nameSpaces) {
+ const QString filePath = d->m_helpEngine->documentationFileName(nameSpace);
+ if (d->m_helpEngine->unregisterDocumentation(nameSpace)) {
+ docsChanged = true;
+ d->m_userRegisteredFiles.remove(filePath);
+ } else {
+ qWarning() << "Error unregistering namespace '" << nameSpace
+ << "' from file '" << filePath
+ << "': " << d->m_helpEngine->error();
+ }
+ }
+ locker.unlock();
+ if (docsChanged)
+ emit Core::HelpManager::Signals::instance()->documentationChanged();
+}
+
+void HelpManager::registerUserDocumentation(const QStringList &filePaths)
+{
+ for (const QString &filePath : filePaths)
+ d->m_userRegisteredFiles.insert(filePath);
+ m_instance->registerDocumentation(filePaths);
+}
+
+QSet<QString> HelpManager::userDocumentationPaths()
+{
+ return d->m_userRegisteredFiles;
+}
+
+static QUrl buildQUrl(const QString &ns, const QString &folder,
+ const QString &relFileName, const QString &anchor)
+{
+ QUrl url;
+ url.setScheme(QLatin1String("qthelp"));
+ url.setAuthority(ns);
+ url.setPath(QLatin1Char('/') + folder + QLatin1Char('/') + relFileName);
+ url.setFragment(anchor);
+ return url;
+}
+
+// This should go into Qt 4.8 once we start using it for Qt Creator
+QMap<QString, QUrl> HelpManager::linksForKeyword(const QString &key)
+{
+ QMap<QString, QUrl> links;
+ QTC_ASSERT(!d->m_needsSetup, return links);
+
+ const QLatin1String sqlite("QSQLITE");
+ const QLatin1String name("HelpManager::linksForKeyword");
+
+ DbCleaner cleaner(name);
+ QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
+ if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
+ const QStringList &registeredDocs = d->m_helpEngine->registeredDocumentations();
+ for (const QString &nameSpace : registeredDocs) {
+ db.setDatabaseName(d->m_helpEngine->documentationFileName(nameSpace));
+ if (db.open()) {
+ QSqlQuery query = QSqlQuery(db);
+ query.setForwardOnly(true);
+ query.exec(QString::fromLatin1(linksForKeyQuery).arg(key));
+ while (query.next()) {
+ QString title = query.value(0).toString();
+ if (title.isEmpty()) // generate a title + corresponding path
+ title = key + QLatin1String(" : ") + query.value(3).toString();
+ links.insertMulti(title, buildQUrl(query.value(1).toString(),
+ query.value(2).toString(), query.value(3).toString(),
+ query.value(4).toString()));
+ }
+ }
+ }
+ }
+ return links;
+}
+
+QMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &id)
+{
+ QMap<QString, QUrl> empty;
+ QTC_ASSERT(!d->m_needsSetup, return empty);
+ return d->m_helpEngine->linksForIdentifier(id);
+}
+
+QUrl HelpManager::findFile(const QUrl &url)
+{
+ QTC_ASSERT(!d->m_needsSetup, return QUrl());
+ return d->m_helpEngine->findFile(url);
+}
+
+QByteArray HelpManager::fileData(const QUrl &url)
+{
+ QTC_ASSERT(!d->m_needsSetup, return QByteArray());
+ return d->m_helpEngine->fileData(url);
+}
+
+void HelpManager::handleHelpRequest(const QUrl &url, Core::HelpManager::HelpViewerLocation location)
+{
+ emit m_instance->helpRequested(url, location);
+}
+
+QStringList HelpManager::registeredNamespaces()
+{
+ QTC_ASSERT(!d->m_needsSetup, return QStringList());
+ return d->m_helpEngine->registeredDocumentations();
+}
+
+QString HelpManager::namespaceFromFile(const QString &file)
+{
+ QTC_ASSERT(!d->m_needsSetup, return QString());
+ return d->m_helpEngine->namespaceName(file);
+}
+
+QString HelpManager::fileFromNamespace(const QString &nameSpace)
+{
+ QTC_ASSERT(!d->m_needsSetup, return QString());
+ return d->m_helpEngine->documentationFileName(nameSpace);
+}
+
+void HelpManager::setCustomValue(const QString &key, const QVariant &value)
+{
+ if (d->m_needsSetup) {
+ d->m_customValues.insert(key, value);
+ return;
+ }
+ if (d->m_helpEngine->setCustomValue(key, value))
+ emit m_instance->collectionFileChanged();
+}
+
+QVariant HelpManager::customValue(const QString &key, const QVariant &value)
+{
+ QTC_ASSERT(!d->m_needsSetup, return QVariant());
+ return d->m_helpEngine->customValue(key, value);
+}
+
+HelpManager::Filters HelpManager::filters()
+{
+ QTC_ASSERT(!d->m_needsSetup, return Filters());
+
+ Filters filters;
+ const QStringList &customFilters = d->m_helpEngine->customFilters();
+ for (const QString &filter : customFilters)
+ filters.insert(filter, d->m_helpEngine->filterAttributes(filter));
+ return filters;
+}
+
+HelpManager::Filters HelpManager::fixedFilters()
+{
+ Filters fixedFilters;
+ QTC_ASSERT(!d->m_needsSetup, return fixedFilters);
+
+ const QLatin1String sqlite("QSQLITE");
+ const QLatin1String name("HelpManager::fixedCustomFilters");
+
+ DbCleaner cleaner(name);
+ QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
+ if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
+ const QStringList &registeredDocs = d->m_helpEngine->registeredDocumentations();
+ for (const QString &nameSpace : registeredDocs) {
+ db.setDatabaseName(d->m_helpEngine->documentationFileName(nameSpace));
+ if (db.open()) {
+ QSqlQuery query = QSqlQuery(db);
+ query.setForwardOnly(true);
+ query.exec(QLatin1String("SELECT Name FROM FilterNameTable"));
+ while (query.next()) {
+ const QString &filter = query.value(0).toString();
+ fixedFilters.insert(filter, d->m_helpEngine->filterAttributes(filter));
+ }
+ }
+ }
+ }
+ return fixedFilters;
+}
+
+HelpManager::Filters HelpManager::userDefinedFilters()
+{
+ QTC_ASSERT(!d->m_needsSetup, return Filters());
+
+ Filters all = filters();
+ const Filters &fixed = fixedFilters();
+ for (Filters::const_iterator it = fixed.constBegin(); it != fixed.constEnd(); ++it)
+ all.remove(it.key());
+ return all;
+}
+
+void HelpManager::removeUserDefinedFilter(const QString &filter)
+{
+ QTC_ASSERT(!d->m_needsSetup, return);
+
+ if (d->m_helpEngine->removeCustomFilter(filter))
+ emit m_instance->collectionFileChanged();
+}
+
+void HelpManager::addUserDefinedFilter(const QString &filter, const QStringList &attr)
+{
+ QTC_ASSERT(!d->m_needsSetup, return);
+
+ if (d->m_helpEngine->addCustomFilter(filter, attr))
+ emit m_instance->collectionFileChanged();
+}
+
+void HelpManager::aboutToShutdown()
+{
+ if (d && d->m_registerFuture.isRunning()) {
+ d->m_registerFuture.cancel();
+ d->m_registerFuture.waitForFinished();
+ }
+}
+
+// -- private
+
+void HelpManager::setupHelpManager()
+{
+ if (!d->m_needsSetup)
+ return;
+ d->m_needsSetup = false;
+
+ d->readSettings();
+
+ // create the help engine
+ d->m_helpEngine = new QHelpEngineCore(collectionFilePath(), m_instance);
+ d->m_helpEngine->setupData();
+
+ for (const QString &filePath : d->documentationFromInstaller())
+ d->m_filesToRegister.insert(filePath);
+
+ d->cleanUpDocumentation();
+
+ if (!d->m_nameSpacesToUnregister.isEmpty()) {
+ m_instance->unregisterDocumentation(d->m_nameSpacesToUnregister.toList());
+ d->m_nameSpacesToUnregister.clear();
+ }
+
+ if (!d->m_filesToRegister.isEmpty()) {
+ m_instance->registerDocumentation(d->m_filesToRegister.toList());
+ d->m_filesToRegister.clear();
+ }
+
+ QHash<QString, QVariant>::const_iterator it;
+ for (it = d->m_customValues.constBegin(); it != d->m_customValues.constEnd(); ++it)
+ setCustomValue(it.key(), it.value());
+
+ emit Core::HelpManager::Signals::instance()->setupFinished();
+}
+
+void HelpManagerPrivate::cleanUpDocumentation()
+{
+ // mark documentation for removal for which there is no documentation file anymore
+ // mark documentation for removal that is neither user registered, nor marked for registration
+ const QStringList &registeredDocs = m_helpEngine->registeredDocumentations();
+ for (const QString &nameSpace : registeredDocs) {
+ const QString filePath = m_helpEngine->documentationFileName(nameSpace);
+ if (!QFileInfo::exists(filePath)
+ || (!m_filesToRegister.contains(filePath)
+ && !m_userRegisteredFiles.contains(filePath))) {
+ m_nameSpacesToUnregister.insert(nameSpace);
+ }
+ }
+}
+
+HelpManagerPrivate::~HelpManagerPrivate()
+{
+ writeSettings();
+ delete m_helpEngine;
+ m_helpEngine = nullptr;
+}
+
+const QStringList HelpManagerPrivate::documentationFromInstaller()
+{
+ QSettings *installSettings = ICore::settings();
+ const QStringList documentationPaths = installSettings->value(QLatin1String("Help/InstalledDocumentation"))
+ .toStringList();
+ QStringList documentationFiles;
+ for (const QString &path : documentationPaths) {
+ QFileInfo pathInfo(path);
+ if (pathInfo.isFile() && pathInfo.isReadable()) {
+ documentationFiles << pathInfo.absoluteFilePath();
+ } else if (pathInfo.isDir()) {
+ const QFileInfoList files(QDir(path).entryInfoList(QStringList(QLatin1String("*.qch")),
+ QDir::Files | QDir::Readable));
+ for (const QFileInfo &fileInfo : files)
+ documentationFiles << fileInfo.absoluteFilePath();
+ }
+ }
+ return documentationFiles;
+}
+
+void HelpManagerPrivate::readSettings()
+{
+ m_userRegisteredFiles = ICore::settings()->value(QLatin1String(kUserDocumentationKey))
+ .toStringList().toSet();
+}
+
+void HelpManagerPrivate::writeSettings()
+{
+ const QStringList list = m_userRegisteredFiles.toList();
+ ICore::settings()->setValue(QLatin1String(kUserDocumentationKey), list);
+}
+
+} // Internal
+} // Core
diff --git a/src/plugins/help/helpmanager.h b/src/plugins/help/helpmanager.h
new file mode 100644
index 0000000000..97b0b4e427
--- /dev/null
+++ b/src/plugins/help/helpmanager.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/helpmanager_implementation.h>
+
+QT_FORWARD_DECLARE_CLASS(QUrl)
+
+#include <QFutureInterface>
+#include <QVariant>
+
+namespace Help {
+namespace Internal {
+
+class HelpManager : public QObject, public Core::HelpManager::Implementation
+{
+ Q_OBJECT
+
+public:
+ using Filters = QHash<QString, QStringList>;
+
+ explicit HelpManager(QObject *parent = nullptr);
+ ~HelpManager() override;
+
+ static HelpManager *instance();
+ static QString collectionFilePath();
+
+ void registerDocumentation(const QStringList &fileNames) override;
+ void unregisterDocumentation(const QStringList &nameSpaces) override;
+
+ static void registerUserDocumentation(const QStringList &filePaths);
+ static QSet<QString> userDocumentationPaths();
+
+ static QMap<QString, QUrl> linksForKeyword(const QString &key);
+ QMap<QString, QUrl> linksForIdentifier(const QString &id) override;
+
+ static QUrl findFile(const QUrl &url);
+ QByteArray fileData(const QUrl &url) override;
+
+ static QStringList registeredNamespaces();
+ static QString namespaceFromFile(const QString &file);
+ static QString fileFromNamespace(const QString &nameSpace);
+
+ static void setCustomValue(const QString &key, const QVariant &value);
+ static QVariant customValue(const QString &key, const QVariant &value = QVariant());
+
+ static Filters filters();
+ static Filters fixedFilters();
+
+ static Filters userDefinedFilters();
+ static void removeUserDefinedFilter(const QString &filter);
+ static void addUserDefinedFilter(const QString &filter, const QStringList &attr);
+
+ static void aboutToShutdown();
+
+ void handleHelpRequest(
+ const QUrl &url,
+ Core::HelpManager::HelpViewerLocation location = Core::HelpManager::HelpModeAlways) override;
+
+
+ static void setupHelpManager();
+ static void registerDocumentationNow(QFutureInterface<bool> &futureInterface,
+ const QStringList &fileNames);
+signals:
+ void collectionFileChanged();
+ void helpRequested(const QUrl &url, Core::HelpManager::HelpViewerLocation location);
+};
+
+} // Internal
+} // Core
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index 405d05bebc..2ce03e0789 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -33,6 +33,7 @@
#include "helpconstants.h"
#include "helpfindsupport.h"
#include "helpindexfilter.h"
+#include "helpmanager.h"
#include "helpmode.h"
#include "helpviewer.h"
#include "localhelpmanager.h"
@@ -145,7 +146,7 @@ public:
HelpViewer *externalHelpViewer();
HelpViewer *helpModeHelpViewer();
HelpWidget *helpWidgetForWindow(QWidget *window);
- HelpViewer *viewerForHelpViewerLocation(HelpManager::HelpViewerLocation location);
+ HelpViewer *viewerForHelpViewerLocation(Core::HelpManager::HelpViewerLocation location);
void showInHelpViewer(const QUrl &url, HelpViewer *viewer);
void doSetupIfNeeded();
@@ -160,7 +161,7 @@ public:
GeneralSettingsPage m_generalSettingsPage;
bool m_setupNeeded = true;
- LocalHelpManager m_helpManager;
+ LocalHelpManager m_localHelpManager;
OpenPagesManager m_openPagesManager;
QString m_contextHelpHighlightId;
@@ -173,11 +174,19 @@ public:
};
static HelpPluginPrivate *dd = nullptr;
+static HelpManager *m_helpManager = nullptr;
+
+HelpPlugin::HelpPlugin()
+{
+ m_helpManager = new HelpManager;
+}
HelpPlugin::~HelpPlugin()
{
delete dd;
dd = nullptr;
+ delete m_helpManager;
+ m_helpManager = nullptr;
}
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
@@ -221,8 +230,10 @@ HelpPluginPrivate::HelpPluginPrivate()
connect(&m_filterSettingsPage, &FilterSettingsPage::filtersChanged,
this, &HelpPluginPrivate::setupHelpEngineIfNeeded);
- connect(HelpManager::instance(), &HelpManager::documentationChanged,
- this, &HelpPluginPrivate::setupHelpEngineIfNeeded);
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &HelpPluginPrivate::setupHelpEngineIfNeeded);
connect(HelpManager::instance(), &HelpManager::collectionFileChanged,
this, &HelpPluginPrivate::setupHelpEngineIfNeeded);
@@ -319,7 +330,13 @@ void HelpPlugin::extensionsInitialized()
QStringList filesToRegister;
// we might need to register creators inbuild help
filesToRegister.append(ICore::documentationPath() + "/qtcreator.qch");
- HelpManager::registerDocumentation(filesToRegister);
+ Core::HelpManager::registerDocumentation(filesToRegister);
+}
+
+bool HelpPlugin::delayedInitialize()
+{
+ HelpManager::setupHelpManager();
+ return true;
}
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
@@ -524,7 +541,7 @@ void HelpPluginPrivate::setupHelpEngineIfNeeded()
{
LocalHelpManager::setEngineNeedsUpdate();
if (ModeManager::currentModeId() == m_mode.id()
- || LocalHelpManager::contextHelpOption() == HelpManager::ExternalHelpAlways)
+ || LocalHelpManager::contextHelpOption() == Core::HelpManager::ExternalHelpAlways)
LocalHelpManager::setupGuiHelpEngine();
}
@@ -564,29 +581,30 @@ HelpWidget *HelpPluginPrivate::helpWidgetForWindow(QWidget *window)
return m_centralWidget;
}
-HelpViewer *HelpPlugin::viewerForHelpViewerLocation(HelpManager::HelpViewerLocation location)
+HelpViewer *HelpPlugin::viewerForHelpViewerLocation(Core::HelpManager::HelpViewerLocation location)
{
return dd->viewerForHelpViewerLocation(location);
}
-HelpViewer *HelpPluginPrivate::viewerForHelpViewerLocation(HelpManager::HelpViewerLocation location)
+HelpViewer *HelpPluginPrivate::viewerForHelpViewerLocation(
+ Core::HelpManager::HelpViewerLocation location)
{
- HelpManager::HelpViewerLocation actualLocation = location;
- if (location == HelpManager::SideBySideIfPossible)
- actualLocation = canShowHelpSideBySide() ? HelpManager::SideBySideAlways
- : HelpManager::HelpModeAlways;
+ Core::HelpManager::HelpViewerLocation actualLocation = location;
+ if (location == Core::HelpManager::SideBySideIfPossible)
+ actualLocation = canShowHelpSideBySide() ? Core::HelpManager::SideBySideAlways
+ : Core::HelpManager::HelpModeAlways;
- if (actualLocation == HelpManager::ExternalHelpAlways)
+ if (actualLocation == Core::HelpManager::ExternalHelpAlways)
return externalHelpViewer();
- if (actualLocation == HelpManager::SideBySideAlways) {
+ if (actualLocation == Core::HelpManager::SideBySideAlways) {
createRightPaneContextViewer();
RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget);
RightPaneWidget::instance()->setShown(true);
return m_rightPaneSideBarWidget->currentViewer();
}
- QTC_CHECK(actualLocation == HelpManager::HelpModeAlways);
+ QTC_CHECK(actualLocation == Core::HelpManager::HelpModeAlways);
return helpModeHelpViewer();
}
@@ -658,7 +676,7 @@ void HelpPluginPrivate::showContextHelp(const QString &contextHelpId)
HelpViewer *viewer = viewerForContextHelp();
QTC_ASSERT(viewer, return);
- QMap<QString, QUrl> links = HelpManager::linksForIdentifier(contextHelpId);
+ QMap<QString, QUrl> links = Core::HelpManager::linksForIdentifier(contextHelpId);
// Maybe the id is already an URL
if (links.isEmpty() && LocalHelpManager::isValidUrl(contextHelpId))
links.insert(contextHelpId, contextHelpId);
@@ -702,7 +720,8 @@ void HelpPluginPrivate::highlightSearchTermsInContextHelp()
m_contextHelpHighlightId.clear();
}
-void HelpPluginPrivate::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocation location)
+void HelpPluginPrivate::handleHelpRequest(const QUrl &url,
+ Core::HelpManager::HelpViewerLocation location)
{
static const QString qtcreatorUnversionedID = "org.qt-project.qtcreator";
if (url.host() == qtcreatorUnversionedID) {
diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h
index 902bc2b86a..0335891498 100644
--- a/src/plugins/help/helpplugin.h
+++ b/src/plugins/help/helpplugin.h
@@ -43,7 +43,7 @@ class HelpPlugin : public ExtensionSystem::IPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Help.json")
public:
- HelpPlugin() = default;
+ HelpPlugin();
~HelpPlugin() final;
static HelpViewer *viewerForHelpViewerLocation(Core::HelpManager::HelpViewerLocation location);
@@ -53,6 +53,7 @@ public:
private:
bool initialize(const QStringList &arguments, QString *errorMessage) final;
void extensionsInitialized() final;
+ bool delayedInitialize() final;
ShutdownFlag aboutToShutdown() final;
};
diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp
index ed17596399..731d938873 100644
--- a/src/plugins/help/localhelpmanager.cpp
+++ b/src/plugins/help/localhelpmanager.cpp
@@ -27,6 +27,7 @@
#include "bookmarkmanager.h"
#include "helpconstants.h"
+#include "helpmanager.h"
#include "helpviewer.h"
#include <app/app_version.h>
@@ -266,7 +267,7 @@ void LocalHelpManager::setupGuiHelpEngine()
{
if (m_needsCollectionFile) {
m_needsCollectionFile = false;
- helpEngine().setCollectionFile(Core::HelpManager::collectionFilePath());
+ helpEngine().setCollectionFile(HelpManager::collectionFilePath());
m_guiNeedsSetup = true;
}
diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp
index 0dc0f6f209..b6294f32fb 100644
--- a/src/plugins/qtsupport/exampleslistmodel.cpp
+++ b/src/plugins/qtsupport/exampleslistmodel.cpp
@@ -115,10 +115,10 @@ ExampleSetModel::ExampleSetModel()
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsLoaded,
this, &ExampleSetModel::qtVersionManagerLoaded);
- if (auto helpManager = Core::HelpManager::instance()) {
- connect(helpManager, &Core::HelpManager::setupFinished,
- this, &ExampleSetModel::helpManagerInitialized);
- }
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::setupFinished,
+ this,
+ &ExampleSetModel::helpManagerInitialized);
}
void ExampleSetModel::recreateModel(const QList<BaseQtVersion *> &qtVersions)
@@ -236,8 +236,10 @@ ExamplesListModel::ExamplesListModel(QObject *parent)
{
connect(&m_exampleSetModel, &ExampleSetModel::selectedExampleSetChanged,
this, &ExamplesListModel::updateExamples);
- connect(Core::HelpManager::instance(), &Core::HelpManager::documentationChanged,
- this, &ExamplesListModel::updateExamples);
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &ExamplesListModel::updateExamples);
}
static QString fixStringForTags(const QString &string)
@@ -682,7 +684,7 @@ void ExampleSetModel::tryToInitialize()
return;
if (!m_qtVersionManagerInitialized)
return;
- if (Core::HelpManager::instance() && !m_helpManagerInitialized)
+ if (!m_helpManagerInitialized)
return;
m_initalized = true;