helpplugin.cpp 32.8 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** 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.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
29

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

#include "bookmarkmanager.h"
#include "centralwidget.h"
#include "contentwindow.h"
con's avatar
con committed
35
36
#include "docsettingspage.h"
#include "filtersettingspage.h"
37
#include "generalsettingspage.h"
kh1's avatar
kh1 committed
38
#include "helpconstants.h"
39
#include "helpfindsupport.h"
con's avatar
con committed
40
#include "helpindexfilter.h"
kh1's avatar
kh1 committed
41
#include "helpmanager.h"
con's avatar
con committed
42
43
44
#include "helpmode.h"
#include "helpviewer.h"
#include "indexwindow.h"
45
46
#include "openpagesmanager.h"
#include "openpagesmodel.h"
con's avatar
con committed
47
48
#include "searchwidget.h"

49
#include <coreplugin/actionmanager/actionmanager.h>
50
51
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
52
53
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
54
#include <coreplugin/editormanager/ieditor.h>
55
56
#include <coreplugin/findplaceholder.h>
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
57
58
59
60
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/rightpane.h>
#include <coreplugin/sidebar.h>
61
#include <coreplugin/uniqueidmanager.h>
kh1's avatar
kh1 committed
62
#include <extensionsystem/pluginmanager.h>
63
#include <texteditor/texteditorconstants.h>
64
#include <utils/styledbar.h>
kh1's avatar
kh1 committed
65
#include <welcome/welcomemode.h>
66

con's avatar
con committed
67
#include <QtCore/QDir>
kh1's avatar
kh1 committed
68
#include <QtCore/QFileInfo>
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
69
70
#include <QtCore/QLibraryInfo>
#include <QtCore/QTranslator>
kh1's avatar
kh1 committed
71
72
#include <QtCore/qplugin.h>

con's avatar
con committed
73
#include <QtGui/QAction>
kh1's avatar
kh1 committed
74
75
#include <QtGui/QComboBox>
#include <QtGui/QDesktopServices>
con's avatar
con committed
76
77
78
#include <QtGui/QShortcut>
#include <QtGui/QSplitter>
#include <QtGui/QToolBar>
kh1's avatar
kh1 committed
79

con's avatar
con committed
80
#include <QtHelp/QHelpEngine>
81
#include <QtHelp/QHelpEngineCore>
con's avatar
con committed
82

83
using namespace Core::Constants;
con's avatar
con committed
84
85
86
using namespace Help;
using namespace Help::Internal;

87
88
89
90
91
92
const char * const SB_INDEX = "Index";
const char * const SB_CONTENTS = "Contents";
const char * const SB_BOOKMARKS = "Bookmarks";
const char * const SB_SEARCH = "Search";
const char * const SB_OPENPAGES = "OpenPages";

93
#define IMAGEPATH ":/help/images/"
94
95
96
#if defined(Q_OS_MAC)
#   define DOCPATH "/../Resources/doc/"
#else
Tobias Hunger's avatar
Tobias Hunger committed
97
#   define DOCPATH "/../share/doc/qtcreator/"
98
99
#endif

kh1's avatar
kh1 committed
100
HelpPlugin::HelpPlugin()
101
102
    : m_mode(0),
    m_core(0),
con's avatar
con committed
103
104
105
106
107
108
    m_centralWidget(0),
    m_helpViewerForSideBar(0),
    m_contentItem(0),
    m_indexItem(0),
    m_searchItem(0),
    m_bookmarkItem(0),
109
110
    m_sideBar(0),
    m_firstModeChange(true)
con's avatar
con committed
111
112
113
114
115
116
117
{
}

HelpPlugin::~HelpPlugin()
{
}

118
bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
con's avatar
con committed
119
{
120
121
    Q_UNUSED(arguments)
    Q_UNUSED(error)
122
    m_core = Core::ICore::instance();
con's avatar
con committed
123
124
125
126
127
    QList<int> globalcontext;
    globalcontext << Core::Constants::C_GLOBAL_ID;
    QList<int> modecontext;
    modecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_MODE_HELP);

128
    const QString &locale = qApp->property("qtc_locale").toString();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
129
130
    if (!locale.isEmpty()) {
        QTranslator *qtr = new QTranslator(this);
131
        QTranslator *qhelptr = new QTranslator(this);
132
133
        const QString &creatorTrPath = Core::ICore::instance()->resourcePath()
            + 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
    addAutoReleasedObject(m_helpManager = new HelpManager(this));
144
145
    addAutoReleasedObject(m_openPagesManager = new OpenPagesManager(this));

146
147
    addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
    addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
148
    addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage());
149

150
151
    connect(m_docSettingsPage, SIGNAL(documentationChanged()), m_filterSettingsPage,
        SLOT(updateFilterPage()));
152
153
    connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
        SLOT(fontChanged()));
kh1's avatar
kh1 committed
154
155
    connect(m_helpManager, SIGNAL(helpRequested(QUrl)), this,
        SLOT(handleHelpRequest(QUrl)));
156
157
158
159
    connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
        SLOT(setupHelpEngineIfNeeded()));
    connect(m_docSettingsPage, SIGNAL(documentationChanged()), this,
        SLOT(setupHelpEngineIfNeeded()));
con's avatar
con committed
160

161
162
    m_splitter = new Core::MiniSplitter;
    m_centralWidget = new Help::Internal::CentralWidget();
163
164
    connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
        SLOT(updateSideBarSource(QUrl)));
con's avatar
con committed
165
166

    // Add Home, Previous and Next actions (used in the toolbar)
167
168
    QAction *action = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")),
        tr("Home"), this);
169
    Core::ActionManager *am = m_core->actionManager();
170
171
172
    Core::Command *cmd = am->registerAction(action, QLatin1String("Help.Home"),
        globalcontext);
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
con's avatar
con committed
173

174
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
175
        tr("Previous Page"), this);
176
    cmd = am->registerAction(action, QLatin1String("Help.Previous"), modecontext);
177
    cmd->setDefaultKeySequence(QKeySequence::Back);
178
179
180
181
    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
182

183
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next Page"),
kh's avatar
kh committed
184
        this);
185
    cmd = am->registerAction(action, QLatin1String("Help.Next"), modecontext);
186
    cmd->setDefaultKeySequence(QKeySequence::Forward);
187
188
189
190
    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
191

192
    action = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")),
con's avatar
con committed
193
        tr("Add Bookmark"), this);
194
    cmd = am->registerAction(action, QLatin1String("Help.AddBookmark"),
kh's avatar
kh committed
195
        modecontext);
con's avatar
con committed
196
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_M));
197
    connect(action, SIGNAL(triggered()), this, SLOT(addBookmark()));
con's avatar
con committed
198

199
200
201
202
203
204
    // Add Contents, Index, and Context menu items and a separator to the Help menu
    action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), tr("Contents"), this);
    cmd = am->registerAction(action, QLatin1String("Help.Contents"), globalcontext);
    am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
    connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));

205
206
207
208
209
210
211
212
    action = new QAction(tr("Index"), this);
    cmd = am->registerAction(action, QLatin1String("Help.Index"), globalcontext);
    am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
    connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));

    action = new QAction(tr("Context Help"), this);
    cmd = am->registerAction(action, QLatin1String("Help.Context"), globalcontext);
    am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
con's avatar
con committed
213
    cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
214
    connect(action, SIGNAL(triggered()), this, SLOT(activateContext()));
con's avatar
con committed
215

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
216
#ifndef Q_WS_MAC
217
218
219
220
    action = new QAction(this);
    action->setSeparator(true);
    cmd = am->registerAction(action, QLatin1String("Help.Separator"), globalcontext);
    am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
con's avatar
con committed
221
222
#endif

223
224
225
    action = new QAction(this);
    am->registerAction(action, Core::Constants::PRINT, modecontext);
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(print()));
con's avatar
con committed
226

227
228
229
230
231
    action = new QAction(this);
    cmd = am->registerAction(action, Core::Constants::COPY, modecontext);
    connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(copy()));
    action->setText(cmd->action()->text());
    action->setIcon(cmd->action()->icon());
232

233
    if (Core::ActionContainer *advancedMenu = am->actionContainer(M_EDIT_ADVANCED)) {
234
        // reuse TextEditor constants to avoid a second pair of menu actions
235
236
        action = new QAction(tr("Increase Font Size"), this);
        cmd = am->registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE,
237
238
            modecontext);
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl++")));
239
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomIn()));
240
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
241

242
243
        action = new QAction(tr("Decrease Font Size"), this);
        cmd = am->registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE,
244
245
            modecontext);
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
246
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomOut()));
247
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
248

249
250
        action = new QAction(tr("Reset Font Size"), this);
        cmd = am->registerAction(action, TextEditor::Constants::RESET_FONT_SIZE,
251
            modecontext);
252
#ifndef Q_WS_MAC
253
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+0")));
254
#endif
255
        connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(resetZoom()));
256
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
257
258
    }

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    if (Core::ActionContainer *windowMenu = am->actionContainer(M_WINDOW)) {
        // reuse EditorManager constants to avoid a second pair of menu actions
        action = new QAction(QApplication::tr("EditorManager",
            "Next Open Document in History"), this);
        Core::Command *ctrlTab = am->registerAction(action, GOTOPREVINHISTORY,
            modecontext);   // Goto Previous In History Action
        windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoPreviousPage()));

        action = new QAction(QApplication::tr("EditorManager",
            "Previous Open Document in History"), this);
        Core::Command *ctrlShiftTab = am->registerAction(action, GOTONEXTINHISTORY,
            modecontext);   // Goto Next In History Action
        windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE);
        connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
            SLOT(gotoNextPage()));

#ifdef Q_WS_MAC
        ctrlTab->setDefaultKeySequence(QKeySequence(tr("Alt+Tab")));
        ctrlShiftTab->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab")));
#else
        ctrlTab->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab")));
        ctrlShiftTab->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab")));
#endif
    }

286
287
288
289
    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
    agg->add(m_centralWidget);
    agg->add(new HelpFindSupport(m_centralWidget));
    m_mainWidget = new QWidget;
con's avatar
con committed
290
    m_splitter->addWidget(m_mainWidget);
291
292
293
294
295
296
    QVBoxLayout *mainWidgetLayout = new QVBoxLayout(m_mainWidget);
    mainWidgetLayout->setMargin(0);
    mainWidgetLayout->setSpacing(0);
    mainWidgetLayout->addWidget(createToolBar());
    mainWidgetLayout->addWidget(m_centralWidget);

297
298
299
300
301
302
303
    HelpIndexFilter *helpIndexFilter = new HelpIndexFilter();
    addAutoReleasedObject(helpIndexFilter);
    connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)), this,
        SLOT(switchToHelpMode(QUrl)));
    connect(helpIndexFilter, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)),
        this, SLOT(switchToHelpMode(QMap<QString, QUrl>, QString)));

304
305
306
307
308
309
310
    QDesktopServices::setUrlHandler("qthelp", this, "handleHelpRequest");
    connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*)),
        this, SLOT(modeChanged(Core::IMode*)));

    addAutoReleasedObject(m_mode = new HelpMode(m_splitter, m_centralWidget));
    m_mode->setContext(QList<int>() << modecontext);

con's avatar
con committed
311
312
313
    return true;
}

314
void HelpPlugin::extensionsInitialized()
315
{
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
    const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
    const QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*"));

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

    const QString &docInternal = QString::fromLatin1("com.nokia.qtcreator.%1%2%3")
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);

    foreach (const QString &ns, engine->registeredDocumentations()) {
        if (ns.startsWith(QLatin1String("com.nokia.qtcreator."))
            && ns != docInternal)
            m_helpManager->unregisterDocumentation(QStringList() << ns);
    }

    QStringList filesToRegister;
    // Explicitly register qml.qch if located in creator directory. This is only
    // needed for the creator-qml package, were we want to ship the documentation
    // without a qt development version.
    const QString &appPath = QCoreApplication::applicationDirPath();
    filesToRegister.append(QDir::cleanPath(QDir::cleanPath(appPath
        + QLatin1String(DOCPATH "qml.qch"))));

    // we might need to register creators inbuild help
    filesToRegister.append(QDir::cleanPath(appPath
        + QLatin1String(DOCPATH "qtcreator.qch")));

    // this comes from the installer
    const QLatin1String key("AddedDocs");
    const QString &addedDocs = engine->customValue(key).toString();
    if (!addedDocs.isEmpty()) {
        engine->removeCustomValue(key);
        filesToRegister += addedDocs.split(QLatin1Char(';'));
    }

    updateFilterComboBox();
    m_helpManager->verifyDocumenation();
    m_helpManager->registerDocumentation(filesToRegister);

    const QString &url = QString::fromLatin1("qthelp://com.nokia.qtcreator."
        "%1%2%3/doc/index.html").arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR)
        .arg(IDE_VERSION_RELEASE);
    engine->setCustomValue(QLatin1String("DefaultHomePage"), url);
    connect(engine, SIGNAL(setupFinished()), this, SLOT(updateFilterComboBox()));
365
366
}

367
void HelpPlugin::aboutToShutdown()
368
{
369
370
    if (m_sideBar)
        m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar"));
371
372
}

373
void HelpPlugin::setupUi()
374
{
375
376
377
378
379
380
381
    // side bar widgets and shortcuts
    QList<int> modecontext;
    Core::ActionManager *am = m_core->actionManager();
    modecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_MODE_HELP);

    IndexWindow *indexWindow = new IndexWindow();
    indexWindow->setWindowTitle(tr("Index"));
382
    m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX));
383
384
385
386
387

    connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
    connect(indexWindow, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)),
        m_centralWidget, SLOT(showTopicChooser(QMap<QString, QUrl>, QString)));
388
389
390
391

    QMap<QString, Core::Command*> shortcutMap;
    QShortcut *shortcut = new QShortcut(m_splitter);
    shortcut->setWhatsThis(tr("Activate Index in Help mode"));
392
393
394
    Core::Command* cmd = am->registerShortcut(shortcut,
        QLatin1String("Help.IndexShortcut"), modecontext);
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
395
    connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex()));
396
    shortcutMap.insert(QLatin1String(SB_INDEX), cmd);
397
398
399

    ContentWindow *contentWindow = new ContentWindow();
    contentWindow->setWindowTitle(tr("Contents"));
400
    m_contentItem = new Core::SideBarItem(contentWindow, QLatin1String(SB_CONTENTS));
401
402
    connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
403
404
405

    shortcut = new QShortcut(m_splitter);
    shortcut->setWhatsThis(tr("Activate Contents in Help mode"));
406
407
408
    cmd = am->registerShortcut(shortcut, QLatin1String("Help.ContentsShortcut"),
        modecontext);
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
409
    connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents()));
410
    shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd);
411
412
413

    SearchWidget *searchWidget = new SearchWidget();
    searchWidget->setWindowTitle(tr("Search"));
414
    m_searchItem = new Core::SideBarItem(searchWidget, "Search");
415
416
    connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSourceFromSearch(QUrl)));
417
418
419
420

    // TODO: enable and find a proper keysequence as this is ambiguous
    // shortcut = new QShortcut(m_splitter);
    // shortcut->setWhatsThis(tr("Activate Search in Help mode"));
421
422
    // cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"),
    //     modecontext);
423
424
    // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
    // connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
425
    // shortcutMap.insert("Search", cmd);
426
427
428
429

    BookmarkManager *manager = &HelpManager::bookmarkManager();
    BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
    bookmarkWidget->setWindowTitle(tr("Bookmarks"));
430
    m_bookmarkItem = new Core::SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS));
431
432
    connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
433
434
435
436

    // TODO: enable and find a proper keysequence as this is ambiguous
    // shortcut = new QShortcut(m_splitter);
    // shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
437
438
    // cmd = am->registerShortcut(shortcut, QLatin1String("Help.BookmarkShortcut"),
    //     modecontext);
439
440
    // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_B));
    // connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
441
    // shortcutMap.insert("Bookmarks", cmd);
442

443
444
    QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
    openPagesWidget->setWindowTitle(tr("Open Pages"));
445
    m_openPagesItem = new Core::SideBarItem(openPagesWidget, QLatin1String(SB_OPENPAGES));
446
447
448
449
450
451
452

    shortcut = new QShortcut(m_splitter);
    shortcut->setWhatsThis(tr("Activate Open Pages in Help mode"));
    cmd = am->registerShortcut(shortcut, QLatin1String("Help.PagesShortcut"),
        modecontext);
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_O));
    connect(shortcut, SIGNAL(activated()), this, SLOT(activateOpenPages()));
453
    shortcutMap.insert(QLatin1String(SB_OPENPAGES), cmd);
454

455
    QList<Core::SideBarItem*> itemList;
456
457
458
    itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem
        << m_openPagesItem;
    m_sideBar = new Core::SideBar(itemList, QList<Core::SideBarItem*>()
kh1's avatar
kh1 committed
459
        << m_contentItem << m_openPagesItem);
460
461
462
    m_sideBar->setShortcutMap(shortcutMap);

    m_splitter->setOpaqueResize(false);
con's avatar
con committed
463
    m_splitter->insertWidget(0, m_sideBar);
464
465
466
467
    m_splitter->setStretchFactor(0, 0);
    m_splitter->setStretchFactor(1, 1);
    m_splitter->setSizes(QList<int>() << 300 << 300);
    m_sideBar->readSettings(m_core->settings(), QLatin1String("HelpSideBar"));
468
469
}

kh1's avatar
kh1 committed
470
471
472
473
void HelpPlugin::resetFilter()
{
    const QLatin1String weAddedFilterKey("UnfilteredFilterInserted");
    const QLatin1String previousFilterNameKey("UnfilteredFilterName");
474
475
476

    QHelpEngineCore *core = &m_helpManager->helpEngineCore();
    if (core->customValue(weAddedFilterKey).toInt() == 1) {
kh1's avatar
kh1 committed
477
        // we added a filter at some point, remove previously added filter
478
479
480
        const QString &filter = core->customValue(previousFilterNameKey).toString();
        if (!filter.isEmpty())
            core->removeCustomFilter(filter);
kh1's avatar
kh1 committed
481
482
483
484
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
485
486
487
488
489
    core->removeCustomFilter(filterName);
    core->addCustomFilter(filterName, QStringList());
    core->setCustomValue(weAddedFilterKey, 1);
    core->setCustomValue(previousFilterNameKey, filterName);
    (&m_helpManager->helpEngine())->setCurrentFilter(filterName);
490
491
}

492
void HelpPlugin::createRightPaneContextViewer()
con's avatar
con committed
493
{
494
495
    if (m_helpViewerForSideBar)
        return;
con's avatar
con committed
496

497
498
    QAction *switchToHelp = new QAction(tr("Go to Help Mode"), this);
    connect(switchToHelp, SIGNAL(triggered()), this, SLOT(switchToHelpMode()));
con's avatar
con committed
499

500
    QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
501
        tr("Next"), this);
502
    QAction *previous = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
503
        tr("Previous"), this);
con's avatar
con committed
504
505
506
507
508

    // Dummy layout to align the close button to the right
    QHBoxLayout *hboxLayout = new QHBoxLayout();
    hboxLayout->setSpacing(0);
    hboxLayout->setMargin(0);
509
510
511
512
513
514
515

    // left side actions
    QToolBar *rightPaneToolBar = new QToolBar();
    rightPaneToolBar->addAction(switchToHelp);
    rightPaneToolBar->addAction(previous);
    rightPaneToolBar->addAction(next);

516
    hboxLayout->addWidget(rightPaneToolBar);
517
518
519
520
    hboxLayout->addStretch();

    QToolButton *closeButton = new QToolButton();
    closeButton->setIcon(QIcon(":/core/images/closebutton.png"));
con's avatar
con committed
521
522
    connect(closeButton, SIGNAL(clicked()), this, SLOT(slotHideRightPane()));

523
524
525
    // close button to the right
    hboxLayout->addWidget(closeButton);

con's avatar
con committed
526
527
528
529
    QVBoxLayout *rightPaneLayout = new QVBoxLayout;
    rightPaneLayout->setMargin(0);
    rightPaneLayout->setSpacing(0);

530
531
532
533
534
535
536
537
    QWidget *rightPaneSideBar = new QWidget;
    rightPaneSideBar->setLayout(rightPaneLayout);
    addAutoReleasedObject(new Core::BaseRightPaneWidget(rightPaneSideBar));

    Utils::StyledBar *rightPaneStyledBar = new Utils::StyledBar;
    rightPaneStyledBar->setLayout(hboxLayout);
    rightPaneLayout->addWidget(rightPaneStyledBar);

538
    m_helpViewerForSideBar = new HelpViewer(qreal(0.0), rightPaneSideBar);
539
540
541
542
    rightPaneLayout->addWidget(m_helpViewerForSideBar);
    rightPaneLayout->addWidget(new Core::FindToolBarPlaceHolder(rightPaneSideBar));
    rightPaneSideBar->setFocusProxy(m_helpViewerForSideBar);

con's avatar
con committed
543
544
545
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(m_helpViewerForSideBar);
    agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
546
547
548
    m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar, QList<int>()
        << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_HELP_SIDEBAR), this));

549
550
551
552
553
    QAction *copy = new QAction(this);
    Core::Command *cmd = m_core->actionManager()->registerAction(copy, Core::Constants::COPY,
        QList<int>() << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_HELP_SIDEBAR));
    copy->setText(cmd->action()->text());
    copy->setIcon(cmd->action()->icon());
554

555
556
557
    connect(copy, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(copy()));
    connect(next, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(forward()));
    connect(previous, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(backward()));
con's avatar
con committed
558
559
}

hjk's avatar
hjk committed
560
561
562
563
564
void HelpPlugin::activateHelpMode()
{
    m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
}

con's avatar
con committed
565
566
567
568
569
570
571
void HelpPlugin::switchToHelpMode()
{
    switchToHelpMode(m_helpViewerForSideBar->source());
}

void HelpPlugin::switchToHelpMode(const QUrl &source)
{
hjk's avatar
hjk committed
572
    activateHelpMode();
con's avatar
con committed
573
574
575
576
    m_centralWidget->setSource(source);
    m_centralWidget->setFocus();
}

kh's avatar
kh committed
577
578
void HelpPlugin::switchToHelpMode(const QMap<QString, QUrl> &urls,
    const QString &keyword)
con's avatar
con committed
579
{
hjk's avatar
hjk committed
580
    activateHelpMode();
con's avatar
con committed
581
582
583
584
585
586
587
588
589
590
    m_centralWidget->showTopicChooser(urls, keyword);
}

void HelpPlugin::slotHideRightPane()
{
    Core::RightPaneWidget::instance()->setShown(false);
}

void HelpPlugin::modeChanged(Core::IMode *mode)
{
591
592
    if (mode == m_mode && m_firstModeChange) {
        m_firstModeChange = false;
593

con's avatar
con committed
594
595
        qApp->processEvents();
        qApp->setOverrideCursor(Qt::WaitCursor);
596

597
        setupUi();
kh1's avatar
kh1 committed
598
        resetFilter();
599
        m_helpManager->setupGuiHelpEngine();
600
        OpenPagesManager::instance().setupInitialPages();
601

602
603
604
605
        qApp->restoreOverrideCursor();
    } else if (mode == m_mode && !m_firstModeChange) {
        qApp->setOverrideCursor(Qt::WaitCursor);
        m_helpManager->setupGuiHelpEngine();
con's avatar
con committed
606
607
608
609
        qApp->restoreOverrideCursor();
    }
}

610
611
void HelpPlugin::updateSideBarSource()
{
612
613
614
615
616
    if (HelpViewer *viewer = m_centralWidget->currentHelpViewer()) {
        const QUrl &url = viewer->source();
        if (url.isValid())
            updateSideBarSource(url);
    }
617
618
619
620
621
622
623
624
}

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

625
void HelpPlugin::updateCloseButton()
626
{
627
628
    m_closeButton->setEnabled(OpenPagesManager::instance().pageCount() > 1);
}
629

630
631
632
633
void HelpPlugin::fontChanged()
{
    if (!m_helpViewerForSideBar)
        createRightPaneContextViewer();
634

635
636
637
638
639
640
641
642
643
    const QHelpEngineCore &engine = m_helpManager->helpEngineCore();
    QFont font = qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
        m_helpViewerForSideBar->viewerFont()));

    m_helpViewerForSideBar->setFont(font);
    const int count = OpenPagesManager::instance().pageCount();
    for (int i = 0; i < count; ++i) {
        if (HelpViewer *viewer = CentralWidget::instance()->viewerAt(i))
            viewer->setViewerFont(font);
644
645
646
    }
}

647
648
649
650
651
652
void HelpPlugin::setupHelpEngineIfNeeded()
{
    if (Core::ICore::instance()->modeManager()->currentMode() == m_mode)
        m_helpManager->setupGuiHelpEngine();
}

653
HelpViewer* HelpPlugin::viewerForContextMode()
con's avatar
con committed
654
{
655
    using namespace Core;
656

657
    bool showSideBySide = false;
658
    const QHelpEngineCore &engine = m_helpManager->helpEngineCore();
659
    RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
660
    switch (engine.customValue(QLatin1String("ContextHelpOption"), 0).toInt()) {
661
662
663
664
        case 0: {
            // side by side if possible
            if (IEditor *editor = EditorManager::instance()->currentEditor()) {
                if (!placeHolder || !placeHolder->isVisible()) {
665
666
667
668
669
                    if (!editor->widget())
                        break;
                    if (!editor->widget()->isVisible())
                        break;
                    if (editor->widget()->width() < 800)
670
671
                        break;
                }
672
            }
673
674
675
676
677
        }   // fall through
        case 1: {
            // side by side
            showSideBySide = true;
        }   break;
678

679
680
        default: // help mode
            break;
681
682
    }

683
    HelpViewer *viewer = m_centralWidget->currentHelpViewer();
684
    if (placeHolder && showSideBySide) {
685
        RightPaneWidget::instance()->setShown(true);
686
687

        createRightPaneContextViewer();
kh's avatar
kh committed
688
        viewer = m_helpViewerForSideBar;
con's avatar
con committed
689
    } else {
690
        activateHelpMode();
691
        if (!viewer)
692
            viewer = OpenPagesManager::instance().createPage();
kh's avatar
kh committed
693
    }
694
695
696
697
698
    return viewer;
}

void HelpPlugin::activateContext()
{
699
    using namespace Core;
700
    createRightPaneContextViewer();
701

702
    RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
703
704
705
706
707
708
709
710
711
712
    if (placeHolder && m_helpViewerForSideBar->hasFocus()) {
        switchToHelpMode();
        return;
    } else if (m_core->modeManager()->currentMode() == m_mode)
        return;

    QString id;
    QMap<QString, QUrl> links;

    // Find out what to show
713
    if (IContext *context = m_core->currentContextObject()) {
714
        id = context->contextHelpId();
715
        links = m_helpManager->helpEngineCore().linksForIdentifier(id);
716
717
    }

718
    if (HelpViewer* viewer = viewerForContextMode()) {
kh's avatar
kh committed
719
720
721
722
723
        if (links.isEmpty()) {
            // No link found or no context object
            viewer->setHtml(tr("<html><head><title>No Documentation</title>"
                "</head><body><br/><center><b>%1</b><br/>No documentation "
                "available.</center></body></html>").arg(id));
con's avatar
con committed
724
            viewer->setSource(QUrl());
kh's avatar
kh committed
725
        } else {
726
            const QUrl &source = *links.begin();
kh's avatar
kh committed
727
728
729
            if (viewer->source() != source)
                viewer->setSource(source);
            viewer->setFocus();
con's avatar
con committed
730
        }
731
732
        if (viewer != m_helpViewerForSideBar)
            activateHelpMode();
con's avatar
con committed
733
734
735
736
737
    }
}

void HelpPlugin::activateIndex()
{
hjk's avatar
hjk committed
738
    activateHelpMode();
con's avatar
con committed
739
740
741
742
743
    m_sideBar->activateItem(m_indexItem);
}

void HelpPlugin::activateContents()
{
hjk's avatar
hjk committed
744
    activateHelpMode();
con's avatar
con committed
745
746
747
748
749
    m_sideBar->activateItem(m_contentItem);
}

void HelpPlugin::activateSearch()
{
hjk's avatar
hjk committed
750
    activateHelpMode();
con's avatar
con committed
751
752
753
    m_sideBar->activateItem(m_searchItem);
}

754
755
756
757
758
759
void HelpPlugin::activateOpenPages()
{
    activateHelpMode();
    m_sideBar->activateItem(m_openPagesItem);
}

con's avatar
con committed
760
761
762
QToolBar *HelpPlugin::createToolBar()
{
    QToolBar *toolWidget = new QToolBar;
763
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
764
765
766
767
768
769
770
771
772
773
    toolWidget->addAction(am->command(QLatin1String("Help.Home"))->action());
    toolWidget->addAction(am->command(QLatin1String("Help.Previous"))->action());
    toolWidget->addAction(am->command(QLatin1String("Help.Next"))->action());
    toolWidget->addSeparator();
    toolWidget->addAction(am->command(QLatin1String("Help.AddBookmark"))->action());
    toolWidget->setMovable(false);

    toolWidget->addSeparator();

    QWidget *w = new QWidget;
774
775
    toolWidget->addWidget(w);

con's avatar
con committed
776
777
778
    QHBoxLayout *layout = new QHBoxLayout(w);
    layout->setMargin(0);
    layout->addSpacing(10);
779
    layout->addWidget(OpenPagesManager::instance().openPagesComboBox());
780

con's avatar
con committed
781
782
783
    layout->addWidget(new QLabel(tr("Filtered by:")));
    m_filterComboBox = new QComboBox;
    m_filterComboBox->setMinimumContentsLength(20);
784
    layout->addWidget(m_filterComboBox);
kh's avatar
kh committed
785
786
    connect(m_filterComboBox, SIGNAL(activated(QString)), this,
        SLOT(filterDocumentation(QString)));
787
788
789
790
791
792
793
794
795
796
797
798
    connect(m_filterComboBox, SIGNAL(currentIndexChanged(int)), this,
        SLOT(updateSideBarSource()));

    m_closeButton = new QToolButton();
    m_closeButton->setIcon(QIcon(":/core/images/closebutton.png"));
    m_closeButton->setToolTip(tr("Close current Page"));
    connect(m_closeButton, SIGNAL(clicked()), &OpenPagesManager::instance(),
        SLOT(closeCurrentPage()));
    connect(&OpenPagesManager::instance(), SIGNAL(pagesChanged()), this,
        SLOT(updateCloseButton()));
    layout->addStretch();
    layout->addWidget(m_closeButton);
con's avatar
con committed
799
800
801
802
803
804

    return toolWidget;
}

void HelpPlugin::updateFilterComboBox()
{
805
    const QHelpEngine &engine = m_helpManager->helpEngine();
con's avatar
con committed
806
807
    QString curFilter = m_filterComboBox->currentText();
    if (curFilter.isEmpty())
808
        curFilter = engine.currentFilter();
con's avatar
con committed
809
    m_filterComboBox->clear();
810
    m_filterComboBox->addItems(engine.customFilters());
con's avatar
con committed
811
812
813
814
815
816
817
818
    int idx = m_filterComboBox->findText(curFilter);
    if (idx < 0)
        idx = 0;
    m_filterComboBox->setCurrentIndex(idx);
}

void HelpPlugin::filterDocumentation(const QString &customFilter)
{
819
    (&m_helpManager->helpEngine())->setCurrentFilter(customFilter);
con's avatar
con committed
820
821
822
823
}

void HelpPlugin::addBookmark()
{
824
    HelpViewer *viewer = m_centralWidget->currentHelpViewer();
con's avatar
con committed
825

826
827
    const QString &url = viewer->source().toString();
    if (url.isEmpty() || url == Help::Constants::AboutBlank)
con's avatar
con committed
828
829
        return;

830
    BookmarkManager *manager = &HelpManager::bookmarkManager();
831
    manager->showBookmarkDialog(m_centralWidget, viewer->title(), url);
con's avatar
con committed
832
833
}

kh1's avatar
kh1 committed
834
void HelpPlugin::handleHelpRequest(const QUrl &url)
con's avatar
con committed
835
{
kh1's avatar
kh1 committed
836
    if (HelpViewer::launchWithExternalApp(url))
837
838
        return;

kh1's avatar
kh1 committed
839
    if (m_helpManager->helpEngineCore().findFile(url).isValid()) {
840
841
842
843
844
845
846
        if (url.queryItemValue(QLatin1String("view")) == QLatin1String("split")) {
            if (HelpViewer* viewer = viewerForContextMode())
                viewer->setSource(url);
        } else {
            activateHelpMode();
            m_centralWidget->setSource(url);
        }
847
    } else {
kh1's avatar
kh1 committed
848
849
850
851
852
853
        QString address = url.toString();
        if (address.startsWith(HelpViewer::NsNokia)
            || address.startsWith(HelpViewer::NsTrolltech)) {
                // local help not installed, resort to external web help
                QString urlPrefix = QLatin1String("http://doc.trolltech.com/");
                if (url.authority() == QLatin1String("com.nokia.qtcreator")) {
854
                    urlPrefix.append(QString::fromLatin1("qtcreator"));
kh1's avatar
kh1 committed
855
856
857
858
                } else {
                    urlPrefix.append(QLatin1String("latest"));
                }
            address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
859
        }
kh1's avatar
kh1 committed
860
        QDesktopServices::openUrl(address);
861
862
    }
}
con's avatar
con committed
863
864

Q_EXPORT_PLUGIN(HelpPlugin)