forked from qt-creator/qt-creator
Save the HelpItem directly in the tooltip instead of the help ID which would need to be looked up again. Change-Id: I107e82e89d9ea26cad9d6532ad4c687d1ac8f1ec Reviewed-by: David Schulz <david.schulz@qt.io>
800 lines
29 KiB
C++
800 lines
29 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 "helpplugin.h"
|
|
|
|
#include "bookmarkmanager.h"
|
|
#include "centralwidget.h"
|
|
#include "docsettingspage.h"
|
|
#include "filtersettingspage.h"
|
|
#include "generalsettingspage.h"
|
|
#include "helpconstants.h"
|
|
#include "helpfindsupport.h"
|
|
#include "helpicons.h"
|
|
#include "helpindexfilter.h"
|
|
#include "helpmanager.h"
|
|
#include "helpmode.h"
|
|
#include "helpviewer.h"
|
|
#include "localhelpmanager.h"
|
|
#include "openpagesmanager.h"
|
|
#include "openpagesmodel.h"
|
|
#include "remotehelpfilter.h"
|
|
#include "searchwidget.h"
|
|
#include "searchtaskhandler.h"
|
|
#include "textbrowserhelpviewer.h"
|
|
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER
|
|
#include "macwebkithelpviewer.h"
|
|
#endif
|
|
#ifdef QTC_WEBENGINE_HELPVIEWER
|
|
#include "webenginehelpviewer.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/helpitem.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/algorithm.h>
|
|
#include <utils/hostosinfo.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/styledbar.h>
|
|
#include <utils/theme/theme.h>
|
|
#include <utils/tooltip/tooltip.h>
|
|
|
|
#include <QClipboard>
|
|
#include <QDialog>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QLibraryInfo>
|
|
#include <QPlainTextEdit>
|
|
#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>
|
|
|
|
static const char kExternalWindowStateKey[] = "Help/ExternalWindowState";
|
|
static const char kToolTipHelpContext[] = "Help.ToolTip";
|
|
|
|
using namespace Core;
|
|
using namespace Utils;
|
|
|
|
namespace Help {
|
|
namespace Internal {
|
|
|
|
class HelpPluginPrivate : public QObject
|
|
{
|
|
public:
|
|
HelpPluginPrivate();
|
|
|
|
void modeChanged(Core::Id mode, Core::Id old);
|
|
|
|
void requestContextHelp();
|
|
void showContextHelp(const HelpItem &contextHelp);
|
|
void activateIndex();
|
|
void activateContents();
|
|
|
|
void saveExternalWindowSettings();
|
|
void showLinksInCurrentViewer(const QMap<QString, QUrl> &links, const QString &key);
|
|
void slotHideRightPane();
|
|
|
|
void updateSideBarSource(const QUrl &newUrl);
|
|
|
|
void setupHelpEngineIfNeeded();
|
|
|
|
HelpViewer *showHelpUrl(const QUrl &url, Core::HelpManager::HelpViewerLocation location);
|
|
|
|
void slotSystemInformation();
|
|
|
|
void resetFilter();
|
|
static void activateHelpMode() { ModeManager::activateMode(Constants::ID_MODE_HELP); }
|
|
static bool canShowHelpSideBySide();
|
|
|
|
HelpViewer *viewerForContextHelp();
|
|
HelpWidget *createHelpWidget(const Core::Context &context, HelpWidget::WidgetStyle style);
|
|
void createRightPaneContextViewer();
|
|
HelpViewer *externalHelpViewer();
|
|
HelpViewer *helpModeHelpViewer();
|
|
HelpWidget *helpWidgetForWindow(QWidget *window);
|
|
HelpViewer *viewerForHelpViewerLocation(Core::HelpManager::HelpViewerLocation location);
|
|
|
|
void showInHelpViewer(const QUrl &url, HelpViewer *viewer);
|
|
void doSetupIfNeeded();
|
|
|
|
HelpMode m_mode;
|
|
CentralWidget *m_centralWidget = nullptr;
|
|
HelpWidget *m_rightPaneSideBarWidget = nullptr;
|
|
|
|
DocSettingsPage m_docSettingsPage;
|
|
FilterSettingsPage m_filterSettingsPage;
|
|
SearchTaskHandler m_searchTaskHandler;
|
|
GeneralSettingsPage m_generalSettingsPage;
|
|
|
|
bool m_setupNeeded = true;
|
|
LocalHelpManager m_localHelpManager;
|
|
OpenPagesManager m_openPagesManager;
|
|
|
|
QPointer<HelpWidget> m_externalWindow;
|
|
QRect m_externalWindowState;
|
|
|
|
HelpIndexFilter helpIndexFilter;
|
|
RemoteHelpFilter remoteHelpFilter;
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
void HelpPlugin::showHelpUrl(const QUrl &url, Core::HelpManager::HelpViewerLocation location)
|
|
{
|
|
dd->showHelpUrl(url, location);
|
|
}
|
|
|
|
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
|
|
{
|
|
Q_UNUSED(arguments)
|
|
Q_UNUSED(error)
|
|
dd = new HelpPluginPrivate;
|
|
return true;
|
|
}
|
|
|
|
HelpPluginPrivate::HelpPluginPrivate()
|
|
{
|
|
Context modecontext(Help::Constants::C_MODE_HELP);
|
|
|
|
const QString &locale = ICore::userInterfaceLanguage();
|
|
if (!locale.isEmpty()) {
|
|
auto qtr = new QTranslator(this);
|
|
auto qhelptr = new QTranslator(this);
|
|
const QString &creatorTrPath = ICore::resourcePath() + "/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))
|
|
QCoreApplication::installTranslator(qtr);
|
|
if (qhelptr->load(helpTrFile, qtTrPath) || qhelptr->load(helpTrFile, creatorTrPath))
|
|
QCoreApplication::installTranslator(qhelptr);
|
|
}
|
|
|
|
m_centralWidget = new CentralWidget(Context("Help.CentralHelpWidget"));
|
|
connect(m_centralWidget, &HelpWidget::sourceChanged,
|
|
this, &HelpPluginPrivate::updateSideBarSource);
|
|
connect(m_centralWidget, &CentralWidget::closeButtonClicked,
|
|
&OpenPagesManager::instance(), &OpenPagesManager::closeCurrentPage);
|
|
|
|
connect(LocalHelpManager::instance(), &LocalHelpManager::returnOnCloseChanged,
|
|
m_centralWidget, &CentralWidget::updateCloseButton);
|
|
connect(HelpManager::instance(), &HelpManager::helpRequested,
|
|
this, &HelpPluginPrivate::showHelpUrl);
|
|
connect(&m_searchTaskHandler, &SearchTaskHandler::search,
|
|
this, &QDesktopServices::openUrl);
|
|
|
|
connect(&m_filterSettingsPage, &FilterSettingsPage::filtersChanged,
|
|
this, &HelpPluginPrivate::setupHelpEngineIfNeeded);
|
|
connect(Core::HelpManager::Signals::instance(),
|
|
&Core::HelpManager::Signals::documentationChanged,
|
|
this,
|
|
&HelpPluginPrivate::setupHelpEngineIfNeeded);
|
|
connect(HelpManager::instance(), &HelpManager::collectionFileChanged,
|
|
this, &HelpPluginPrivate::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("help-contents"),
|
|
HelpPlugin::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, &QAction::triggered, this, &HelpPluginPrivate::activateContents);
|
|
|
|
action = new QAction(HelpPlugin::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, &QAction::triggered, this, &HelpPluginPrivate::activateIndex);
|
|
|
|
action = new QAction(HelpPlugin::tr("Context Help"), this);
|
|
cmd = ActionManager::registerAction(action, Help::Constants::CONTEXT_HELP,
|
|
Context(kToolTipHelpContext, Core::Constants::C_GLOBAL));
|
|
cmd->setTouchBarIcon(Icons::MACOS_TOUCHBAR_HELP.icon());
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
|
|
ActionManager::actionContainer(Core::Constants::TOUCH_BAR)
|
|
->addAction(cmd, Core::Constants::G_TOUCHBAR_HELP);
|
|
cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
|
|
connect(action, &QAction::triggered, this, &HelpPluginPrivate::requestContextHelp);
|
|
ActionContainer *textEditorContextMenu = ActionManager::actionContainer(
|
|
TextEditor::Constants::M_STANDARDCONTEXTMENU);
|
|
if (textEditorContextMenu) {
|
|
textEditorContextMenu->insertGroup(TextEditor::Constants::G_BOM,
|
|
Core::Constants::G_HELP);
|
|
textEditorContextMenu->addSeparator(Core::Constants::G_HELP);
|
|
textEditorContextMenu->addAction(cmd, Core::Constants::G_HELP);
|
|
}
|
|
|
|
action = new QAction(HelpPlugin::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, &QAction::triggered, this, [this] {
|
|
showHelpUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/technical-support.html"),
|
|
Core::HelpManager::HelpModeAlways);
|
|
});
|
|
|
|
action = new QAction(HelpPlugin::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, &QAction::triggered, this, [] {
|
|
QDesktopServices::openUrl(QUrl("https://bugreports.qt.io"));
|
|
});
|
|
|
|
action = new QAction(HelpPlugin::tr("System Information..."), this);
|
|
cmd = ActionManager::registerAction(action, "Help.SystemInformation");
|
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
|
|
connect(action, &QAction::triggered, this, &HelpPluginPrivate::slotSystemInformation);
|
|
|
|
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, &QAction::triggered, &OpenPagesManager::instance(),
|
|
&OpenPagesManager::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, &QAction::triggered, &OpenPagesManager::instance(),
|
|
&OpenPagesManager::gotoNextPage);
|
|
}
|
|
|
|
connect(&helpIndexFilter, &HelpIndexFilter::linksActivated,
|
|
this, &HelpPluginPrivate::showLinksInCurrentViewer);
|
|
|
|
connect(&remoteHelpFilter, &RemoteHelpFilter::linkActivated,
|
|
this, &QDesktopServices::openUrl);
|
|
|
|
QDesktopServices::setUrlHandler("qthelp", HelpManager::instance(), "showHelpUrl");
|
|
connect(ModeManager::instance(), &ModeManager::currentModeChanged,
|
|
this, &HelpPluginPrivate::modeChanged);
|
|
|
|
m_mode.setWidget(m_centralWidget);
|
|
}
|
|
|
|
void HelpPlugin::extensionsInitialized()
|
|
{
|
|
QStringList filesToRegister;
|
|
// we might need to register creators inbuild help
|
|
filesToRegister.append(Core::HelpManager::documentationPath() + "/qtcreator.qch");
|
|
Core::HelpManager::registerDocumentation(filesToRegister);
|
|
}
|
|
|
|
bool HelpPlugin::delayedInitialize()
|
|
{
|
|
HelpManager::setupHelpManager();
|
|
return true;
|
|
}
|
|
|
|
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
|
|
{
|
|
delete dd->m_externalWindow.data();
|
|
|
|
delete dd->m_centralWidget;
|
|
dd->m_centralWidget = nullptr;
|
|
|
|
delete dd->m_rightPaneSideBarWidget;
|
|
dd->m_rightPaneSideBarWidget = nullptr;
|
|
|
|
return SynchronousShutdown;
|
|
}
|
|
|
|
void HelpPluginPrivate::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("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 = HelpPlugin::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 HelpPluginPrivate::saveExternalWindowSettings()
|
|
{
|
|
if (!m_externalWindow)
|
|
return;
|
|
m_externalWindowState = m_externalWindow->geometry();
|
|
QSettings *settings = ICore::settings();
|
|
settings->setValue(kExternalWindowStateKey, qVariantFromValue(m_externalWindowState));
|
|
}
|
|
|
|
HelpWidget *HelpPluginPrivate::createHelpWidget(const Context &context, HelpWidget::WidgetStyle style)
|
|
{
|
|
auto widget = new HelpWidget(context, style);
|
|
|
|
connect(widget, &HelpWidget::openHelpMode, this, [this](const QUrl &url) {
|
|
showHelpUrl(url, Core::HelpManager::HelpModeAlways);
|
|
});
|
|
connect(widget, &HelpWidget::closeButtonClicked, this, &HelpPluginPrivate::slotHideRightPane);
|
|
connect(widget, &HelpWidget::aboutToClose,
|
|
this, &HelpPluginPrivate::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 HelpPluginPrivate::createRightPaneContextViewer()
|
|
{
|
|
if (m_rightPaneSideBarWidget)
|
|
return;
|
|
m_rightPaneSideBarWidget = createHelpWidget(Context(Constants::C_HELP_SIDEBAR),
|
|
HelpWidget::SideBarWidget);
|
|
}
|
|
|
|
HelpViewer *HelpPluginPrivate::externalHelpViewer()
|
|
{
|
|
if (m_externalWindow)
|
|
return m_externalWindow->currentViewer();
|
|
doSetupIfNeeded();
|
|
// Deletion for this widget is taken care of in HelpPlugin::aboutToShutdown().
|
|
m_externalWindow = createHelpWidget(Context(Constants::C_HELP_EXTERNAL),
|
|
HelpWidget::ExternalWindow);
|
|
if (m_externalWindowState.isNull()) {
|
|
QSettings *settings = ICore::settings();
|
|
m_externalWindowState = settings->value(kExternalWindowStateKey).toRect();
|
|
}
|
|
if (m_externalWindowState.isNull())
|
|
m_externalWindow->resize(650, 700);
|
|
else
|
|
m_externalWindow->setGeometry(m_externalWindowState);
|
|
m_externalWindow->show();
|
|
return m_externalWindow->currentViewer();
|
|
}
|
|
|
|
HelpViewer *HelpPlugin::createHelpViewer(qreal zoom)
|
|
{
|
|
// check for backends
|
|
using ViewerFactory = std::function<HelpViewer *()>;
|
|
using ViewerFactoryItem = QPair<QByteArray, ViewerFactory>; // id -> factory
|
|
QVector<ViewerFactoryItem> factories;
|
|
#ifdef QTC_WEBENGINE_HELPVIEWER
|
|
factories.append(qMakePair(QByteArray("qtwebengine"), []() { return new WebEngineHelpViewer(); }));
|
|
#endif
|
|
factories.append(qMakePair(QByteArray("textbrowser"), []() { return new TextBrowserHelpViewer(); }));
|
|
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER
|
|
// default setting
|
|
#ifdef QTC_MAC_NATIVE_HELPVIEWER_DEFAULT
|
|
factories.prepend(qMakePair(QByteArray("native"), []() { return new MacWebKitHelpViewer(); }));
|
|
#else
|
|
factories.append(qMakePair(QByteArray("native"), []() { return new MacWebKitHelpViewer(); }));
|
|
#endif
|
|
#endif
|
|
|
|
HelpViewer *viewer = nullptr;
|
|
|
|
// check requested backend
|
|
const QByteArray backend = qgetenv("QTC_HELPVIEWER_BACKEND");
|
|
if (!backend.isEmpty()) {
|
|
const int pos = Utils::indexOf(factories, [backend](const ViewerFactoryItem &item) {
|
|
return backend == item.first;
|
|
});
|
|
if (pos == -1) {
|
|
qWarning("Help viewer backend \"%s\" not found, using default.", backend.constData());
|
|
} else {
|
|
viewer = factories.at(pos).second();
|
|
}
|
|
}
|
|
|
|
if (!viewer)
|
|
viewer = factories.first().second();
|
|
QTC_ASSERT(viewer, return nullptr);
|
|
|
|
// initialize font
|
|
viewer->setViewerFont(LocalHelpManager::fallbackFont());
|
|
connect(LocalHelpManager::instance(), &LocalHelpManager::fallbackFontChanged,
|
|
viewer, &HelpViewer::setViewerFont);
|
|
|
|
// initialize zoom
|
|
viewer->setScale(zoom);
|
|
|
|
// add find support
|
|
auto agg = new Aggregation::Aggregate;
|
|
agg->add(viewer);
|
|
agg->add(new HelpViewerFindSupport(viewer));
|
|
|
|
return viewer;
|
|
}
|
|
|
|
void HelpPluginPrivate::showLinksInCurrentViewer(const QMap<QString, QUrl> &links, const QString &key)
|
|
{
|
|
if (links.size() < 1)
|
|
return;
|
|
HelpWidget *widget = helpWidgetForWindow(QApplication::activeWindow());
|
|
widget->showLinks(links, key);
|
|
}
|
|
|
|
void HelpPluginPrivate::slotHideRightPane()
|
|
{
|
|
RightPaneWidget::instance()->setShown(false);
|
|
}
|
|
|
|
void HelpPluginPrivate::modeChanged(Core::Id mode, Core::Id old)
|
|
{
|
|
Q_UNUSED(old)
|
|
if (mode == m_mode.id()) {
|
|
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
|
|
doSetupIfNeeded();
|
|
QGuiApplication::restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
void HelpPluginPrivate::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 HelpPluginPrivate::setupHelpEngineIfNeeded()
|
|
{
|
|
LocalHelpManager::setEngineNeedsUpdate();
|
|
if (ModeManager::currentModeId() == m_mode.id()
|
|
|| LocalHelpManager::contextHelpOption() == Core::HelpManager::ExternalHelpAlways)
|
|
LocalHelpManager::setupGuiHelpEngine();
|
|
}
|
|
|
|
bool HelpPluginPrivate::canShowHelpSideBySide()
|
|
{
|
|
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 *HelpPluginPrivate::helpModeHelpViewer()
|
|
{
|
|
activateHelpMode(); // should trigger an createPage...
|
|
HelpViewer *viewer = m_centralWidget->currentViewer();
|
|
if (!viewer)
|
|
viewer = OpenPagesManager::instance().createPage();
|
|
return viewer;
|
|
}
|
|
|
|
HelpWidget *HelpPluginPrivate::helpWidgetForWindow(QWidget *window)
|
|
{
|
|
if (m_externalWindow && m_externalWindow->window() == window->window())
|
|
return m_externalWindow;
|
|
activateHelpMode();
|
|
return m_centralWidget;
|
|
}
|
|
|
|
HelpViewer *HelpPluginPrivate::viewerForHelpViewerLocation(
|
|
Core::HelpManager::HelpViewerLocation location)
|
|
{
|
|
Core::HelpManager::HelpViewerLocation actualLocation = location;
|
|
if (location == Core::HelpManager::SideBySideIfPossible)
|
|
actualLocation = canShowHelpSideBySide() ? Core::HelpManager::SideBySideAlways
|
|
: Core::HelpManager::HelpModeAlways;
|
|
|
|
if (actualLocation == Core::HelpManager::ExternalHelpAlways)
|
|
return externalHelpViewer();
|
|
|
|
if (actualLocation == Core::HelpManager::SideBySideAlways) {
|
|
createRightPaneContextViewer();
|
|
RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget);
|
|
RightPaneWidget::instance()->setShown(true);
|
|
return m_rightPaneSideBarWidget->currentViewer();
|
|
}
|
|
|
|
QTC_CHECK(actualLocation == Core::HelpManager::HelpModeAlways);
|
|
|
|
return helpModeHelpViewer();
|
|
}
|
|
|
|
void HelpPluginPrivate::showInHelpViewer(const QUrl &url, HelpViewer *viewer)
|
|
{
|
|
QTC_ASSERT(viewer, return);
|
|
viewer->setFocus();
|
|
viewer->stop();
|
|
viewer->setSource(url);
|
|
ICore::raiseWindow(viewer);
|
|
// Show the parent top-level-widget in case it was closed previously.
|
|
viewer->window()->show();
|
|
}
|
|
|
|
HelpViewer *HelpPluginPrivate::viewerForContextHelp()
|
|
{
|
|
return viewerForHelpViewerLocation(LocalHelpManager::contextHelpOption());
|
|
}
|
|
|
|
static QUrl findBestLink(const QMap<QString, QUrl> &links)
|
|
{
|
|
if (links.isEmpty())
|
|
return QUrl();
|
|
QUrl source = links.constBegin().value();
|
|
// workaround to show the latest Qt version
|
|
int version = 0;
|
|
QRegExp exp("(\\d+)");
|
|
foreach (const QUrl &link, links) {
|
|
const QString &authority = link.authority();
|
|
if (authority.startsWith("com.trolltech.")
|
|
|| authority.startsWith("org.qt-project.")) {
|
|
if (exp.indexIn(authority) >= 0) {
|
|
const int tmpVersion = exp.cap(1).toInt();
|
|
if (tmpVersion > version) {
|
|
source = link;
|
|
version = tmpVersion;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return source;
|
|
}
|
|
|
|
void HelpPluginPrivate::requestContextHelp()
|
|
{
|
|
// Find out what to show
|
|
const QVariant tipHelpValue = Utils::ToolTip::contextHelp();
|
|
const HelpItem tipHelp = tipHelpValue.canConvert<HelpItem>()
|
|
? tipHelpValue.value<HelpItem>()
|
|
: HelpItem(tipHelpValue.toString());
|
|
IContext *context = ICore::currentContextObject();
|
|
if (!tipHelp.isValid() && context)
|
|
context->contextHelp([this](const HelpItem &item) { showContextHelp(item); });
|
|
else
|
|
showContextHelp(tipHelp);
|
|
}
|
|
|
|
void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
|
|
{
|
|
const QMap<QString, QUrl> &links = contextHelp.links();
|
|
|
|
const QUrl source = findBestLink(links);
|
|
if (!source.isValid()) {
|
|
// No link found or no context object
|
|
HelpViewer *viewer = showHelpUrl(QUrl(Help::Constants::AboutBlank),
|
|
LocalHelpManager::contextHelpOption());
|
|
if (viewer) {
|
|
viewer->setHtml(QString("<html><head><title>%1</title>"
|
|
"</head><body bgcolor=\"%2\"><br/><center>"
|
|
"<font color=\"%3\"><b>%4</b></font><br/>"
|
|
"<font color=\"%3\">%5</font>"
|
|
"</center></body></html>")
|
|
.arg(HelpPlugin::tr("No Documentation"))
|
|
.arg(creatorTheme()->color(Theme::BackgroundColorNormal).name())
|
|
.arg(creatorTheme()->color(Theme::TextColorNormal).name())
|
|
.arg(contextHelp.helpId())
|
|
.arg(HelpPlugin::tr("No documentation available.")));
|
|
}
|
|
} else {
|
|
showHelpUrl(source, LocalHelpManager::contextHelpOption());
|
|
}
|
|
}
|
|
|
|
void HelpPluginPrivate::activateIndex()
|
|
{
|
|
activateHelpMode();
|
|
m_centralWidget->activateSideBarItem(Constants::HELP_INDEX);
|
|
}
|
|
|
|
void HelpPluginPrivate::activateContents()
|
|
{
|
|
activateHelpMode();
|
|
m_centralWidget->activateSideBarItem(Constants::HELP_CONTENTS);
|
|
}
|
|
|
|
HelpViewer *HelpPluginPrivate::showHelpUrl(const QUrl &url, Core::HelpManager::HelpViewerLocation location)
|
|
{
|
|
static const QString qtcreatorUnversionedID = "org.qt-project.qtcreator";
|
|
if (url.host() == qtcreatorUnversionedID) {
|
|
// QtHelp doesn't know about versions, add the version number and use that
|
|
QUrl versioned = url;
|
|
versioned.setHost(qtcreatorUnversionedID + "."
|
|
+ QString::fromLatin1(Core::Constants::IDE_VERSION_LONG).remove('.'));
|
|
|
|
return showHelpUrl(versioned, location);
|
|
}
|
|
|
|
if (HelpViewer::launchWithExternalApp(url))
|
|
return nullptr;
|
|
|
|
if (!HelpManager::findFile(url).isValid()) {
|
|
const QString address = url.toString();
|
|
if (address.startsWith("qthelp://org.qt-project.")
|
|
|| address.startsWith("qthelp://com.nokia.")
|
|
|| address.startsWith("qthelp://com.trolltech.")) {
|
|
// local help not installed, resort to external web help
|
|
QString urlPrefix = "http://doc.qt.io/";
|
|
if (url.authority().startsWith(qtcreatorUnversionedID))
|
|
urlPrefix.append(QString::fromLatin1("qtcreator"));
|
|
else
|
|
urlPrefix.append("qt-5");
|
|
QDesktopServices::openUrl(QUrl(urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')))));
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
HelpViewer *viewer = viewerForHelpViewerLocation(location);
|
|
showInHelpViewer(url, viewer);
|
|
return viewer;
|
|
}
|
|
|
|
class DialogClosingOnEscape : public QDialog
|
|
{
|
|
public:
|
|
DialogClosingOnEscape(QWidget *parent = nullptr) : QDialog(parent) {}
|
|
bool event(QEvent *event) override
|
|
{
|
|
if (event->type() == QEvent::ShortcutOverride) {
|
|
auto ke = static_cast<QKeyEvent *>(event);
|
|
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
|
|
ke->accept();
|
|
return true;
|
|
}
|
|
}
|
|
return QDialog::event(event);
|
|
}
|
|
};
|
|
|
|
void HelpPluginPrivate::slotSystemInformation()
|
|
{
|
|
auto dialog = new DialogClosingOnEscape(ICore::dialogParent());
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
dialog->setModal(true);
|
|
dialog->setWindowTitle(HelpPlugin::tr("System Information"));
|
|
auto layout = new QVBoxLayout;
|
|
dialog->setLayout(layout);
|
|
auto intro = new QLabel(HelpPlugin::tr("Use the following to provide more detailed information about your system to bug reports:"));
|
|
intro->setWordWrap(true);
|
|
layout->addWidget(intro);
|
|
const QString text = "{noformat}\n" + ICore::systemInformation() + "\n{noformat}";
|
|
auto info = new QPlainTextEdit;
|
|
QFont font = info->font();
|
|
font.setFamily("Courier");
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
info->setFont(font);
|
|
info->setPlainText(text);
|
|
layout->addWidget(info);
|
|
auto buttonBox = new QDialogButtonBox;
|
|
buttonBox->addButton(QDialogButtonBox::Cancel);
|
|
buttonBox->addButton(HelpPlugin::tr("Copy to Clipboard"), QDialogButtonBox::AcceptRole);
|
|
connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
|
|
connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
|
|
layout->addWidget(buttonBox);
|
|
connect(dialog, &QDialog::accepted, info, [info]() {
|
|
if (QApplication::clipboard())
|
|
QApplication::clipboard()->setText(info->toPlainText());
|
|
});
|
|
connect(dialog, &QDialog::rejected, dialog, [dialog]{ dialog->close(); });
|
|
dialog->resize(700, 400);
|
|
ICore::registerWindow(dialog, Context("Help.SystemInformation"));
|
|
dialog->show();
|
|
}
|
|
|
|
void HelpPluginPrivate::doSetupIfNeeded()
|
|
{
|
|
LocalHelpManager::setupGuiHelpEngine();
|
|
if (m_setupNeeded) {
|
|
resetFilter();
|
|
m_setupNeeded = false;
|
|
OpenPagesManager::instance().setupInitialPages();
|
|
LocalHelpManager::bookmarkManager().setupBookmarkModels();
|
|
}
|
|
}
|
|
|
|
} // Internal
|
|
} // Help
|