summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;