helpplugin.cpp 32.2 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>
kh1's avatar
kh1 committed
57
#include <coreplugin/helpmanager.h>
hjk's avatar
hjk committed
58 59 60 61
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/rightpane.h>
#include <coreplugin/sidebar.h>
62
#include <coreplugin/uniqueidmanager.h>
kh1's avatar
kh1 committed
63
#include <extensionsystem/pluginmanager.h>
64
#include <texteditor/texteditorconstants.h>
65
#include <utils/styledbar.h>
kh1's avatar
kh1 committed
66
#include <welcome/welcomemode.h>
67

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

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

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

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

86 87 88 89 90 91
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";

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

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

HelpPlugin::~HelpPlugin()
{
}

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

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

kh1's avatar
kh1 committed
142
    addAutoReleasedObject(m_helpManager = new LocalHelpManager(this));
143
    addAutoReleasedObject(m_openPagesManager = new OpenPagesManager(this));
144 145
    addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
    addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
146
    addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage());
147

148 149
    connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
        SLOT(fontChanged()));
kh1's avatar
kh1 committed
150
    connect(Core::HelpManager::instance(), SIGNAL(helpRequested(QUrl)), this,
kh1's avatar
kh1 committed
151
        SLOT(handleHelpRequest(QUrl)));
kh1's avatar
kh1 committed
152
    m_filterSettingsPage->setHelpManager(m_helpManager);
153 154
    connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
        SLOT(setupHelpEngineIfNeeded()));
kh1's avatar
kh1 committed
155
    connect(Core::HelpManager::instance(), SIGNAL(documentationChanged()), this,
156
        SLOT(setupHelpEngineIfNeeded()));
con's avatar
con committed
157

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

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

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

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

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

196 197 198 199 200 201
    // 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()));

202 203 204 205 206 207 208 209
    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
210
    cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
211
    connect(action, SIGNAL(triggered()), this, SLOT(activateContext()));
con's avatar
con committed
212

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
213
#ifndef Q_WS_MAC
214 215 216 217
    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
218 219
#endif

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

224 225 226 227 228
    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());
229

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

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

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

256 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
    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
    }

283 284 285 286
    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
287
    m_splitter->addWidget(m_mainWidget);
288 289 290 291 292 293
    QVBoxLayout *mainWidgetLayout = new QVBoxLayout(m_mainWidget);
    mainWidgetLayout->setMargin(0);
    mainWidgetLayout->setSpacing(0);
    mainWidgetLayout->addWidget(createToolBar());
    mainWidgetLayout->addWidget(m_centralWidget);

294 295 296 297 298 299 300
    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)));

301 302 303 304 305 306 307
    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
308 309 310
    return true;
}

311
void HelpPlugin::extensionsInitialized()
312
{
kh1's avatar
kh1 committed
313
    const QString &nsInternal = QString::fromLatin1("com.nokia.qtcreator.%1%2%3")
314 315
        .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);

kh1's avatar
kh1 committed
316 317
    Core::HelpManager *helpManager = Core::HelpManager::instance();
    foreach (const QString &ns, helpManager->registeredNamespaces()) {
318
        if (ns.startsWith(QLatin1String("com.nokia.qtcreator."))
kh1's avatar
kh1 committed
319 320
            && ns != nsInternal)
            helpManager->unregisterDocumentation(QStringList() << ns);
321 322 323 324 325
    }

    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
kh1's avatar
kh1 committed
326
    // without a qt development version. TODO: is this still really needed, remove
327 328 329 330 331 332 333
    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")));
334 335
}

336
void HelpPlugin::aboutToShutdown()
337
{
338 339
    if (m_sideBar)
        m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar"));
340 341
}

342
void HelpPlugin::setupUi()
343
{
344 345 346 347 348 349 350
    // 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"));
351
    m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX));
352 353 354 355 356

    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)));
357 358 359 360

    QMap<QString, Core::Command*> shortcutMap;
    QShortcut *shortcut = new QShortcut(m_splitter);
    shortcut->setWhatsThis(tr("Activate Index in Help mode"));
361 362 363
    Core::Command* cmd = am->registerShortcut(shortcut,
        QLatin1String("Help.IndexShortcut"), modecontext);
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
364
    connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex()));
365
    shortcutMap.insert(QLatin1String(SB_INDEX), cmd);
366 367 368

    ContentWindow *contentWindow = new ContentWindow();
    contentWindow->setWindowTitle(tr("Contents"));
369
    m_contentItem = new Core::SideBarItem(contentWindow, QLatin1String(SB_CONTENTS));
370 371
    connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
372 373 374

    shortcut = new QShortcut(m_splitter);
    shortcut->setWhatsThis(tr("Activate Contents in Help mode"));
375 376 377
    cmd = am->registerShortcut(shortcut, QLatin1String("Help.ContentsShortcut"),
        modecontext);
    cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
378
    connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents()));
379
    shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd);
380 381 382

    SearchWidget *searchWidget = new SearchWidget();
    searchWidget->setWindowTitle(tr("Search"));
383
    m_searchItem = new Core::SideBarItem(searchWidget, "Search");
384 385
    connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSourceFromSearch(QUrl)));
386

kh1's avatar
kh1 committed
387 388 389 390 391 392 393
     shortcut = new QShortcut(m_splitter);
     shortcut->setWhatsThis(tr("Activate Search in Help mode"));
     cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"),
         modecontext);
     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Slash));
     connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
     shortcutMap.insert(SB_SEARCH, cmd);
394

kh1's avatar
kh1 committed
395
    BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
396 397
    BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
    bookmarkWidget->setWindowTitle(tr("Bookmarks"));
398
    m_bookmarkItem = new Core::SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS));
399 400
    connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
401

kh1's avatar
kh1 committed
402 403 404 405 406 407 408
     shortcut = new QShortcut(m_splitter);
     shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
     cmd = am->registerShortcut(shortcut, QLatin1String("Help.BookmarkShortcut"),
         modecontext);
     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B));
     connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
     shortcutMap.insert(SB_BOOKMARKS, cmd);
409

410 411
    QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
    openPagesWidget->setWindowTitle(tr("Open Pages"));
412
    m_openPagesItem = new Core::SideBarItem(openPagesWidget, QLatin1String(SB_OPENPAGES));
413 414 415 416 417 418 419

    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()));
420
    shortcutMap.insert(QLatin1String(SB_OPENPAGES), cmd);
421

422
    QList<Core::SideBarItem*> itemList;
423 424 425
    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
426
        << m_contentItem << m_openPagesItem);
427 428 429
    m_sideBar->setShortcutMap(shortcutMap);

    m_splitter->setOpaqueResize(false);
con's avatar
con committed
430
    m_splitter->insertWidget(0, m_sideBar);
431 432 433 434
    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"));
435 436
}

kh1's avatar
kh1 committed
437 438
void HelpPlugin::resetFilter()
{
kh1's avatar
kh1 committed
439 440 441 442 443 444 445 446 447 448 449
    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 = &LocalHelpManager::helpEngine();
    const QStringList &filters = engine->customFilters();
    foreach (const QString &filter, filters) {
        if (filterRegExp.exactMatch(filter) && filter != filterInternal)
            engine->removeCustomFilter(filter);
    }

kh1's avatar
kh1 committed
450 451
    const QLatin1String weAddedFilterKey("UnfilteredFilterInserted");
    const QLatin1String previousFilterNameKey("UnfilteredFilterName");
kh1's avatar
kh1 committed
452
    if (engine->customValue(weAddedFilterKey).toInt() == 1) {
kh1's avatar
kh1 committed
453
        // we added a filter at some point, remove previously added filter
kh1's avatar
kh1 committed
454
        const QString &filter = engine->customValue(previousFilterNameKey).toString();
455
        if (!filter.isEmpty())
kh1's avatar
kh1 committed
456
            engine->removeCustomFilter(filter);
kh1's avatar
kh1 committed
457 458 459 460
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
kh1's avatar
kh1 committed
461 462 463 464 465 466 467 468
    engine->removeCustomFilter(filterName);
    engine->addCustomFilter(filterName, QStringList());
    engine->setCustomValue(weAddedFilterKey, 1);
    engine->setCustomValue(previousFilterNameKey, filterName);
    engine->setCurrentFilter(filterName);

    updateFilterComboBox();
    connect(engine, SIGNAL(setupFinished()), this, SLOT(updateFilterComboBox()));
469 470
}

471
void HelpPlugin::createRightPaneContextViewer()
con's avatar
con committed
472
{
473 474
    if (m_helpViewerForSideBar)
        return;
con's avatar
con committed
475

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

479
    QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
480
        tr("Next"), this);
481
    QAction *previous = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
482
        tr("Previous"), this);
con's avatar
con committed
483 484 485 486 487

    // Dummy layout to align the close button to the right
    QHBoxLayout *hboxLayout = new QHBoxLayout();
    hboxLayout->setSpacing(0);
    hboxLayout->setMargin(0);
488 489 490 491 492 493 494

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

495
    hboxLayout->addWidget(rightPaneToolBar);
496 497 498 499
    hboxLayout->addStretch();

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

502 503 504
    // close button to the right
    hboxLayout->addWidget(closeButton);

con's avatar
con committed
505 506 507 508
    QVBoxLayout *rightPaneLayout = new QVBoxLayout;
    rightPaneLayout->setMargin(0);
    rightPaneLayout->setSpacing(0);

509 510 511 512 513 514 515 516
    QWidget *rightPaneSideBar = new QWidget;
    rightPaneSideBar->setLayout(rightPaneLayout);
    addAutoReleasedObject(new Core::BaseRightPaneWidget(rightPaneSideBar));

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

517
    m_helpViewerForSideBar = new HelpViewer(qreal(0.0), rightPaneSideBar);
518 519 520 521
    rightPaneLayout->addWidget(m_helpViewerForSideBar);
    rightPaneLayout->addWidget(new Core::FindToolBarPlaceHolder(rightPaneSideBar));
    rightPaneSideBar->setFocusProxy(m_helpViewerForSideBar);

con's avatar
con committed
522 523 524
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(m_helpViewerForSideBar);
    agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
525 526 527
    m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar, QList<int>()
        << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_HELP_SIDEBAR), this));

528 529 530 531 532
    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());
533

534 535 536
    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
537 538
}

hjk's avatar
hjk committed
539 540 541 542 543
void HelpPlugin::activateHelpMode()
{
    m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
}

con's avatar
con committed
544 545 546 547 548 549 550
void HelpPlugin::switchToHelpMode()
{
    switchToHelpMode(m_helpViewerForSideBar->source());
}

void HelpPlugin::switchToHelpMode(const QUrl &source)
{
hjk's avatar
hjk committed
551
    activateHelpMode();
con's avatar
con committed
552 553 554 555
    m_centralWidget->setSource(source);
    m_centralWidget->setFocus();
}

kh's avatar
kh committed
556 557
void HelpPlugin::switchToHelpMode(const QMap<QString, QUrl> &urls,
    const QString &keyword)
con's avatar
con committed
558
{
hjk's avatar
hjk committed
559
    activateHelpMode();
con's avatar
con committed
560 561 562 563 564 565 566 567 568 569
    m_centralWidget->showTopicChooser(urls, keyword);
}

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

void HelpPlugin::modeChanged(Core::IMode *mode)
{
570 571
    if (mode == m_mode && m_firstModeChange) {
        m_firstModeChange = false;
572

con's avatar
con committed
573 574
        qApp->processEvents();
        qApp->setOverrideCursor(Qt::WaitCursor);
575

kh1's avatar
kh1 committed
576
        m_helpManager->setupGuiHelpEngine();
577
        setupUi();
kh1's avatar
kh1 committed
578
        resetFilter();
579
        OpenPagesManager::instance().setupInitialPages();
580

581 582 583 584
        qApp->restoreOverrideCursor();
    } else if (mode == m_mode && !m_firstModeChange) {
        qApp->setOverrideCursor(Qt::WaitCursor);
        m_helpManager->setupGuiHelpEngine();
con's avatar
con committed
585 586 587 588
        qApp->restoreOverrideCursor();
    }
}

589 590
void HelpPlugin::updateSideBarSource()
{
591 592 593 594 595
    if (HelpViewer *viewer = m_centralWidget->currentHelpViewer()) {
        const QUrl &url = viewer->source();
        if (url.isValid())
            updateSideBarSource(url);
    }
596 597 598 599 600 601 602 603
}

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

604
void HelpPlugin::updateCloseButton()
605
{
606 607
    m_closeButton->setEnabled(OpenPagesManager::instance().pageCount() > 1);
}
608

609 610 611 612
void HelpPlugin::fontChanged()
{
    if (!m_helpViewerForSideBar)
        createRightPaneContextViewer();
613

kh1's avatar
kh1 committed
614
    const QHelpEngine &engine = LocalHelpManager::helpEngine();
615 616 617 618 619 620 621 622
    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);
623 624 625
    }
}

626 627
void HelpPlugin::setupHelpEngineIfNeeded()
{
kh1's avatar
kh1 committed
628 629
    m_helpManager->setEngineNeedsUpdate();
    if (Core::ModeManager::instance()->currentMode() == m_mode)
630 631 632
        m_helpManager->setupGuiHelpEngine();
}

633
HelpViewer* HelpPlugin::viewerForContextMode()
con's avatar
con committed
634
{
635
    using namespace Core;
636

637
    bool showSideBySide = false;
kh1's avatar
kh1 committed
638
    const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
639
    RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
640
    switch (engine.customValue(QLatin1String("ContextHelpOption"), 0).toInt()) {
641 642 643 644
        case 0: {
            // side by side if possible
            if (IEditor *editor = EditorManager::instance()->currentEditor()) {
                if (!placeHolder || !placeHolder->isVisible()) {
645 646 647 648 649
                    if (!editor->widget())
                        break;
                    if (!editor->widget()->isVisible())
                        break;
                    if (editor->widget()->width() < 800)
650 651
                        break;
                }
652
            }
653 654 655 656 657
        }   // fall through
        case 1: {
            // side by side
            showSideBySide = true;
        }   break;
658

659 660
        default: // help mode
            break;
661 662
    }

663
    HelpViewer *viewer = m_centralWidget->currentHelpViewer();
664
    if (placeHolder && showSideBySide) {
665
        RightPaneWidget::instance()->setShown(true);
666 667

        createRightPaneContextViewer();
kh's avatar
kh committed
668
        viewer = m_helpViewerForSideBar;
con's avatar
con committed
669
    } else {
670
        activateHelpMode();
671
        if (!viewer)
672
            viewer = OpenPagesManager::instance().createPage();
kh's avatar
kh committed
673
    }
674 675 676 677 678
    return viewer;
}

void HelpPlugin::activateContext()
{
679
    using namespace Core;
680
    createRightPaneContextViewer();
681

682
    RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
683 684 685 686 687 688 689 690 691 692
    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
693
    if (IContext *context = m_core->currentContextObject()) {
694
        id = context->contextHelpId();
kh1's avatar
kh1 committed
695
        links = Core::HelpManager::instance()->linksForIdentifier(id);
696 697
    }

698
    if (HelpViewer* viewer = viewerForContextMode()) {
kh's avatar
kh committed
699 700 701 702 703
        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
704
            viewer->setSource(QUrl());
kh's avatar
kh committed
705
        } else {
706
            const QUrl &source = *links.begin();
kh's avatar
kh committed
707 708 709
            if (viewer->source() != source)
                viewer->setSource(source);
            viewer->setFocus();
con's avatar
con committed
710
        }
711 712
        if (viewer != m_helpViewerForSideBar)
            activateHelpMode();
con's avatar
con committed
713 714 715 716 717
    }
}

void HelpPlugin::activateIndex()
{
hjk's avatar
hjk committed
718
    activateHelpMode();
con's avatar
con committed
719 720 721 722 723
    m_sideBar->activateItem(m_indexItem);
}

void HelpPlugin::activateContents()
{
hjk's avatar
hjk committed
724
    activateHelpMode();
con's avatar
con committed
725 726 727 728 729
    m_sideBar->activateItem(m_contentItem);
}

void HelpPlugin::activateSearch()
{
hjk's avatar
hjk committed
730
    activateHelpMode();
con's avatar
con committed
731 732 733
    m_sideBar->activateItem(m_searchItem);
}

734 735 736 737 738 739
void HelpPlugin::activateOpenPages()
{
    activateHelpMode();
    m_sideBar->activateItem(m_openPagesItem);
}

kh1's avatar
kh1 committed
740 741 742 743 744 745
void HelpPlugin::activateBookmarks()
{
    activateHelpMode();
    m_sideBar->activateItem(m_bookmarkItem);
}

con's avatar
con committed
746 747 748
QToolBar *HelpPlugin::createToolBar()
{
    QToolBar *toolWidget = new QToolBar;
749
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
750 751 752 753 754 755 756 757 758 759
    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;
760 761
    toolWidget->addWidget(w);

con's avatar
con committed
762 763 764
    QHBoxLayout *layout = new QHBoxLayout(w);
    layout->setMargin(0);
    layout->addSpacing(10);
765
    layout->addWidget(OpenPagesManager::instance().openPagesComboBox());
766

con's avatar
con committed
767 768 769
    layout->addWidget(new QLabel(tr("Filtered by:")));
    m_filterComboBox = new QComboBox;
    m_filterComboBox->setMinimumContentsLength(20);
770
    layout->addWidget(m_filterComboBox);
kh's avatar
kh committed
771 772
    connect(m_filterComboBox, SIGNAL(activated(QString)), this,
        SLOT(filterDocumentation(QString)));
773 774 775 776 777 778 779 780 781 782 783 784
    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
785 786 787 788 789 790

    return toolWidget;
}

void HelpPlugin::updateFilterComboBox()
{
kh1's avatar
kh1 committed
791
    const QHelpEngine &engine = LocalHelpManager::helpEngine();
con's avatar
con committed
792 793
    QString curFilter = m_filterComboBox->currentText();
    if (curFilter.isEmpty())
794
        curFilter = engine.currentFilter();
con's avatar
con committed
795
    m_filterComboBox->clear();
796
    m_filterComboBox->addItems(engine.customFilters());
con's avatar
con committed
797 798 799 800 801 802 803 804
    int idx = m_filterComboBox->findText(curFilter);
    if (idx < 0)
        idx = 0;
    m_filterComboBox->setCurrentIndex(idx);
}

void HelpPlugin::filterDocumentation(const QString &customFilter)
{
kh1's avatar
kh1 committed
805
    LocalHelpManager::helpEngine().setCurrentFilter(customFilter);
con's avatar
con committed
806 807 808 809
}

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

812 813
    const QString &url = viewer->source().toString();
    if (url.isEmpty() || url == Help::Constants::AboutBlank)
con's avatar
con committed
814 815
        return;

kh1's avatar
kh1 committed
816
    BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
817
    manager->showBookmarkDialog(m_centralWidget, viewer->title(), url);
con's avatar
con committed
818 819
}

kh1's avatar
kh1 committed
820
void HelpPlugin::handleHelpRequest(const QUrl &url)
con's avatar
con committed
821
{
kh1's avatar
kh1 committed
822
    if (HelpViewer::launchWithExternalApp(url))
823 824
        return;

825 826
    QString address = url.toString();
    if (!Core::HelpManager::instance()->findFile(url).isValid()) {
kh1's avatar
kh1 committed
827 828 829 830 831
        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")) {
832
                    urlPrefix.append(QString::fromLatin1("qtcreator"));
kh1's avatar
kh1 committed
833 834 835 836
                } else {
                    urlPrefix.append(QLatin1String("latest"));
                }
            address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
837
        }
838 839 840 841 842 843 844 845 846
    }

    const QUrl newUrl(address);
    if (newUrl.queryItemValue(QLatin1String("view")) == QLatin1String("split")) {
        if (HelpViewer* viewer = viewerForContextMode())
            viewer->setSource(newUrl);
    } else {
        activateHelpMode();
        m_centralWidget->setSource(newUrl);
847 848
    }
}
con's avatar
con committed
849 850

Q_EXPORT_PLUGIN(HelpPlugin)