helpplugin.cpp 31.3 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

kh1's avatar
kh1 committed
83 84
#if defined(QT_NO_WEBKIT)
#   include <QtGui/QApplication>
kh's avatar
kh committed
85
#else
kh1's avatar
kh1 committed
86
#   include <QtWebKit/QWebSettings>
87 88
#endif

89
using namespace Core::Constants;
con's avatar
con committed
90 91 92
using namespace Help;
using namespace Help::Internal;

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 154 155 156 157 158 159
    connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
        SLOT(fontChanged()));
    connect(m_helpManager, SIGNAL(helpRequested(QString)), this,
        SLOT(handleHelpRequest(QString)));
    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

    // Add Index, Contents, and Context menu items and a separator to the Help menu
200 201 202 203 204 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("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()));

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

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

        a = new QAction(tr("Reset Font Size"), this);
mae's avatar
mae committed
251
        cmd = am->registerAction(a,  TextEditor::Constants::RESET_FONT_SIZE,
252 253 254 255
            modecontext);
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+0")));
        connect(a, SIGNAL(triggered()), m_centralWidget, SLOT(resetZoom()));
        advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
256 257
    }

258 259 260 261
    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
262
    m_splitter->addWidget(m_mainWidget);
263 264 265 266 267 268
    QVBoxLayout *mainWidgetLayout = new QVBoxLayout(m_mainWidget);
    mainWidgetLayout->setMargin(0);
    mainWidgetLayout->setSpacing(0);
    mainWidgetLayout->addWidget(createToolBar());
    mainWidgetLayout->addWidget(m_centralWidget);

269 270 271 272 273 274 275
    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)));

276 277 278 279 280 281 282
    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
283 284 285
    return true;
}

286
void HelpPlugin::extensionsInitialized()
287
{
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
    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()));
337 338
}

339
void HelpPlugin::shutdown()
340
{
341 342
    if (m_sideBar)
        m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar"));
343 344
}

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

    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)));
360 361 362 363

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

    ContentWindow *contentWindow = new ContentWindow();
    contentWindow->setWindowTitle(tr("Contents"));
    m_contentItem = new Core::SideBarItem(contentWindow);
373 374
    connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
375 376 377

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

    SearchWidget *searchWidget = new SearchWidget();
    searchWidget->setWindowTitle(tr("Search"));
    m_searchItem = new Core::SideBarItem(searchWidget);
387 388
    connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSourceFromSearch(QUrl)));
389 390 391 392

    // TODO: enable and find a proper keysequence as this is ambiguous
    // shortcut = new QShortcut(m_splitter);
    // shortcut->setWhatsThis(tr("Activate Search in Help mode"));
393 394
    // cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"),
    //     modecontext);
395 396 397 398 399 400 401 402
    // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
    // connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
    // shortcutMap.insert(searchWidget->windowTitle(), cmd);

    BookmarkManager *manager = &HelpManager::bookmarkManager();
    BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
    bookmarkWidget->setWindowTitle(tr("Bookmarks"));
    m_bookmarkItem = new Core::SideBarItem(bookmarkWidget);
403 404
    connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSource(QUrl)));
405 406 407 408

    // TODO: enable and find a proper keysequence as this is ambiguous
    // shortcut = new QShortcut(m_splitter);
    // shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
409 410
    // cmd = am->registerShortcut(shortcut, QLatin1String("Help.BookmarkShortcut"),
    //     modecontext);
411 412 413 414
    // cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_B));
    // connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
    // shortcutMap.insert(bookmarkWidget->windowTitle(), cmd);

415 416 417 418 419 420 421 422 423 424 425 426
    QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
    openPagesWidget->setWindowTitle(tr("Open Pages"));
    m_openPagesItem = new Core::SideBarItem(openPagesWidget);

    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()));
    shortcutMap.insert(openPagesWidget->windowTitle(), cmd);

427
    QList<Core::SideBarItem*> itemList;
428 429 430 431
    itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem
        << m_openPagesItem;
    m_sideBar = new Core::SideBar(itemList, QList<Core::SideBarItem*>()
        << m_indexItem << m_openPagesItem);
432 433 434
    m_sideBar->setShortcutMap(shortcutMap);

    m_splitter->setOpaqueResize(false);
con's avatar
con committed
435
    m_splitter->insertWidget(0, m_sideBar);
436 437 438 439
    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"));
440 441
}

kh1's avatar
kh1 committed
442 443 444 445
void HelpPlugin::resetFilter()
{
    const QLatin1String weAddedFilterKey("UnfilteredFilterInserted");
    const QLatin1String previousFilterNameKey("UnfilteredFilterName");
446 447 448

    QHelpEngineCore *core = &m_helpManager->helpEngineCore();
    if (core->customValue(weAddedFilterKey).toInt() == 1) {
kh1's avatar
kh1 committed
449
        // we added a filter at some point, remove previously added filter
450 451 452
        const QString &filter = core->customValue(previousFilterNameKey).toString();
        if (!filter.isEmpty())
            core->removeCustomFilter(filter);
kh1's avatar
kh1 committed
453 454 455 456
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
457 458 459 460 461
    core->removeCustomFilter(filterName);
    core->addCustomFilter(filterName, QStringList());
    core->setCustomValue(weAddedFilterKey, 1);
    core->setCustomValue(previousFilterNameKey, filterName);
    (&m_helpManager->helpEngine())->setCurrentFilter(filterName);
462 463
}

464
void HelpPlugin::createRightPaneContextViewer()
con's avatar
con committed
465
{
466 467
    if (m_helpViewerForSideBar)
        return;
con's avatar
con committed
468

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

472
    QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
473
        tr("Next"), this);
474
    QAction *previous = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
475
        tr("Previous"), this);
con's avatar
con committed
476 477 478 479 480

    // Dummy layout to align the close button to the right
    QHBoxLayout *hboxLayout = new QHBoxLayout();
    hboxLayout->setSpacing(0);
    hboxLayout->setMargin(0);
481 482 483 484 485 486 487

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

488
    hboxLayout->addWidget(rightPaneToolBar);
489 490 491 492
    hboxLayout->addStretch();

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

495 496 497
    // close button to the right
    hboxLayout->addWidget(closeButton);

con's avatar
con committed
498 499 500 501
    QVBoxLayout *rightPaneLayout = new QVBoxLayout;
    rightPaneLayout->setMargin(0);
    rightPaneLayout->setSpacing(0);

502 503 504 505 506 507 508 509
    QWidget *rightPaneSideBar = new QWidget;
    rightPaneSideBar->setLayout(rightPaneLayout);
    addAutoReleasedObject(new Core::BaseRightPaneWidget(rightPaneSideBar));

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

510
    m_helpViewerForSideBar = new HelpViewer(qreal(0.0), rightPaneSideBar);
511 512 513 514
    rightPaneLayout->addWidget(m_helpViewerForSideBar);
    rightPaneLayout->addWidget(new Core::FindToolBarPlaceHolder(rightPaneSideBar));
    rightPaneSideBar->setFocusProxy(m_helpViewerForSideBar);

con's avatar
con committed
515 516 517
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(m_helpViewerForSideBar);
    agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
518 519 520
    m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar, QList<int>()
        << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_HELP_SIDEBAR), this));

521
#if defined(QT_NO_WEBKIT)
522 523
    m_helpViewerForSideBar->setFont(qVariantValue<QFont>(m_helpManager->helpEngineCore()
        .customValue(QLatin1String("font"), QApplication::font())));
524
#endif
525

526 527 528 529 530
    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());
531

532 533 534
    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
535 536
}

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

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

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

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

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

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

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

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

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

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

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

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

607 608 609 610
void HelpPlugin::fontChanged()
{
    if (!m_helpViewerForSideBar)
        createRightPaneContextViewer();
611

612 613 614 615 616 617 618 619 620
    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);
621 622 623
    }
}

624 625 626 627 628 629
void HelpPlugin::setupHelpEngineIfNeeded()
{
    if (Core::ICore::instance()->modeManager()->currentMode() == m_mode)
        m_helpManager->setupGuiHelpEngine();
}

630
HelpViewer* HelpPlugin::viewerForContextMode()
con's avatar
con committed
631
{
632
    using namespace Core;
633

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

656 657
        default: // help mode
            break;
658 659
    }

660
    HelpViewer *viewer = m_centralWidget->currentHelpViewer();
661
    if (placeHolder && showSideBySide) {
662
        RightPaneWidget::instance()->setShown(true);
663 664

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

void HelpPlugin::activateContext()
{
676
    using namespace Core;
677
    createRightPaneContextViewer();
678

679
    RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
680 681 682 683 684 685 686 687 688 689
    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
690
    if (IContext *context = m_core->currentContextObject()) {
691
        id = context->contextHelpId();
692
        links = m_helpManager->helpEngineCore().linksForIdentifier(id);
693 694
    }

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

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

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

void HelpPlugin::activateSearch()
{
hjk's avatar
hjk committed
727
    activateHelpMode();
con's avatar
con committed
728 729 730
    m_sideBar->activateItem(m_searchItem);
}

731 732 733 734 735 736
void HelpPlugin::activateOpenPages()
{
    activateHelpMode();
    m_sideBar->activateItem(m_openPagesItem);
}

con's avatar
con committed
737 738 739
QToolBar *HelpPlugin::createToolBar()
{
    QToolBar *toolWidget = new QToolBar;
740
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
741 742 743 744 745 746 747 748 749 750
    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;
751 752
    toolWidget->addWidget(w);

con's avatar
con committed
753 754 755
    QHBoxLayout *layout = new QHBoxLayout(w);
    layout->setMargin(0);
    layout->addSpacing(10);
756
    layout->addWidget(OpenPagesManager::instance().openPagesComboBox());
757

con's avatar
con committed
758 759 760
    layout->addWidget(new QLabel(tr("Filtered by:")));
    m_filterComboBox = new QComboBox;
    m_filterComboBox->setMinimumContentsLength(20);
761
    layout->addWidget(m_filterComboBox);
kh's avatar
kh committed
762 763
    connect(m_filterComboBox, SIGNAL(activated(QString)), this,
        SLOT(filterDocumentation(QString)));
764 765 766 767 768 769 770 771 772 773 774 775
    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
776 777 778 779 780 781

    return toolWidget;
}

void HelpPlugin::updateFilterComboBox()
{
782
    const QHelpEngine &engine = m_helpManager->helpEngine();
con's avatar
con committed
783 784
    QString curFilter = m_filterComboBox->currentText();
    if (curFilter.isEmpty())
785
        curFilter = engine.currentFilter();
con's avatar
con committed
786
    m_filterComboBox->clear();
787
    m_filterComboBox->addItems(engine.customFilters());
con's avatar
con committed
788 789 790 791 792 793 794 795
    int idx = m_filterComboBox->findText(curFilter);
    if (idx < 0)
        idx = 0;
    m_filterComboBox->setCurrentIndex(idx);
}

void HelpPlugin::filterDocumentation(const QString &customFilter)
{
796
    (&m_helpManager->helpEngine())->setCurrentFilter(customFilter);
con's avatar
con committed
797 798 799 800
}

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

803 804
    const QString &url = viewer->source().toString();
    if (url.isEmpty() || url == Help::Constants::AboutBlank)
con's avatar
con committed
805 806
        return;

807
    BookmarkManager *manager = &HelpManager::bookmarkManager();
808
    manager->showBookmarkDialog(m_centralWidget, viewer->title(), url);
con's avatar
con committed
809 810
}

811
void HelpPlugin::handleHelpRequest(const QString &address)
con's avatar
con committed
812
{
813 814 815
    if (HelpViewer::launchWithExternalApp(address))
        return;

816
    if (m_helpManager->helpEngineCore().findFile(address).isValid()) {
817 818 819 820 821 822 823 824
        const QUrl url(address);
        if (url.queryItemValue(QLatin1String("view")) == QLatin1String("split")) {
            if (HelpViewer* viewer = viewerForContextMode())
                viewer->setSource(url);
        } else {
            activateHelpMode();
            m_centralWidget->setSource(url);
        }
825 826 827
    } else {
        // local help not installed, resort to external web help
        QString urlPrefix;
828
        if (address.startsWith(QLatin1String("qthelp://com.nokia.qtcreator"))) {
829 830
            urlPrefix = QString::fromLatin1("http://doc.trolltech.com/qtcreator"
                "-%1.%2/").arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR);
831 832 833
        } else {
            urlPrefix = QLatin1String("http://doc.trolltech.com/latest/");
        }
834
        QDesktopServices::openUrl(QUrl(urlPrefix + address.mid(address
835
            .lastIndexOf(QLatin1Char('/')) + 1)));
836 837
    }
}
con's avatar
con committed
838 839

Q_EXPORT_PLUGIN(HelpPlugin)