helpplugin.cpp 47.1 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
13
14
** 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
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** 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
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29

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

#include "centralwidget.h"
con's avatar
con committed
33
#include "docsettingspage.h"
34
#include "externalhelpwindow.h"
con's avatar
con committed
35
#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>
kh1's avatar
kh1 committed
69
#include <coreplugin/helpmanager.h>
hjk's avatar
hjk committed
70
71
72
73
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/rightpane.h>
#include <coreplugin/sidebar.h>
kh1's avatar
kh1 committed
74
#include <extensionsystem/pluginmanager.h>
75
#include <coreplugin/find/findplugin.h>
76
#include <texteditor/texteditorconstants.h>
77
#include <utils/hostosinfo.h>
78
79
#include <utils/styledbar.h>

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

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

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

using namespace Help::Internal;

99
100
101
102
const char SB_INDEX[] = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index");
const char SB_CONTENTS[] = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Contents");
const char SB_BOOKMARKS[] = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Bookmarks");
const char SB_SEARCH[] = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Search");
103

104
const char SB_OPENPAGES[] = "OpenPages";
105

106
#define IMAGEPATH ":/help/images/"
107

108
109
110
111
112
113
114
115
using namespace Core;

static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    button->setPopupMode(QToolButton::DelayedPopup);
    return button;
116
117
}

kh1's avatar
kh1 committed
118
HelpPlugin::HelpPlugin()
119
    : m_mode(0),
con's avatar
con committed
120
    m_centralWidget(0),
121
    m_rightPaneSideBarWidget(0),
con's avatar
con committed
122
123
124
125
126
    m_helpViewerForSideBar(0),
    m_contentItem(0),
    m_indexItem(0),
    m_searchItem(0),
    m_bookmarkItem(0),
127
    m_sideBar(0),
128
    m_firstModeChange(true),
129
130
    m_helpManager(0),
    m_openPagesManager(0),
131
132
    m_oldMode(0),
    m_connectWindow(true),
133
134
    m_externalWindow(0),
    m_backMenu(0),
135
136
    m_nextMenu(0),
    m_isSidebarVisible(true)
con's avatar
con committed
137
138
139
140
141
{
}

HelpPlugin::~HelpPlugin()
{
142
143
    delete m_centralWidget;
    delete m_openPagesManager;
144
    delete m_rightPaneSideBarWidget;
145
146

    delete m_helpManager;
con's avatar
con committed
147
148
}

149
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
con's avatar
con committed
150
{
151
152
    Q_UNUSED(arguments)
    Q_UNUSED(error)
153
154
    Context globalcontext(Core::Constants::C_GLOBAL);
    Context modecontext(Constants::C_MODE_HELP);
con's avatar
con committed
155

156
    const QString &locale = ICore::userInterfaceLanguage();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
157
158
    if (!locale.isEmpty()) {
        QTranslator *qtr = new QTranslator(this);
159
        QTranslator *qhelptr = new QTranslator(this);
160
        const QString &creatorTrPath = ICore::resourcePath()
161
            + QLatin1String("/translations");
162
163
164
165
166
167
168
        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
169
170
    }

171
172
    m_helpManager = new LocalHelpManager(this);
    m_openPagesManager = new OpenPagesManager(this);
173
174
    addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
    addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
175
    addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage());
176
    addAutoReleasedObject(m_searchTaskHandler = new SearchTaskHandler);
177

178
179
    connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
        SLOT(fontChanged()));
180
181
    connect(m_generalSettingsPage, SIGNAL(contextHelpOptionChanged()), this,
        SLOT(contextHelpOptionChanged()));
182
183
    connect(m_generalSettingsPage, SIGNAL(returnOnCloseChanged()), this,
        SLOT(updateCloseButton()));
184
    connect(HelpManager::instance(), SIGNAL(helpRequested(QUrl)), this,
kh1's avatar
kh1 committed
185
        SLOT(handleHelpRequest(QUrl)));
186
187
    connect(m_searchTaskHandler, SIGNAL(search(QUrl)), this,
            SLOT(switchToHelpMode(QUrl)));
188

189
190
    connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
        SLOT(setupHelpEngineIfNeeded()));
191
    connect(HelpManager::instance(), SIGNAL(documentationChanged()), this,
192
        SLOT(setupHelpEngineIfNeeded()));
193
    connect(HelpManager::instance(), SIGNAL(collectionFileChanged()), this,
194
        SLOT(setupHelpEngineIfNeeded()));
195
    connect(HelpManager::instance(), SIGNAL(setupFinished()), this,
196
            SLOT(unregisterOldQtCreatorDocumentation()));
con's avatar
con committed
197

198
    m_splitter = new MiniSplitter;
199
    m_centralWidget = new Help::Internal::CentralWidget();
200
201
    connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
        SLOT(updateSideBarSource(QUrl)));
con's avatar
con committed
202
    // Add Home, Previous and Next actions (used in the toolbar)
203
204
    QAction *action = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")),
        tr("Home"), this);
205
    ActionManager::registerAction(action, "Help.Home", globalcontext);
206
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
con's avatar
con committed
207

208
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
209
        tr("Previous Page"), this);
210
    Command *cmd = ActionManager::registerAction(action, "Help.Previous", modecontext);
211
    cmd->setDefaultKeySequence(QKeySequence::Back);
212
213
214
215
    action->setEnabled(m_centralWidget->isBackwardAvailable());
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(backward()));
    connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), action,
        SLOT(setEnabled(bool)));
con's avatar
con committed
216

217
218
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next Page"), this);
    cmd = ActionManager::registerAction(action, "Help.Next", modecontext);
219
    cmd->setDefaultKeySequence(QKeySequence::Forward);
220
221
222
223
    action->setEnabled(m_centralWidget->isForwardAvailable());
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(forward()));
    connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), action,
        SLOT(setEnabled(bool)));
con's avatar
con committed
224

225
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")),
con's avatar
con committed
226
        tr("Add Bookmark"), this);
227
228
    cmd = ActionManager::registerAction(action, "Help.AddBookmark", modecontext);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+M") : tr("Ctrl+M")));
229
    connect(action, SIGNAL(triggered()), this, SLOT(addBookmark()));
con's avatar
con committed
230

231
    // Add Contents, Index, and Context menu items
232
233
    action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")),
        tr(SB_CONTENTS), this);
234
235
    cmd = ActionManager::registerAction(action, "Help.Contents", globalcontext);
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
236
237
    connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));

238
    action = new QAction(tr(SB_INDEX), this);
239
240
    cmd = ActionManager::registerAction(action, "Help.Index", globalcontext);
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
241
242
243
    connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));

    action = new QAction(tr("Context Help"), this);
244
245
    cmd = ActionManager::registerAction(action, "Help.Context", globalcontext);
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
con's avatar
con committed
246
    cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
247
    connect(action, SIGNAL(triggered()), this, SLOT(activateContext()));
con's avatar
con committed
248

249
    action = new QAction(tr("Technical Support"), this);
250
    cmd = ActionManager::registerAction(action, "Help.TechSupport", globalcontext);
251
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
252
253
    connect(action, SIGNAL(triggered()), this, SLOT(slotOpenSupportPage()));

254
    action = new QAction(tr("Report Bug..."), this);
255
    cmd = ActionManager::registerAction(action, "Help.ReportBug", globalcontext);
256
    ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
257
258
    connect(action, SIGNAL(triggered()), this, SLOT(slotReportBug()));

259
    action = new QAction(this);
260
    ActionManager::registerAction(action, Core::Constants::PRINT, modecontext);
261
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(print()));
con's avatar
con committed
262

263
    action = new QAction(this);
264
    cmd = ActionManager::registerAction(action, Core::Constants::COPY, modecontext);
265
266
267
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(copy()));
    action->setText(cmd->action()->text());
    action->setIcon(cmd->action()->icon());
268

269
    if (ActionContainer *advancedMenu = ActionManager::actionContainer(Core::Constants::M_EDIT_ADVANCED)) {
270
        // reuse TextEditor constants to avoid a second pair of menu actions
271
        action = new QAction(tr("Increase Font Size"), this);
272
        cmd = ActionManager::registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE, modecontext);
273
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomIn()));
274
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
275

276
        action = new QAction(tr("Decrease Font Size"), this);
277
        cmd = ActionManager::registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE, modecontext);
278
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomOut()));
279
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
280

281
        action = new QAction(tr("Reset Font Size"), this);
282
        cmd = ActionManager::registerAction(action, TextEditor::Constants::RESET_FONT_SIZE, modecontext);
283
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(resetZoom()));
284
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
285
286
    }

287
    if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) {
288
        // reuse EditorManager constants to avoid a second pair of menu actions
289
        // Goto Previous In History Action
Jarek Kobus's avatar
Jarek Kobus committed
290
        action = new QAction(this);
291
292
        Command *ctrlTab = ActionManager::registerAction(action, Core::Constants::GOTOPREVINHISTORY,
            modecontext);
293
294
295
296
        windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoPreviousPage()));

297
        // Goto Next In History Action
Jarek Kobus's avatar
Jarek Kobus committed
298
        action = new QAction(this);
299
300
        Command *ctrlShiftTab = ActionManager::registerAction(action, Core::Constants::GOTONEXTINHISTORY,
            modecontext);
301
302
303
304
305
        windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoNextPage()));
    }

306
307
308
    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
    agg->add(m_centralWidget);
    agg->add(new HelpFindSupport(m_centralWidget));
309
310
311
312
313
314
315
316
317

    QWidget *toolBarWidget = new QWidget;
    QHBoxLayout *toolBarLayout = new QHBoxLayout(toolBarWidget);
    toolBarLayout->setMargin(0);
    toolBarLayout->setSpacing(0);
    toolBarLayout->addWidget(m_externalHelpBar = createIconToolBar(true));
    toolBarLayout->addWidget(m_internalHelpBar = createIconToolBar(false));
    toolBarLayout->addWidget(createWidgetToolBar());

kh1's avatar
kh1 committed
318
319
320
    QWidget *mainWidget = new QWidget;
    m_splitter->addWidget(mainWidget);
    QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget);
321
322
    mainWidgetLayout->setMargin(0);
    mainWidgetLayout->setSpacing(0);
323
    mainWidgetLayout->addWidget(toolBarWidget);
324
325
    mainWidgetLayout->addWidget(m_centralWidget);

326
327
    if (QLayout *layout = m_centralWidget->layout()) {
        layout->setSpacing(0);
328
        FindToolBarPlaceHolder *fth = new FindToolBarPlaceHolder(m_centralWidget);
329
        fth->setObjectName(QLatin1String("HelpFindToolBarPlaceHolder"));
330
        mainWidgetLayout->addWidget(fth);
331
332
    }

333
334
335
336
337
    HelpIndexFilter *helpIndexFilter = new HelpIndexFilter();
    addAutoReleasedObject(helpIndexFilter);
    connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)), this,
        SLOT(switchToHelpMode(QUrl)));

kh1's avatar
kh1 committed
338
339
340
341
342
    RemoteHelpFilter *remoteHelpFilter = new RemoteHelpFilter();
    addAutoReleasedObject(remoteHelpFilter);
    connect(remoteHelpFilter, SIGNAL(linkActivated(QUrl)), this,
        SLOT(switchToHelpMode(QUrl)));

343
    QDesktopServices::setUrlHandler(QLatin1String("qthelp"), this, "handleHelpRequest");
344
345
    connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*,Core::IMode*)),
            this, SLOT(modeChanged(Core::IMode*,Core::IMode*)));
346

347
    m_externalWindow = new ExternalHelpWindow;
348
    m_mode = new HelpMode;
349
    if (contextHelpOption() == Help::Constants::ExternalHelpAlways) {
350
        m_mode->setWidget(new QWidget);
351
        m_mode->setEnabled(false);
kh1's avatar
kh1 committed
352
        m_externalHelpBar->setVisible(true);
353
354
355
        m_externalWindow->setCentralWidget(m_splitter);
        QTimer::singleShot(0, this, SLOT(showExternalWindow()));
    } else {
356
        m_mode->setWidget(m_splitter);
kh1's avatar
kh1 committed
357
        m_internalHelpBar->setVisible(true);
358
359
    }
    addAutoReleasedObject(m_mode);
360

con's avatar
con committed
361
362
363
    return true;
}

364
void HelpPlugin::extensionsInitialized()
365
{
366
367
    QStringList filesToRegister;
    // we might need to register creators inbuild help
368
    filesToRegister.append(ICore::documentationPath() + QLatin1String("/qtcreator.qch"));
369
    HelpManager::registerDocumentation(filesToRegister);
370
371
}

372
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
373
{
374
    if (m_sideBar) {
375
        QSettings *settings = ICore::settings();
376
377
378
379
380
        m_sideBar->saveSettings(settings, QLatin1String("HelpSideBar"));
        // keep a boolean value to avoid to modify the sidebar class, at least some qml stuff
        // depends on the always visible property of the sidebar...
        settings->setValue(QLatin1String("HelpSideBar/") + QLatin1String("Visible"), m_isSidebarVisible);
    }
kh1's avatar
kh1 committed
381
382
383
384
385
386

    if (m_externalWindow) {
        delete m_externalWindow;
        m_centralWidget = 0; // Running the external window will take down the central widget as well, cause
            // calling m_externalWindow->setCentralWidget(m_centralWidget) will pass ownership to the window.
    }
387

388
    return SynchronousShutdown;
389
390
}

391
392
void HelpPlugin::unregisterOldQtCreatorDocumentation()
{
393
    const QString &nsInternal = QString::fromLatin1("org.qt-project.qtcreator.%1%2%3")
394
395
396
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);

    QStringList documentationToUnregister;
397
    foreach (const QString &ns, HelpManager::registeredNamespaces()) {
398
        if (ns.startsWith(QLatin1String("org.qt-project.qtcreator."))
399
400
401
402
403
                && ns != nsInternal) {
            documentationToUnregister << ns;
        }
    }
    if (!documentationToUnregister.isEmpty())
404
        HelpManager::unregisterDocumentation(documentationToUnregister);
405
406
}

407
void HelpPlugin::setupUi()
408
{
409
    // side bar widgets and shortcuts
410
    Context modecontext(Constants::C_MODE_HELP);
411
412

    IndexWindow *indexWindow = new IndexWindow();
413
    indexWindow->setWindowTitle(tr(SB_INDEX));
414
    m_indexItem = new SideBarItem(indexWindow, QLatin1String(SB_INDEX));
415
416
417

    connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
Robert Loehning's avatar
Robert Loehning committed
418
419
    connect(indexWindow, SIGNAL(linksActivated(QMap<QString,QUrl>,QString)),
        m_centralWidget, SLOT(showTopicChooser(QMap<QString,QUrl>,QString)));
420

421
    QMap<QString, Command*> shortcutMap;
422
423
    QAction *action = new QAction(tr("Activate Index in Help mode"), m_splitter);
    Command *cmd = ActionManager::registerAction(action, "Help.IndexShortcut", modecontext);
424
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+I") : tr("Ctrl+Shift+I")));
425
    connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));
426
    shortcutMap.insert(QLatin1String(SB_INDEX), cmd);
427
428

    ContentWindow *contentWindow = new ContentWindow();
429
    contentWindow->setWindowTitle(tr(SB_CONTENTS));
430
    m_contentItem = new SideBarItem(contentWindow, QLatin1String(SB_CONTENTS));
431
432
    connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
433

434
435
    action = new QAction(tr("Activate Contents in Help mode"), m_splitter);
    cmd = ActionManager::registerAction(action, "Help.ContentsShortcut", modecontext);
436
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+Shift+C") : tr("Ctrl+Shift+C")));
437
    connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));
438
    shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd);
439
440

    SearchWidget *searchWidget = new SearchWidget();
441
    searchWidget->setWindowTitle(tr(SB_SEARCH));
442
    m_searchItem = new SideBarItem(searchWidget, QLatin1String(SB_SEARCH));
443
444
    connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSourceFromSearch(QUrl)));
445

446
447
     action = new QAction(tr("Activate Search in Help mode"), m_splitter);
     cmd = ActionManager::registerAction(action, "Help.SearchShortcut", modecontext);
448
     cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+/") : tr("Ctrl+Shift+/")));
449
     connect(action, SIGNAL(triggered()), this, SLOT(activateSearch()));
con's avatar
con committed
450
     shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
451

kh1's avatar
kh1 committed
452
    BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
453
    BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
454
    bookmarkWidget->setWindowTitle(tr(SB_BOOKMARKS));
455
    m_bookmarkItem = new SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS));
456
457
    connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
458
459
    connect(bookmarkWidget, SIGNAL(createPage(QUrl,bool)), &OpenPagesManager::instance(),
            SLOT(createPage(QUrl,bool)));
460

461
462
     action = new QAction(tr("Activate Bookmarks in Help mode"), m_splitter);
     cmd = ActionManager::registerAction(action, "Help.BookmarkShortcut", modecontext);
463
     cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+B") : tr("Ctrl+Shift+B")));
464
     connect(action, SIGNAL(triggered()), this, SLOT(activateBookmarks()));
con's avatar
con committed
465
     shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
466

467
468
    QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
    openPagesWidget->setWindowTitle(tr("Open Pages"));
469
    m_openPagesItem = new SideBarItem(openPagesWidget, QLatin1String(SB_OPENPAGES));
470

471
472
    action = new QAction(tr("Activate Open Pages in Help mode"), m_splitter);
    cmd = ActionManager::registerAction(action, "Help.PagesShortcut", modecontext);
473
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+O") : tr("Ctrl+Shift+O")));
474
    connect(action, SIGNAL(triggered()), this, SLOT(activateOpenPages()));
475
    shortcutMap.insert(QLatin1String(SB_OPENPAGES), cmd);
476

477
    QList<SideBarItem*> itemList;
478
479
    itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem
        << m_openPagesItem;
480
    m_sideBar = new SideBar(itemList, QList<SideBarItem*>()
kh1's avatar
kh1 committed
481
        << m_contentItem << m_openPagesItem);
482
    m_sideBar->setCloseWhenEmpty(true);
483
    m_sideBar->setShortcutMap(shortcutMap);
484
    connect(m_sideBar, SIGNAL(sideBarClosed()), this, SLOT(onSideBarVisibilityChanged()));
485
486

    m_splitter->setOpaqueResize(false);
con's avatar
con committed
487
    m_splitter->insertWidget(0, m_sideBar);
488
489
    m_splitter->setStretchFactor(0, 0);
    m_splitter->setStretchFactor(1, 1);
490
    m_sideBar->readSettings(ICore::settings(), QLatin1String("HelpSideBar"));
491
    m_splitter->setSizes(QList<int>() << m_sideBar->size().width() << 300);
492
493
494
495
496

    m_toggleSideBarAction = new QAction(QIcon(QLatin1String(Core::Constants::ICON_TOGGLE_SIDEBAR)),
        tr("Show Sidebar"), this);
    m_toggleSideBarAction->setCheckable(true);
    connect(m_toggleSideBarAction, SIGNAL(triggered(bool)), this, SLOT(showHideSidebar()));
497
    cmd = ActionManager::registerAction(m_toggleSideBarAction, Core::Constants::TOGGLE_SIDEBAR, modecontext);
498
499
}

kh1's avatar
kh1 committed
500
501
void HelpPlugin::resetFilter()
{
kh1's avatar
kh1 committed
502
503
    const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
504
    QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*"));
kh1's avatar
kh1 committed
505
506
507
508
509
510
511
512

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

513
514
515
516
    // 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();
517
        if (!filter.isEmpty())
kh1's avatar
kh1 committed
518
            engine->removeCustomFilter(filter);
kh1's avatar
kh1 committed
519
520
521
522
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
kh1's avatar
kh1 committed
523
524
    engine->removeCustomFilter(filterName);
    engine->addCustomFilter(filterName, QStringList());
525
526
    engine->setCustomValue(Help::Constants::WeAddedFilterKey, 1);
    engine->setCustomValue(Help::Constants::PreviousFilterNameKey, filterName);
kh1's avatar
kh1 committed
527
528
529
530
    engine->setCurrentFilter(filterName);

    updateFilterComboBox();
    connect(engine, SIGNAL(setupFinished()), this, SLOT(updateFilterComboBox()));
531
532
}

533
void HelpPlugin::createRightPaneContextViewer()
con's avatar
con committed
534
{
535
    if (m_rightPaneSideBarWidget)
536
        return;
con's avatar
con committed
537

538
    Utils::StyledBar *toolBar = new Utils::StyledBar();
con's avatar
con committed
539

540
541
    QAction *switchToHelp = new QAction(tr("Go to Help Mode"), toolBar);
    connect(switchToHelp, SIGNAL(triggered()), this, SLOT(switchToHelpMode()));
542
    QAction *back = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
543
        tr("Previous"), toolBar);
544
    QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
545
        tr("Next"), toolBar);
546
    QAction *close = new QAction(QIcon(QLatin1String(Core::Constants::ICON_CLOSE_DOCUMENT)),
547
548
        QLatin1String(""), toolBar);
    connect(close, SIGNAL(triggered()), this, SLOT(slotHideRightPane()));
549

550
    setupNavigationMenus(back, next, toolBar);
con's avatar
con committed
551

552
553
554
    QHBoxLayout *layout = new QHBoxLayout(toolBar);
    layout->setSpacing(0);
    layout->setMargin(0);
555

556
557
558
559
560
    layout->addWidget(toolButton(switchToHelp));
    layout->addWidget(toolButton(back));
    layout->addWidget(toolButton(next));
    layout->addStretch();
    layout->addWidget(toolButton(close));
con's avatar
con committed
561

562
    m_rightPaneSideBarWidget = new QWidget;
563
564
    m_helpViewerForSideBar = createHelpViewer(qreal(0.0));
    m_helpViewerForSideBar->setOpenInNewWindowActionVisible(false);
565

566
    QVBoxLayout *rightPaneLayout = new QVBoxLayout(m_rightPaneSideBarWidget);
567
568
569
    rightPaneLayout->setMargin(0);
    rightPaneLayout->setSpacing(0);
    rightPaneLayout->addWidget(toolBar);
570
    rightPaneLayout->addWidget(m_helpViewerForSideBar);
571
    FindToolBarPlaceHolder *fth = new FindToolBarPlaceHolder(m_rightPaneSideBarWidget);
572
573
574
    fth->setObjectName(QLatin1String("HelpRightPaneFindToolBarPlaceHolder"));
    rightPaneLayout->addWidget(fth);
    m_rightPaneSideBarWidget->setFocusProxy(m_helpViewerForSideBar);
575

con's avatar
con committed
576
577
578
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(m_helpViewerForSideBar);
    agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
579

580
581
    Context context(Constants::C_HELP_SIDEBAR);
    IContext *icontext = new IContext(this);
582
583
    icontext->setContext(context);
    icontext->setWidget(m_helpViewerForSideBar);
584
    ICore::addContextObject(icontext);
585

586
    QAction *copy = new QAction(this);
587
    Command *cmd = ActionManager::registerAction(copy, Core::Constants::COPY, context);
588
589
590
    copy->setText(cmd->action()->text());
    copy->setIcon(cmd->action()->icon());
    connect(copy, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(copy()));
591

592
    next->setEnabled(m_helpViewerForSideBar->isForwardAvailable());
593
    connect(next, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(forward()));
594
595
    connect(m_helpViewerForSideBar, SIGNAL(forwardAvailable(bool)), next,
        SLOT(setEnabled(bool)));
596

597
598
599
600
    back->setEnabled(m_helpViewerForSideBar->isBackwardAvailable());
    connect(back, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(backward()));
    connect(m_helpViewerForSideBar, SIGNAL(backwardAvailable(bool)), back,
        SLOT(setEnabled(bool)));
kh1's avatar
kh1 committed
601

602
    if (ActionContainer *advancedMenu = ActionManager::actionContainer(Core::Constants::M_EDIT_ADVANCED)) {
603
604
        // reuse TextEditor constants to avoid a second pair of menu actions
        QAction *action = new QAction(tr("Increase Font Size"), this);
605
        cmd = ActionManager::registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE, context);
606
607
608
609
        connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneUp()));
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);

        action = new QAction(tr("Decrease Font Size"), this);
610
        cmd = ActionManager::registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE, context);
611
612
613
614
        connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneDown()));
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);

        action = new QAction(tr("Reset Font Size"), this);
615
        cmd = ActionManager::registerAction(action, TextEditor::Constants::RESET_FONT_SIZE, context);
616
617
618
619
        connect(action, SIGNAL(triggered()), this, SLOT(resetRightPaneScale()));
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
    }

kh1's avatar
kh1 committed
620
621
622
    // force setup, as we might have never switched to full help mode
    // thus the help engine might still run without collection file setup
    m_helpManager->setupGuiHelpEngine();
con's avatar
con committed
623
624
}

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
void HelpPlugin::scaleRightPaneUp()
{
    if (m_helpViewerForSideBar)
        m_helpViewerForSideBar->scaleUp();
}

void HelpPlugin::scaleRightPaneDown()
{
    if (m_helpViewerForSideBar)
        m_helpViewerForSideBar->scaleDown();
}

void HelpPlugin::resetRightPaneScale()
{
    if (m_helpViewerForSideBar)
        m_helpViewerForSideBar->resetScale();
}

643
644
HelpViewer *HelpPlugin::createHelpViewer(qreal zoom)
{
645
646
647
648
649
650
651
652
653
    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);
#endif
    } else if (backend.compare(QLatin1String("textbrowser"), Qt::CaseInsensitive) == 0) {
        viewer = new TextBrowserHelpViewer(zoom);
    } else {
654
#ifndef QT_NO_WEBKIT
655
        viewer = new QtWebKitHelpViewer(zoom);
656
#else
657
        viewer = new TextBrowserHelpViewer(zoom);
658
#endif
659
660
661
662
663
664
665
    }

    // initialize font
    QVariant fontSetting = LocalHelpManager::engineFontSettings();
    if (fontSetting.isValid())
        viewer->setViewerFont(fontSetting.value<QFont>());
    return viewer;
666
667
}

hjk's avatar
hjk committed
668
669
void HelpPlugin::activateHelpMode()
{
670
    if (contextHelpOption() != Help::Constants::ExternalHelpAlways)
671
        ModeManager::activateMode(Id(Constants::ID_MODE_HELP));
672
673
    else
        showExternalWindow();
hjk's avatar
hjk committed
674
675
}

con's avatar
con committed
676
677
678
679
680
681
682
void HelpPlugin::switchToHelpMode()
{
    switchToHelpMode(m_helpViewerForSideBar->source());
}

void HelpPlugin::switchToHelpMode(const QUrl &source)
{
hjk's avatar
hjk committed
683
    activateHelpMode();
con's avatar
con committed
684
685
686
687
688
689
    m_centralWidget->setSource(source);
    m_centralWidget->setFocus();
}

void HelpPlugin::slotHideRightPane()
{
690
    RightPaneWidget::instance()->setShown(false);
con's avatar
con committed
691
692
}

693
694
695
void HelpPlugin::showHideSidebar()
{
    m_sideBar->setVisible(!m_sideBar->isVisible());
696
    onSideBarVisibilityChanged();
697
698
}

699
700
void HelpPlugin::showExternalWindow()
{
701
    bool firstTime = m_firstModeChange;
kh1's avatar
kh1 committed
702
    doSetupIfNeeded();
703
    m_externalWindow->show();
704
705
    connectExternalHelpWindow();
    if (firstTime)
706
        ICore::raiseWindow(ICore::mainWindow());
707
    else
708
        ICore::raiseWindow(m_externalWindow);
709
710
}

711
void HelpPlugin::modeChanged(IMode *mode, IMode *old)
con's avatar
con committed
712
{
713
    if (mode == m_mode) {
714
        m_oldMode = old;
715
        qApp->setOverrideCursor(Qt::WaitCursor);
kh1's avatar
kh1 committed
716
        doSetupIfNeeded();
con's avatar
con committed
717
718
719
720
        qApp->restoreOverrideCursor();
    }
}

721
722
void HelpPlugin::updateSideBarSource()
{
723
724
725
726
727
    if (HelpViewer *viewer = m_centralWidget->currentHelpViewer()) {
        const QUrl &url = viewer->source();
        if (url.isValid())
            updateSideBarSource(url);
    }
728
729
730
731
732
733
734
735
}

void HelpPlugin::updateSideBarSource(const QUrl &newUrl)
{
    if (m_helpViewerForSideBar)
        m_helpViewerForSideBar->setSource(newUrl);
}

736
void HelpPlugin::updateCloseButton()
737
{
738
    const bool closeOnReturn = HelpManager::customValue(QLatin1String("ReturnOnClose"),
739
740
        false).toBool();
    m_closeButton->setEnabled((OpenPagesManager::instance().pageCount() > 1)
Orgad Shaneh's avatar
Orgad Shaneh committed
741
                              || closeOnReturn);
742
}
743

744
745
746
747
void HelpPlugin::fontChanged()
{
    if (!m_helpViewerForSideBar)
        createRightPaneContextViewer();
748

749
750
751
    QVariant fontSetting = LocalHelpManager::engineFontSettings();
    QFont font = fontSetting.isValid() ? fontSetting.value<QFont>()
                                       : m_helpViewerForSideBar->viewerFont();
752

753
    m_helpViewerForSideBar->setViewerFont(font);
754
755
756
757
    const int count = OpenPagesManager::instance().pageCount();
    for (int i = 0; i < count; ++i) {
        if (HelpViewer *viewer = CentralWidget::instance()->viewerAt(i))
            viewer->setViewerFont(font);
758
759
760
    }
}

761
762
763
764
765
766
767
768
769
770
771
772
773
QStackedLayout * layoutForWidget(QWidget *parent, QWidget *widget)
{
    QList<QStackedLayout*> list = parent->findChildren<QStackedLayout*>();
    foreach (QStackedLayout *layout, list) {
        const int index = layout->indexOf(widget);
        if (index >= 0)
            return layout;
    }
    return 0;
}

void HelpPlugin::contextHelpOptionChanged()
{
kh1's avatar
kh1 committed
774
    doSetupIfNeeded();
775
776
777
778
779
780
781
782
783
784
785
786
787
788
    QWidget *modeWidget = m_mode->widget();
    if (modeWidget == m_splitter
        && contextHelpOption() == Help::Constants::ExternalHelpAlways) {
        if (QWidget *widget = m_splitter->parentWidget()) {
            if (QStackedLayout *layout = layoutForWidget(widget, m_splitter)) {
                const int index = layout->indexOf(m_splitter);
                layout->removeWidget(m_splitter);
                m_mode->setWidget(new QWidget);
                layout->insertWidget(index, m_mode->widget());
                m_externalWindow->setCentralWidget(m_splitter);
                m_splitter->show();

                slotHideRightPane();
                m_mode->setEnabled(false);
789
790
                m_externalHelpBar->setVisible(true);
                m_internalHelpBar->setVisible(false);
791
                m_externalWindow->show();
792
793
                connectExternalHelpWindow();

794
795
                if (m_oldMode && m_mode == ModeManager::currentMode())
                    ModeManager::activateMode(m_oldMode->id());
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
            }
        }
    } else if (modeWidget != m_splitter
        && contextHelpOption() != Help::Constants::ExternalHelpAlways) {
        QStackedLayout *wLayout = layoutForWidget(modeWidget->parentWidget(),
            modeWidget);
        if (wLayout && m_splitter->parentWidget()->layout()) {
            const int index = wLayout->indexOf(modeWidget);
            QWidget *tmp = wLayout->widget(index);
            wLayout->removeWidget(modeWidget);
            delete tmp;

            m_splitter->parentWidget()->layout()->removeWidget(m_splitter);
            m_mode->setWidget(m_splitter);
            wLayout->insertWidget(index, m_splitter);

            m_mode->setEnabled(true);
            m_externalWindow->close();
814
            m_sideBar->setVisible(true);
815
816
            m_internalHelpBar->setVisible(true);
            m_externalHelpBar->setVisible(false);
817
818
819
820
        }
    }
}

821
822
void HelpPlugin::setupHelpEngineIfNeeded()
{
kh1's avatar
kh1 committed
823
    m_helpManager->setEngineNeedsUpdate();
824
    if (ModeManager::currentMode() == m_mode
825
        || contextHelpOption() == Help::Constants::ExternalHelpAlways)
826
827
828
        m_helpManager->setupGuiHelpEngine();
}

829
HelpViewer *HelpPlugin::viewerForContextMode()
con's avatar
con committed
830
{
831
832
    if (ModeManager::currentMode()->id() == Core::Constants::MODE_WELCOME)
        ModeManager::activateMode(Core::Constants::MODE_EDIT);
833

834
835
    bool showSideBySide = false;
    RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
836
837
    switch (contextHelpOption()) {
        case Help::Constants::SideBySideIfPossible: {
838
            // side by side if possible
hjk's avatar
hjk committed
839
            if (IEditor *editor = EditorManager::currentEditor()) {
840
                if (!placeHolder || !placeHolder->isVisible()) {
841
842
843
844
845
                    if (!editor->widget())
                        break;
                    if (!editor->widget()->isVisible())
                        break;
                    if (editor->widget()->width() < 800)
846
847
                        break;
                }
848
            }
849
        }   // fall through
850
        case Help::Constants::SideBySideAlways: {
851
852
853
            // side by side
            showSideBySide = true;
        }   break;
854

855
856
        default: // help mode
            break;
857