helpplugin.cpp 24.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
** 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 Digia.  For licensing terms and
Eike Ziller's avatar
Eike Ziller committed
13
14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** 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.
hjk's avatar
hjk committed
24
25
26
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30

con's avatar
con committed
31
#include "helpplugin.h"
32
33

#include "centralwidget.h"
con's avatar
con committed
34
35
#include "docsettingspage.h"
#include "filtersettingspage.h"
36
#include "generalsettingspage.h"
kh1's avatar
kh1 committed
37
#include "helpconstants.h"
38
#include "helpfindsupport.h"
con's avatar
con committed
39
40
41
#include "helpindexfilter.h"
#include "helpmode.h"
#include "helpviewer.h"
42
#include "localhelpmanager.h"
43
44
#include "openpagesmanager.h"
#include "openpagesmodel.h"
45
#include "qtwebkithelpviewer.h"
kh1's avatar
kh1 committed
46
#include "remotehelpfilter.h"
con's avatar
con committed
47
#include "searchwidget.h"
48
#include "searchtaskhandler.h"
49
#include "textbrowserhelpviewer.h"
con's avatar
con committed
50

51
52
53
54
#ifdef QTC_MAC_NATIVE_HELPVIEWER
#include "macwebkithelpviewer.h"
#endif

55
56
57
58
#include <bookmarkmanager.h>
#include <contentwindow.h>
#include <indexwindow.h>

59
#include <app/app_version.h>
60
#include <coreplugin/actionmanager/actionmanager.h>
61
62
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
63
#include <coreplugin/id.h>
64
65
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
66
#include <coreplugin/editormanager/ieditor.h>
67
68
#include <coreplugin/findplaceholder.h>
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
69
70
71
72
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/rightpane.h>
#include <coreplugin/sidebar.h>
kh1's avatar
kh1 committed
73
#include <extensionsystem/pluginmanager.h>
74
#include <coreplugin/find/findplugin.h>
75
#include <texteditor/texteditorconstants.h>
76
#include <utils/hostosinfo.h>
77
#include <utils/qtcassert.h>
78
#include <utils/styledbar.h>
79
#include <utils/theme/theme.h>
80

81
82
83
84
85
86
87
#include <QDir>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QTimer>
#include <QTranslator>
#include <qplugin.h>
#include <QRegExp>
kh1's avatar
kh1 committed
88

89
90
91
92
93
94
#include <QAction>
#include <QComboBox>
#include <QDesktopServices>
#include <QMenu>
#include <QStackedLayout>
#include <QSplitter>
kh1's avatar
kh1 committed
95

96
#include <QHelpEngine>
con's avatar
con committed
97
98
99

using namespace Help::Internal;

100
101
static const char kExternalWindowStateKey[] = "Help/ExternalWindowState";

102
using namespace Core;
103
using namespace Utils;
104

kh1's avatar
kh1 committed
105
HelpPlugin::HelpPlugin()
106
    : m_mode(0),
con's avatar
con committed
107
    m_centralWidget(0),
108
    m_rightPaneSideBarWidget(0),
109
    m_setupNeeded(true),
110
    m_helpManager(0),
111
    m_openPagesManager(0)
con's avatar
con committed
112
113
114
115
116
{
}

HelpPlugin::~HelpPlugin()
{
117
118
    delete m_openPagesManager;
    delete m_helpManager;
con's avatar
con committed
119
120
}

121
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
con's avatar
con committed
122
{
123
124
    Q_UNUSED(arguments)
    Q_UNUSED(error)
125
126
    Context globalcontext(Core::Constants::C_GLOBAL);
    Context modecontext(Constants::C_MODE_HELP);
con's avatar
con committed
127

128
    const QString &locale = ICore::userInterfaceLanguage();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
129
130
    if (!locale.isEmpty()) {
        QTranslator *qtr = new QTranslator(this);
131
        QTranslator *qhelptr = new QTranslator(this);
132
        const QString &creatorTrPath = ICore::resourcePath()
133
            + QLatin1String("/translations");
134
135
136
137
138
139
140
        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);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
141
142
    }

143
144
    m_helpManager = new LocalHelpManager(this);
    m_openPagesManager = new OpenPagesManager(this);
145
146
    addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
    addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
147
    addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage());
148
    addAutoReleasedObject(m_searchTaskHandler = new SearchTaskHandler);
149

150
151
152
153
154
155
    m_centralWidget = new Help::Internal::CentralWidget(modecontext);
    connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
        SLOT(updateSideBarSource(QUrl)));
    connect(m_centralWidget, &CentralWidget::closeButtonClicked,
            &OpenPagesManager::instance(), &OpenPagesManager::closeCurrentPage);

156
157
    connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
        SLOT(fontChanged()));
158
    connect(m_generalSettingsPage, SIGNAL(returnOnCloseChanged()), m_centralWidget,
159
        SLOT(updateCloseButton()));
160
161
    connect(HelpManager::instance(), SIGNAL(helpRequested(QUrl,Core::HelpManager::HelpViewerLocation)),
            this, SLOT(handleHelpRequest(QUrl,Core::HelpManager::HelpViewerLocation)));
162
    connect(m_searchTaskHandler, SIGNAL(search(QUrl)), this,
163
            SLOT(showLinkInHelpMode(QUrl)));
164

165
166
    connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
        SLOT(setupHelpEngineIfNeeded()));
167
    connect(HelpManager::instance(), SIGNAL(documentationChanged()), this,
168
        SLOT(setupHelpEngineIfNeeded()));
169
    connect(HelpManager::instance(), SIGNAL(collectionFileChanged()), this,
170
        SLOT(setupHelpEngineIfNeeded()));
con's avatar
con committed
171

172
    Command *cmd;
173
    QAction *action;
con's avatar
con committed
174

175
    // Add Contents, Index, and Context menu items
176
    action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")),
177
        tr(Constants::SB_CONTENTS), this);
178
    cmd = ActionManager::registerAction(action, "Help.ContentsMenu", globalcontext);
179
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
180
181
    connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));

182
    action = new QAction(tr(Constants::SB_INDEX), this);
183
    cmd = ActionManager::registerAction(action, "Help.IndexMenu", globalcontext);
184
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
185
186
187
    connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));

    action = new QAction(tr("Context Help"), this);
188
    cmd = ActionManager::registerAction(action, Help::Constants::CONTEXT_HELP, globalcontext);
189
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
con's avatar
con committed
190
    cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
191
    connect(action, SIGNAL(triggered()), this, SLOT(showContextHelp()));
con's avatar
con committed
192

193
    action = new QAction(tr("Technical Support"), this);
194
    cmd = ActionManager::registerAction(action, "Help.TechSupport", globalcontext);
195
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
196
197
    connect(action, SIGNAL(triggered()), this, SLOT(slotOpenSupportPage()));

198
    action = new QAction(tr("Report Bug..."), this);
199
    cmd = ActionManager::registerAction(action, "Help.ReportBug", globalcontext);
200
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
201
202
    connect(action, SIGNAL(triggered()), this, SLOT(slotReportBug()));

203
    if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) {
204
        // reuse EditorManager constants to avoid a second pair of menu actions
205
        // Goto Previous In History Action
Jarek Kobus's avatar
Jarek Kobus committed
206
        action = new QAction(this);
207
208
        Command *ctrlTab = ActionManager::registerAction(action, Core::Constants::GOTOPREVINHISTORY,
            modecontext);
209
210
211
212
        windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoPreviousPage()));

213
        // Goto Next In History Action
Jarek Kobus's avatar
Jarek Kobus committed
214
        action = new QAction(this);
215
216
        Command *ctrlShiftTab = ActionManager::registerAction(action, Core::Constants::GOTONEXTINHISTORY,
            modecontext);
217
218
219
220
221
        windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoNextPage()));
    }

222
    auto helpIndexFilter = new HelpIndexFilter();
223
    addAutoReleasedObject(helpIndexFilter);
224
225
226
227
    connect(helpIndexFilter, &HelpIndexFilter::linkActivated,
            this, &HelpPlugin::showLinkInHelpMode);
    connect(helpIndexFilter, &HelpIndexFilter::linksActivated,
            this, &HelpPlugin::showLinksInHelpMode);
228

kh1's avatar
kh1 committed
229
230
231
    RemoteHelpFilter *remoteHelpFilter = new RemoteHelpFilter();
    addAutoReleasedObject(remoteHelpFilter);
    connect(remoteHelpFilter, SIGNAL(linkActivated(QUrl)), this,
232
        SLOT(showLinkInHelpMode(QUrl)));
kh1's avatar
kh1 committed
233

234
    QDesktopServices::setUrlHandler(QLatin1String("qthelp"), this, "handleHelpRequest");
235
236
    connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*,Core::IMode*)),
            this, SLOT(modeChanged(Core::IMode*,Core::IMode*)));
237

238
    m_mode = new HelpMode;
239
    m_mode->setWidget(m_centralWidget);
240
    addAutoReleasedObject(m_mode);
241

con's avatar
con committed
242
243
244
    return true;
}

245
void HelpPlugin::extensionsInitialized()
246
{
247
248
    QStringList filesToRegister;
    // we might need to register creators inbuild help
249
    filesToRegister.append(ICore::documentationPath() + QLatin1String("/qtcreator.qch"));
250
    HelpManager::registerDocumentation(filesToRegister);
251
252
}

253
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
254
{
255
256
257
258
259
260
    if (m_externalWindow)
        delete m_externalWindow.data();
    if (m_centralWidget)
        delete m_centralWidget;
    if (m_rightPaneSideBarWidget)
        delete m_rightPaneSideBarWidget;
261
    return SynchronousShutdown;
262
263
}

kh1's avatar
kh1 committed
264
265
void HelpPlugin::resetFilter()
{
kh1's avatar
kh1 committed
266
267
    const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
268
    QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*"));
kh1's avatar
kh1 committed
269
270
271
272
273
274
275
276

    QHelpEngineCore *engine = &LocalHelpManager::helpEngine();
    const QStringList &filters = engine->customFilters();
    foreach (const QString &filter, filters) {
        if (filterRegExp.exactMatch(filter) && filter != filterInternal)
            engine->removeCustomFilter(filter);
    }

277
278
279
280
    // 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();
281
        if (!filter.isEmpty())
kh1's avatar
kh1 committed
282
            engine->removeCustomFilter(filter);
kh1's avatar
kh1 committed
283
284
285
286
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
kh1's avatar
kh1 committed
287
288
    engine->removeCustomFilter(filterName);
    engine->addCustomFilter(filterName, QStringList());
289
290
    engine->setCustomValue(Help::Constants::WeAddedFilterKey, 1);
    engine->setCustomValue(Help::Constants::PreviousFilterNameKey, filterName);
kh1's avatar
kh1 committed
291
292
    engine->setCurrentFilter(filterName);

293
294
295
    LocalHelpManager::updateFilterModel();
    connect(engine, &QHelpEngineCore::setupFinished,
            LocalHelpManager::instance(), &LocalHelpManager::updateFilterModel);
296
297
}

298
void HelpPlugin::saveExternalWindowSettings()
con's avatar
con committed
299
{
300
    if (!m_externalWindow)
301
        return;
302
303
304
305
306
    m_externalWindowState = m_externalWindow->geometry();
    QSettings *settings = Core::ICore::settings();
    settings->setValue(QLatin1String(kExternalWindowStateKey),
                       qVariantFromValue(m_externalWindowState));
}
con's avatar
con committed
307

308
309
310
HelpWidget *HelpPlugin::createHelpWidget(const Context &context, HelpWidget::WidgetStyle style)
{
    HelpWidget *widget = new HelpWidget(context, style);
311

312
    connect(widget->currentViewer(), SIGNAL(loadFinished()),
313
            this, SLOT(highlightSearchTermsInContextHelp()));
314
    connect(widget, SIGNAL(openHelpMode(QUrl)),
315
            this, SLOT(showLinkInHelpMode(QUrl)));
316
    connect(widget, SIGNAL(closeButtonClicked()),
317
            this, SLOT(slotHideRightPane()));
318
319
    connect(widget, SIGNAL(aboutToClose()),
            this, SLOT(saveExternalWindowSettings()));
320

kh1's avatar
kh1 committed
321
322
    // force setup, as we might have never switched to full help mode
    // thus the help engine might still run without collection file setup
323
    LocalHelpManager::setupGuiHelpEngine();
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339

    return widget;
}

void HelpPlugin::createRightPaneContextViewer()
{
    if (m_rightPaneSideBarWidget)
        return;
    m_rightPaneSideBarWidget = createHelpWidget(Core::Context(Constants::C_HELP_SIDEBAR),
                                                HelpWidget::SideBarWidget);
}

HelpViewer *HelpPlugin::externalHelpViewer()
{
    if (m_externalWindow)
        return m_externalWindow->currentViewer();
340
    doSetupIfNeeded();
341
342
343
344
345
346
    m_externalWindow = createHelpWidget(Core::Context(Constants::C_HELP_EXTERNAL),
                                        HelpWidget::ExternalWindow);
    if (m_externalWindowState.isNull()) {
        QSettings *settings = Core::ICore::settings();
        m_externalWindowState = settings->value(QLatin1String(kExternalWindowStateKey)).toRect();
    }
347
348
349
    if (m_externalWindowState.isNull())
        m_externalWindow->resize(650, 700);
    else
350
351
        m_externalWindow->setGeometry(m_externalWindowState);
    m_externalWindow->show();
352
    m_externalWindow->setFocus();
353
    return m_externalWindow->currentViewer();
con's avatar
con committed
354
355
}

356
357
HelpViewer *HelpPlugin::createHelpViewer(qreal zoom)
{
358
359
360
361
362
    HelpViewer *viewer = 0;
    const QString backend = QLatin1String(qgetenv("QTC_HELPVIEWER_BACKEND"));
    if (backend.compare(QLatin1String("native"), Qt::CaseInsensitive) == 0) {
#ifdef QTC_MAC_NATIVE_HELPVIEWER
        viewer = new MacWebKitHelpViewer(zoom);
363
364
#else
        qWarning() << "native help viewer is requested, but was not enabled during compilation";
365
#endif
366
    } else if (backend.compare(QLatin1String("textbrowser"), Qt::CaseInsensitive) != 0) {
367
#ifndef QT_NO_WEBKIT
368
        viewer = new QtWebKitHelpViewer(zoom);
369
#endif
370
    }
371
372
    if (!viewer)
        viewer = new TextBrowserHelpViewer(zoom);
373
374
375
376
377

    // initialize font
    QVariant fontSetting = LocalHelpManager::engineFontSettings();
    if (fontSetting.isValid())
        viewer->setViewerFont(fontSetting.value<QFont>());
378
379
380
381
382
383

    // add find support
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(viewer);
    agg->add(new HelpViewerFindSupport(viewer));

384
    return viewer;
385
386
}

hjk's avatar
hjk committed
387
388
void HelpPlugin::activateHelpMode()
{
389
    ModeManager::activateMode(Id(Constants::ID_MODE_HELP));
hjk's avatar
hjk committed
390
391
}

392
void HelpPlugin::showLinkInHelpMode(const QUrl &source)
con's avatar
con committed
393
{
hjk's avatar
hjk committed
394
    activateHelpMode();
395
    Core::ICore::raiseWindow(m_mode->widget());
con's avatar
con committed
396
397
398
399
    m_centralWidget->setSource(source);
    m_centralWidget->setFocus();
}

400
401
402
403
404
405
406
void HelpPlugin::showLinksInHelpMode(const QMap<QString, QUrl> &links, const QString &key)
{
    activateHelpMode();
    Core::ICore::raiseWindow(m_mode->widget());
    m_centralWidget->showTopicChooser(links, key);
}

con's avatar
con committed
407
408
void HelpPlugin::slotHideRightPane()
{
409
    RightPaneWidget::instance()->setShown(false);
con's avatar
con committed
410
411
}

412
void HelpPlugin::modeChanged(IMode *mode, IMode *old)
con's avatar
con committed
413
{
414
    Q_UNUSED(old)
415
    if (mode == m_mode) {
416
        qApp->setOverrideCursor(Qt::WaitCursor);
kh1's avatar
kh1 committed
417
        doSetupIfNeeded();
con's avatar
con committed
418
419
420
421
        qApp->restoreOverrideCursor();
    }
}

422
423
void HelpPlugin::updateSideBarSource()
{
424
    if (HelpViewer *viewer = m_centralWidget->currentViewer()) {
425
426
427
428
        const QUrl &url = viewer->source();
        if (url.isValid())
            updateSideBarSource(url);
    }
429
430
431
432
}

void HelpPlugin::updateSideBarSource(const QUrl &newUrl)
{
433
434
435
436
437
438
439
    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));
    }
440
441
}

442
443
void HelpPlugin::fontChanged()
{
444
    if (!m_rightPaneSideBarWidget)
445
        createRightPaneContextViewer();
446

447
448
    QVariant fontSetting = LocalHelpManager::engineFontSettings();
    QFont font = fontSetting.isValid() ? fontSetting.value<QFont>()
449
                                       : m_rightPaneSideBarWidget->currentViewer()->viewerFont();
450

451
    m_rightPaneSideBarWidget->setViewerFont(font);
452
    m_centralWidget->setViewerFont(font);
453
454
}

455
456
void HelpPlugin::setupHelpEngineIfNeeded()
{
457
    LocalHelpManager::setEngineNeedsUpdate();
458
    if (ModeManager::currentMode() == m_mode
459
460
            || contextHelpOption() == Core::HelpManager::ExternalHelpAlways)
        LocalHelpManager::setupGuiHelpEngine();
461
462
}

463
bool HelpPlugin::canShowHelpSideBySide() const
con's avatar
con committed
464
{
465
    RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    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(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();
491

492
    if (actualLocation == Core::HelpManager::SideBySideAlways) {
493
        createRightPaneContextViewer();
494
        RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget);
495
        RightPaneWidget::instance()->setShown(true);
496
        return m_rightPaneSideBarWidget->currentViewer();
kh's avatar
kh committed
497
    }
498

499
500
    QTC_CHECK(actualLocation == Core::HelpManager::HelpModeAlways);

501
    activateHelpMode(); // should trigger an createPage...
502
    HelpViewer *viewer = m_centralWidget->currentViewer();
503
504
    if (!viewer)
        viewer = OpenPagesManager::instance().createPage();
505
506
507
    return viewer;
}

508
509
510
511
512
HelpViewer *HelpPlugin::viewerForContextHelp()
{
    return viewerForHelpViewerLocation(contextHelpOption());
}

513
514
515
516
517
518
static QUrl findBestLink(const QMap<QString, QUrl> &links, QString *highlightId)
{
    if (highlightId)
        highlightId->clear();
    if (links.isEmpty())
        return QUrl();
519
    QUrl source = links.constBegin().value();
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
    // 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;
}

541
void HelpPlugin::showContextHelp()
542
{
543
    if (ModeManager::currentMode() == m_mode)
544
545
546
        return;

    // Find out what to show
547
    QMap<QString, QUrl> links;
548
    QString idFromContext;
hjk's avatar
hjk committed
549
    if (IContext *context = Core::ICore::currentContextObject()) {
550
551
        idFromContext = context->contextHelpId();
        links = HelpManager::linksForIdentifier(idFromContext);
552
        // Maybe the id is already an URL
553
554
        if (links.isEmpty() && LocalHelpManager::isValidUrl(idFromContext))
            links.insert(idFromContext, idFromContext);
555
556
    }

557
    if (HelpViewer *viewer = viewerForContextHelp()) {
558
559
        QUrl source = findBestLink(links, &m_contextHelpHighlightId);
        if (!source.isValid()) {
kh's avatar
kh committed
560
            // No link found or no context object
561
            viewer->setSource(QUrl(Help::Constants::AboutBlank));
kh's avatar
kh committed
562
            viewer->setHtml(tr("<html><head><title>No Documentation</title>"
563
564
565
566
567
568
569
                "</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(idFromContext)
                .arg(creatorTheme()->color(Theme::TextColorNormal).name()));
kh's avatar
kh committed
570
        } else {
571
572
573
            const QUrl &oldSource = viewer->source();
            if (source != oldSource) {
                viewer->stop();
574
                viewer->setSource(source); // triggers loadFinished which triggers id highlighting
575
            } else {
576
                viewer->scrollToAnchor(source.fragment());
577
            }
578
            viewer->setFocus();
579
            Core::ICore::raiseWindow(viewer);
con's avatar
con committed
580
581
582
583
584
585
        }
    }
}

void HelpPlugin::activateIndex()
{
hjk's avatar
hjk committed
586
    activateHelpMode();
587
    m_centralWidget->activateSideBarItem(QLatin1String(Constants::HELP_INDEX));
con's avatar
con committed
588
589
590
591
}

void HelpPlugin::activateContents()
{
hjk's avatar
hjk committed
592
    activateHelpMode();
593
    m_centralWidget->activateSideBarItem(QLatin1String(Constants::HELP_CONTENTS));
kh1's avatar
kh1 committed
594
595
}

596
void HelpPlugin::highlightSearchTermsInContextHelp()
597
{
598
599
    if (m_contextHelpHighlightId.isEmpty())
        return;
600
    HelpViewer *viewer = viewerForContextHelp();
601
602
603
    QTC_ASSERT(viewer, return);
    viewer->highlightId(m_contextHelpHighlightId);
    m_contextHelpHighlightId.clear();
604
605
}

606
void HelpPlugin::handleHelpRequest(const QUrl &url, Core::HelpManager::HelpViewerLocation location)
con's avatar
con committed
607
{
kh1's avatar
kh1 committed
608
    if (HelpViewer::launchWithExternalApp(url))
609
610
        return;

611
    QString address = url.toString();
612
    if (!HelpManager::findFile(url).isValid()) {
613
614
        if (address.startsWith(QLatin1String("qthelp://org.qt-project."))
            || address.startsWith(QLatin1String("qthelp://com.nokia."))
hjk's avatar
hjk committed
615
            || address.startsWith(QLatin1String("qthelp://com.trolltech."))) {
kh1's avatar
kh1 committed
616
                // local help not installed, resort to external web help
617
                QString urlPrefix = QLatin1String("http://qt-project.org/doc/");
618
                if (url.authority() == QLatin1String("org.qt-project.qtcreator"))
619
                    urlPrefix.append(QString::fromLatin1("qtcreator"));
620
                else
kh1's avatar
kh1 committed
621
622
                    urlPrefix.append(QLatin1String("latest"));
            address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
623
        }
624
625
626
    }

    const QUrl newUrl(address);
627
628
629
630
    HelpViewer *viewer = viewerForHelpViewerLocation(location);
    QTC_ASSERT(viewer, return);
    viewer->setSource(newUrl);
    Core::ICore::raiseWindow(viewer);
631
}
con's avatar
con committed
632

633
634
void HelpPlugin::slotOpenSupportPage()
{
635
    showLinkInHelpMode(QUrl(QLatin1String("qthelp://org.qt-project.qtcreator/doc/technical-support.html")));
636
637
}

638
639
void HelpPlugin::slotReportBug()
{
640
    QDesktopServices::openUrl(QUrl(QLatin1String("https://bugreports.qt-project.org")));
641
642
}

kh1's avatar
kh1 committed
643
void HelpPlugin::doSetupIfNeeded()
644
{
645
    LocalHelpManager::setupGuiHelpEngine();
646
    if (m_setupNeeded) {
647
648
        qApp->processEvents();
        resetFilter();
649
        m_setupNeeded = false;
650
651
652
653
        OpenPagesManager::instance().setupInitialPages();
    }
}

654
Core::HelpManager::HelpViewerLocation HelpPlugin::contextHelpOption() const
655
{
hjk's avatar
hjk committed
656
    QSettings *settings = Core::ICore::settings();
657
    const QString key = QLatin1String(Help::Constants::ID_MODE_HELP) + QLatin1String("/ContextHelpOption");
658
    if (settings->contains(key))
659
660
        return Core::HelpManager::HelpViewerLocation(
                    settings->value(key, Core::HelpManager::SideBySideIfPossible).toInt());
661

662
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
663
664
    return Core::HelpManager::HelpViewerLocation(engine.customValue(QLatin1String("ContextHelpOption"),
        Core::HelpManager::SideBySideIfPossible).toInt());
665
}