forked from qt-creator/qt-creator
The tool tip never has focus, so it cannot become the IContext that is checked for context help. So, integrate the help id into Utils::ToolTip and check the tool tip first when checking for context help. As a side effect the [F1] button and help id for the tool tip is now also available for use outside of the text editors. Task-number: QTCREATORBUG-5345 Change-Id: Id975703caf161d1183c247e8ad8bb693b90fd306 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com> Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
682 lines
25 KiB
C++
682 lines
25 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
|
** use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "helpplugin.h"
|
|
|
|
#include "bookmarkmanager.h"
|
|
#include "centralwidget.h"
|
|
#include "docsettingspage.h"
|
|
#include "filtersettingspage.h"
|
|
#include "generalsettingspage.h"
|
|
#include "helpconstants.h"
|
|
#include "helpfindsupport.h"
|
|
#include "helpindexfilter.h"
|
|
#include "helpmode.h"
|
|
#include "helpviewer.h"
|
|
#include "localhelpmanager.h"
|
|
#include "openpagesmanager.h"
|
|
#include "openpagesmodel.h"
|
|
#include "qtwebkithelpviewer.h"
|
|
#include "remotehelpfilter.h"
|
|
#include "searchwidget.h"
|
|
#include "searchtaskhandler.h"
|
|
#include "textbrowserhelpviewer.h"
|
|
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER
|
|
#include "macwebkithelpviewer.h"
|
|
#endif
|
|
|
|
#include <bookmarkmanager.h>
|
|
#include <contentwindow.h>
|
|
#include <indexwindow.h>
|
|
|
|
#include <app/app_version.h>
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
|
#include <coreplugin/actionmanager/command.h>
|
|
#include <coreplugin/id.h>
|
|
#include <coreplugin/coreconstants.h>
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
#include <coreplugin/findplaceholder.h>
|
|
#include <coreplugin/icore.h>
|
|
#include <coreplugin/minisplitter.h>
|
|
#include <coreplugin/modemanager.h>
|
|
#include <coreplugin/rightpane.h>
|
|
#include <coreplugin/sidebar.h>
|
|
#include <extensionsystem/pluginmanager.h>
|
|
#include <coreplugin/find/findplugin.h>
|
|
#include <texteditor/texteditorconstants.h>
|
|
#include <utils/hostosinfo.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/styledbar.h>
|
|
#include <utils/theme/theme.h>
|
|
#include <utils/tooltip/tooltip.h>
|
|
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QLibraryInfo>
|
|
#include <QTimer>
|
|
#include <QTranslator>
|
|
#include <qplugin.h>
|
|
#include <QRegExp>
|
|
|
|
#include <QAction>
|
|
#include <QComboBox>
|
|
#include <QDesktopServices>
|
|
#include <QMenu>
|
|
#include <QStackedLayout>
|
|
#include <QSplitter>
|
|
|
|
#include <QHelpEngine>
|
|
|
|
#include <functional>
|
|
|
|
using namespace Help::Internal;
|
|
|
|
static const char kExternalWindowStateKey[] = "Help/ExternalWindowState";
|
|
static const char kToolTipHelpContext[] = "Help.ToolTip";
|
|
|
|
using namespace Core;
|
|
using namespace Utils;
|
|
|
|
HelpPlugin::HelpPlugin()
|
|
: m_mode(0),
|
|
m_centralWidget(0),
|
|
m_rightPaneSideBarWidget(0),
|
|
m_setupNeeded(true),
|
|
m_helpManager(0),
|
|
m_openPagesManager(0)
|
|
{
|
|
}
|
|
|
|
HelpPlugin::~HelpPlugin()
|
|
{
|
|
delete m_openPagesManager;
|
|
delete m_helpManager;
|
|
}
|
|
|
|
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
|
|
{
|
|
Q_UNUSED(arguments)
|
|
Q_UNUSED(error)
|
|
Context modecontext(Constants::C_MODE_HELP);
|
|
|
|
const QString &locale = ICore::userInterfaceLanguage();
|
|
if (!locale.isEmpty()) {
|
|
QTranslator *qtr = new QTranslator(this);
|
|
QTranslator *qhelptr = new QTranslator(this);
|
|
const QString &creatorTrPath = ICore::resourcePath()
|
|
+ QLatin1String("/translations");
|
|
const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
|
|
const QString &trFile = QLatin1String("assistant_") + locale;
|
|
const QString &helpTrFile = QLatin1String("qt_help_") + locale;
|
|
if (qtr->load(trFile, qtTrPath) || qtr->load(trFile, creatorTrPath))
|
|
qApp->installTranslator(qtr);
|
|
if (qhelptr->load(helpTrFile, qtTrPath) || qhelptr->load(helpTrFile, creatorTrPath))
|
|
qApp->installTranslator(qhelptr);
|
|
}
|
|
|
|
m_helpManager = new LocalHelpManager(this);
|
|
m_openPagesManager = new OpenPagesManager(this);
|
|
addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
|
|
addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
|
|
addAutoReleasedObject(new GeneralSettingsPage());
|
|
addAutoReleasedObject(m_searchTaskHandler = new SearchTaskHandler);
|
|
|
|
m_centralWidget = new CentralWidget(modecontext);
|
|
connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
|
|
SLOT(updateSideBarSource(QUrl)));
|
|
connect(m_centralWidget, &CentralWidget::closeButtonClicked,
|
|
&OpenPagesManager::instance(), &OpenPagesManager::closeCurrentPage);
|
|
|
|
connect(LocalHelpManager::instance(), &LocalHelpManager::returnOnCloseChanged,
|
|
m_centralWidget, &CentralWidget::updateCloseButton);
|
|
connect(HelpManager::instance(), SIGNAL(helpRequested(QUrl,Core::HelpManager::HelpViewerLocation)),
|
|
this, SLOT(handleHelpRequest(QUrl,Core::HelpManager::HelpViewerLocation)));
|
|
connect(m_searchTaskHandler, SIGNAL(search(QUrl)), this,
|
|
SLOT(showLinkInHelpMode(QUrl)));
|
|
|
|
connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
|
|
SLOT(setupHelpEngineIfNeeded()));
|
|
connect(HelpManager::instance(), SIGNAL(documentationChanged()), this,
|
|
SLOT(setupHelpEngineIfNeeded()));
|
|
connect(HelpManager::instance(), SIGNAL(collectionFileChanged()), this,
|
|
SLOT(setupHelpEngineIfNeeded()));
|
|
|
|
connect(ToolTip::instance(), &ToolTip::shown, ICore::instance(), []() {
|
|
ICore::addAdditionalContext(Context(kToolTipHelpContext), ICore::ContextPriority::High);
|
|
});
|
|
connect(ToolTip::instance(), &ToolTip::hidden,ICore::instance(), []() {
|
|
ICore::removeAdditionalContext(Context(kToolTipHelpContext));
|
|
});
|
|
|
|
Command *cmd;
|
|
QAction *action;
|
|
|
|
// Add Contents, Index, and Context menu items
|
|
action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")),
|
|
tr(Constants::SB_CONTENTS), this);
|
|
cmd = ActionManager::registerAction(action, "Help.ContentsMenu");
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
|
|
connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));
|
|
|
|
action = new QAction(tr(Constants::SB_INDEX), this);
|
|
cmd = ActionManager::registerAction(action, "Help.IndexMenu");
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
|
|
connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));
|
|
|
|
action = new QAction(tr("Context Help"), this);
|
|
cmd = ActionManager::registerAction(action, Help::Constants::CONTEXT_HELP,
|
|
Context(kToolTipHelpContext, Core::Constants::C_GLOBAL));
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
|
|
cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
|
|
connect(action, SIGNAL(triggered()), this, SLOT(showContextHelp()));
|
|
|
|
action = new QAction(tr("Technical Support"), this);
|
|
cmd = ActionManager::registerAction(action, "Help.TechSupport");
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
|
|
connect(action, SIGNAL(triggered()), this, SLOT(slotOpenSupportPage()));
|
|
|
|
action = new QAction(tr("Report Bug..."), this);
|
|
cmd = ActionManager::registerAction(action, "Help.ReportBug");
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
|
|
connect(action, SIGNAL(triggered()), this, SLOT(slotReportBug()));
|
|
|
|
if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) {
|
|
// reuse EditorManager constants to avoid a second pair of menu actions
|
|
// Goto Previous In History Action
|
|
action = new QAction(this);
|
|
Command *ctrlTab = ActionManager::registerAction(action, Core::Constants::GOTOPREVINHISTORY,
|
|
modecontext);
|
|
windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE);
|
|
connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
|
|
SLOT(gotoPreviousPage()));
|
|
|
|
// Goto Next In History Action
|
|
action = new QAction(this);
|
|
Command *ctrlShiftTab = ActionManager::registerAction(action, Core::Constants::GOTONEXTINHISTORY,
|
|
modecontext);
|
|
windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE);
|
|
connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
|
|
SLOT(gotoNextPage()));
|
|
}
|
|
|
|
auto helpIndexFilter = new HelpIndexFilter();
|
|
addAutoReleasedObject(helpIndexFilter);
|
|
connect(helpIndexFilter, &HelpIndexFilter::linkActivated,
|
|
this, &HelpPlugin::showLinkInHelpMode);
|
|
connect(helpIndexFilter, &HelpIndexFilter::linksActivated,
|
|
this, &HelpPlugin::showLinksInHelpMode);
|
|
|
|
RemoteHelpFilter *remoteHelpFilter = new RemoteHelpFilter();
|
|
addAutoReleasedObject(remoteHelpFilter);
|
|
connect(remoteHelpFilter, SIGNAL(linkActivated(QUrl)), this,
|
|
SLOT(showLinkInHelpMode(QUrl)));
|
|
|
|
QDesktopServices::setUrlHandler(QLatin1String("qthelp"), HelpManager::instance(), "handleHelpRequest");
|
|
connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*,Core::IMode*)),
|
|
this, SLOT(modeChanged(Core::IMode*,Core::IMode*)));
|
|
|
|
m_mode = new HelpMode;
|
|
m_mode->setWidget(m_centralWidget);
|
|
addAutoReleasedObject(m_mode);
|
|
|
|
return true;
|
|
}
|
|
|
|
void HelpPlugin::extensionsInitialized()
|
|
{
|
|
QStringList filesToRegister;
|
|
// we might need to register creators inbuild help
|
|
filesToRegister.append(ICore::documentationPath() + QLatin1String("/qtcreator.qch"));
|
|
HelpManager::registerDocumentation(filesToRegister);
|
|
}
|
|
|
|
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
|
|
{
|
|
if (m_externalWindow)
|
|
delete m_externalWindow.data();
|
|
if (m_centralWidget)
|
|
delete m_centralWidget;
|
|
if (m_rightPaneSideBarWidget)
|
|
delete m_rightPaneSideBarWidget;
|
|
return SynchronousShutdown;
|
|
}
|
|
|
|
void HelpPlugin::resetFilter()
|
|
{
|
|
const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
|
|
.arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
|
|
QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*"));
|
|
|
|
QHelpEngineCore *engine = &LocalHelpManager::helpEngine();
|
|
const QStringList &filters = engine->customFilters();
|
|
foreach (const QString &filter, filters) {
|
|
if (filterRegExp.exactMatch(filter) && filter != filterInternal)
|
|
engine->removeCustomFilter(filter);
|
|
}
|
|
|
|
// we added a filter at some point, remove previously added filter
|
|
if (engine->customValue(Help::Constants::WeAddedFilterKey).toInt() == 1) {
|
|
const QString &filter =
|
|
engine->customValue(Help::Constants::PreviousFilterNameKey).toString();
|
|
if (!filter.isEmpty())
|
|
engine->removeCustomFilter(filter);
|
|
}
|
|
|
|
// potentially remove a filter with new name
|
|
const QString filterName = tr("Unfiltered");
|
|
engine->removeCustomFilter(filterName);
|
|
engine->addCustomFilter(filterName, QStringList());
|
|
engine->setCustomValue(Help::Constants::WeAddedFilterKey, 1);
|
|
engine->setCustomValue(Help::Constants::PreviousFilterNameKey, filterName);
|
|
engine->setCurrentFilter(filterName);
|
|
|
|
LocalHelpManager::updateFilterModel();
|
|
connect(engine, &QHelpEngineCore::setupFinished,
|
|
LocalHelpManager::instance(), &LocalHelpManager::updateFilterModel);
|
|
}
|
|
|
|
void HelpPlugin::saveExternalWindowSettings()
|
|
{
|
|
if (!m_externalWindow)
|
|
return;
|
|
m_externalWindowState = m_externalWindow->geometry();
|
|
QSettings *settings = ICore::settings();
|
|
settings->setValue(QLatin1String(kExternalWindowStateKey),
|
|
qVariantFromValue(m_externalWindowState));
|
|
}
|
|
|
|
HelpWidget *HelpPlugin::createHelpWidget(const Context &context, HelpWidget::WidgetStyle style)
|
|
{
|
|
HelpWidget *widget = new HelpWidget(context, style);
|
|
|
|
connect(widget->currentViewer(), SIGNAL(loadFinished()),
|
|
this, SLOT(highlightSearchTermsInContextHelp()));
|
|
connect(widget, SIGNAL(openHelpMode(QUrl)),
|
|
this, SLOT(showLinkInHelpMode(QUrl)));
|
|
connect(widget, SIGNAL(closeButtonClicked()),
|
|
this, SLOT(slotHideRightPane()));
|
|
connect(widget, SIGNAL(aboutToClose()),
|
|
this, SLOT(saveExternalWindowSettings()));
|
|
|
|
// force setup, as we might have never switched to full help mode
|
|
// thus the help engine might still run without collection file setup
|
|
LocalHelpManager::setupGuiHelpEngine();
|
|
|
|
return widget;
|
|
}
|
|
|
|
void HelpPlugin::createRightPaneContextViewer()
|
|
{
|
|
if (m_rightPaneSideBarWidget)
|
|
return;
|
|
m_rightPaneSideBarWidget = createHelpWidget(Context(Constants::C_HELP_SIDEBAR),
|
|
HelpWidget::SideBarWidget);
|
|
}
|
|
|
|
HelpViewer *HelpPlugin::externalHelpViewer()
|
|
{
|
|
if (m_externalWindow)
|
|
return m_externalWindow->currentViewer();
|
|
doSetupIfNeeded();
|
|
m_externalWindow = createHelpWidget(Context(Constants::C_HELP_EXTERNAL),
|
|
HelpWidget::ExternalWindow);
|
|
if (m_externalWindowState.isNull()) {
|
|
QSettings *settings = ICore::settings();
|
|
m_externalWindowState = settings->value(QLatin1String(kExternalWindowStateKey)).toRect();
|
|
}
|
|
if (m_externalWindowState.isNull())
|
|
m_externalWindow->resize(650, 700);
|
|
else
|
|
m_externalWindow->setGeometry(m_externalWindowState);
|
|
m_externalWindow->show();
|
|
m_externalWindow->setFocus();
|
|
return m_externalWindow->currentViewer();
|
|
}
|
|
|
|
HelpViewer *HelpPlugin::createHelpViewer(qreal zoom)
|
|
{
|
|
// check for backends
|
|
typedef std::function<HelpViewer *()> ViewerFactory;
|
|
QHash<QString, ViewerFactory> factories; // id -> factory
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER
|
|
factories.insert(QLatin1String("native"), []() { return new MacWebKitHelpViewer(); });
|
|
#endif
|
|
#ifndef QT_NO_WEBKIT
|
|
factories.insert(QLatin1String("qtwebkit"), []() { return new QtWebKitHelpViewer(); });
|
|
#endif
|
|
factories.insert(QLatin1String("textbrowser"), []() { return new TextBrowserHelpViewer(); });
|
|
|
|
ViewerFactory factory;
|
|
// TODO: Visual Studio < 2013 has a bug in std::function's operator bool, which in this case
|
|
// leads to succeeding boolean checks on factory which should not succeed.
|
|
// So we may not check against "if (!factory)"
|
|
bool factoryFound = false;
|
|
|
|
// check requested backend
|
|
const QString backend = QLatin1String(qgetenv("QTC_HELPVIEWER_BACKEND"));
|
|
if (!backend.isEmpty()) {
|
|
if (!factories.contains(backend)) {
|
|
qWarning("Help viewer backend \"%s\" not found, using default.", qPrintable(backend));
|
|
} else {
|
|
factory = factories.value(backend);
|
|
factoryFound = true;
|
|
}
|
|
}
|
|
// default setting
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER_DEFAULT
|
|
if (!factoryFound && factories.contains(QLatin1String("native"))) {
|
|
factory = factories.value(QLatin1String("native"));
|
|
factoryFound = true;
|
|
}
|
|
#endif
|
|
if (!factoryFound && factories.contains(QLatin1String("qtwebkit"))) {
|
|
factory = factories.value(QLatin1String("qtwebkit"));
|
|
factoryFound = true;
|
|
}
|
|
if (!factoryFound && factories.contains(QLatin1String("textbrowser"))) {
|
|
factory = factories.value(QLatin1String("textbrowser"));
|
|
factoryFound = true;
|
|
}
|
|
QTC_ASSERT(factoryFound, return 0);
|
|
HelpViewer *viewer = factory();
|
|
|
|
// initialize font
|
|
viewer->setViewerFont(LocalHelpManager::fallbackFont());
|
|
connect(LocalHelpManager::instance(), &LocalHelpManager::fallbackFontChanged,
|
|
viewer, &HelpViewer::setViewerFont);
|
|
|
|
// initialize zoom
|
|
viewer->setScale(zoom);
|
|
|
|
// add find support
|
|
Aggregation::Aggregate *agg = new Aggregation::Aggregate();
|
|
agg->add(viewer);
|
|
agg->add(new HelpViewerFindSupport(viewer));
|
|
|
|
return viewer;
|
|
}
|
|
|
|
void HelpPlugin::activateHelpMode()
|
|
{
|
|
ModeManager::activateMode(Id(Constants::ID_MODE_HELP));
|
|
}
|
|
|
|
void HelpPlugin::showLinkInHelpMode(const QUrl &source)
|
|
{
|
|
activateHelpMode();
|
|
ICore::raiseWindow(m_mode->widget());
|
|
m_centralWidget->setSource(source);
|
|
m_centralWidget->setFocus();
|
|
}
|
|
|
|
void HelpPlugin::showLinksInHelpMode(const QMap<QString, QUrl> &links, const QString &key)
|
|
{
|
|
activateHelpMode();
|
|
ICore::raiseWindow(m_mode->widget());
|
|
m_centralWidget->showTopicChooser(links, key);
|
|
}
|
|
|
|
void HelpPlugin::slotHideRightPane()
|
|
{
|
|
RightPaneWidget::instance()->setShown(false);
|
|
}
|
|
|
|
void HelpPlugin::modeChanged(IMode *mode, IMode *old)
|
|
{
|
|
Q_UNUSED(old)
|
|
if (mode == m_mode) {
|
|
qApp->setOverrideCursor(Qt::WaitCursor);
|
|
doSetupIfNeeded();
|
|
qApp->restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
void HelpPlugin::updateSideBarSource()
|
|
{
|
|
if (HelpViewer *viewer = m_centralWidget->currentViewer()) {
|
|
const QUrl &url = viewer->source();
|
|
if (url.isValid())
|
|
updateSideBarSource(url);
|
|
}
|
|
}
|
|
|
|
void HelpPlugin::updateSideBarSource(const QUrl &newUrl)
|
|
{
|
|
if (m_rightPaneSideBarWidget) {
|
|
// This is called when setSource on the central widget is called.
|
|
// Avoid nested setSource calls (even of different help viewers) by scheduling the
|
|
// sidebar viewer update on the event loop (QTCREATORBUG-12742)
|
|
QMetaObject::invokeMethod(m_rightPaneSideBarWidget->currentViewer(), "setSource",
|
|
Qt::QueuedConnection, Q_ARG(QUrl, newUrl));
|
|
}
|
|
}
|
|
|
|
void HelpPlugin::setupHelpEngineIfNeeded()
|
|
{
|
|
LocalHelpManager::setEngineNeedsUpdate();
|
|
if (ModeManager::currentMode() == m_mode
|
|
|| LocalHelpManager::contextHelpOption() == HelpManager::ExternalHelpAlways)
|
|
LocalHelpManager::setupGuiHelpEngine();
|
|
}
|
|
|
|
bool HelpPlugin::canShowHelpSideBySide() const
|
|
{
|
|
RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
|
|
if (!placeHolder)
|
|
return false;
|
|
if (placeHolder->isVisible())
|
|
return true;
|
|
|
|
IEditor *editor = EditorManager::currentEditor();
|
|
if (!editor)
|
|
return true;
|
|
QTC_ASSERT(editor->widget(), return true);
|
|
if (!editor->widget()->isVisible())
|
|
return true;
|
|
if (editor->widget()->width() < 800)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
HelpViewer *HelpPlugin::viewerForHelpViewerLocation(HelpManager::HelpViewerLocation location)
|
|
{
|
|
HelpManager::HelpViewerLocation actualLocation = location;
|
|
if (location == HelpManager::SideBySideIfPossible)
|
|
actualLocation = canShowHelpSideBySide() ? HelpManager::SideBySideAlways
|
|
: HelpManager::HelpModeAlways;
|
|
|
|
if (actualLocation == HelpManager::ExternalHelpAlways)
|
|
return externalHelpViewer();
|
|
|
|
if (actualLocation == HelpManager::SideBySideAlways) {
|
|
createRightPaneContextViewer();
|
|
RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget);
|
|
RightPaneWidget::instance()->setShown(true);
|
|
return m_rightPaneSideBarWidget->currentViewer();
|
|
}
|
|
|
|
QTC_CHECK(actualLocation == HelpManager::HelpModeAlways);
|
|
|
|
activateHelpMode(); // should trigger an createPage...
|
|
HelpViewer *viewer = m_centralWidget->currentViewer();
|
|
if (!viewer)
|
|
viewer = OpenPagesManager::instance().createPage();
|
|
return viewer;
|
|
}
|
|
|
|
HelpViewer *HelpPlugin::viewerForContextHelp()
|
|
{
|
|
return viewerForHelpViewerLocation(LocalHelpManager::contextHelpOption());
|
|
}
|
|
|
|
static QUrl findBestLink(const QMap<QString, QUrl> &links, QString *highlightId)
|
|
{
|
|
if (highlightId)
|
|
highlightId->clear();
|
|
if (links.isEmpty())
|
|
return QUrl();
|
|
QUrl source = links.constBegin().value();
|
|
// workaround to show the latest Qt version
|
|
int version = 0;
|
|
QRegExp exp(QLatin1String("(\\d+)"));
|
|
foreach (const QUrl &link, links) {
|
|
const QString &authority = link.authority();
|
|
if (authority.startsWith(QLatin1String("com.trolltech."))
|
|
|| authority.startsWith(QLatin1String("org.qt-project."))) {
|
|
if (exp.indexIn(authority) >= 0) {
|
|
const int tmpVersion = exp.cap(1).toInt();
|
|
if (tmpVersion > version) {
|
|
source = link;
|
|
version = tmpVersion;
|
|
if (highlightId)
|
|
*highlightId = source.fragment();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return source;
|
|
}
|
|
|
|
void HelpPlugin::showContextHelp()
|
|
{
|
|
// Find out what to show
|
|
QString contextHelpId = Utils::ToolTip::contextHelpId();
|
|
IContext *context = ICore::currentContextObject();
|
|
if (contextHelpId.isEmpty() && context)
|
|
contextHelpId = context->contextHelpId();
|
|
|
|
// get the viewer after getting the help id,
|
|
// because a new window might be opened and therefore focus be moved
|
|
HelpViewer *viewer = viewerForContextHelp();
|
|
QTC_ASSERT(viewer, return);
|
|
|
|
QMap<QString, QUrl> links = HelpManager::linksForIdentifier(contextHelpId);
|
|
// Maybe the id is already an URL
|
|
if (links.isEmpty() && LocalHelpManager::isValidUrl(contextHelpId))
|
|
links.insert(contextHelpId, contextHelpId);
|
|
|
|
QUrl source = findBestLink(links, &m_contextHelpHighlightId);
|
|
if (!source.isValid()) {
|
|
// No link found or no context object
|
|
viewer->setSource(QUrl(Help::Constants::AboutBlank));
|
|
viewer->setHtml(tr("<html><head><title>No Documentation</title>"
|
|
"</head><body><br/><center>"
|
|
"<font color=\"%1\"><b>%2</b></font><br/>"
|
|
"<font color=\"%3\">No documentation available.</font>"
|
|
"</center></body></html>")
|
|
.arg(creatorTheme()->color(Theme::TextColorNormal).name())
|
|
.arg(contextHelpId)
|
|
.arg(creatorTheme()->color(Theme::TextColorNormal).name()));
|
|
} else {
|
|
const QUrl &oldSource = viewer->source();
|
|
if (source != oldSource) {
|
|
viewer->stop();
|
|
viewer->setSource(source); // triggers loadFinished which triggers id highlighting
|
|
} else {
|
|
viewer->scrollToAnchor(source.fragment());
|
|
}
|
|
viewer->setFocus();
|
|
ICore::raiseWindow(viewer);
|
|
}
|
|
}
|
|
|
|
void HelpPlugin::activateIndex()
|
|
{
|
|
activateHelpMode();
|
|
m_centralWidget->activateSideBarItem(QLatin1String(Constants::HELP_INDEX));
|
|
}
|
|
|
|
void HelpPlugin::activateContents()
|
|
{
|
|
activateHelpMode();
|
|
m_centralWidget->activateSideBarItem(QLatin1String(Constants::HELP_CONTENTS));
|
|
}
|
|
|
|
void HelpPlugin::highlightSearchTermsInContextHelp()
|
|
{
|
|
if (m_contextHelpHighlightId.isEmpty())
|
|
return;
|
|
HelpViewer *viewer = viewerForContextHelp();
|
|
QTC_ASSERT(viewer, return);
|
|
viewer->highlightId(m_contextHelpHighlightId);
|
|
m_contextHelpHighlightId.clear();
|
|
}
|
|
|
|
void HelpPlugin::handleHelpRequest(const QUrl &url, HelpManager::HelpViewerLocation location)
|
|
{
|
|
if (HelpViewer::launchWithExternalApp(url))
|
|
return;
|
|
|
|
QString address = url.toString();
|
|
if (!HelpManager::findFile(url).isValid()) {
|
|
if (address.startsWith(QLatin1String("qthelp://org.qt-project."))
|
|
|| address.startsWith(QLatin1String("qthelp://com.nokia."))
|
|
|| address.startsWith(QLatin1String("qthelp://com.trolltech."))) {
|
|
// local help not installed, resort to external web help
|
|
QString urlPrefix = QLatin1String("http://doc.qt.io/");
|
|
if (url.authority() == QLatin1String("org.qt-project.qtcreator"))
|
|
urlPrefix.append(QString::fromLatin1("qtcreator"));
|
|
else
|
|
urlPrefix.append(QLatin1String("latest"));
|
|
address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
|
|
}
|
|
}
|
|
|
|
const QUrl newUrl(address);
|
|
HelpViewer *viewer = viewerForHelpViewerLocation(location);
|
|
QTC_ASSERT(viewer, return);
|
|
viewer->setSource(newUrl);
|
|
ICore::raiseWindow(viewer);
|
|
}
|
|
|
|
void HelpPlugin::slotOpenSupportPage()
|
|
{
|
|
showLinkInHelpMode(QUrl(QLatin1String("qthelp://org.qt-project.qtcreator/doc/technical-support.html")));
|
|
}
|
|
|
|
void HelpPlugin::slotReportBug()
|
|
{
|
|
QDesktopServices::openUrl(QUrl(QLatin1String("https://bugreports.qt.io")));
|
|
}
|
|
|
|
void HelpPlugin::doSetupIfNeeded()
|
|
{
|
|
LocalHelpManager::setupGuiHelpEngine();
|
|
if (m_setupNeeded) {
|
|
resetFilter();
|
|
m_setupNeeded = false;
|
|
OpenPagesManager::instance().setupInitialPages();
|
|
LocalHelpManager::bookmarkManager().setupBookmarkModels();
|
|
}
|
|
}
|