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>
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
81
#include <QtHelp/QHelpEngine>

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

85
86
87
88
89
const char * const SB_INDEX = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index");
const char * const SB_CONTENTS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Contents");
const char * const SB_BOOKMARKS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Bookmarks");
const char * const SB_SEARCH = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Search");

90
91
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();
122
    Core::Context globalcontext(Core::Constants::C_GLOBAL);
123
    Core::Context modecontext(Constants::C_MODE_HELP);
con's avatar
con committed
124

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

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

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

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

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

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

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

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

194
    // Add Contents, Index, and Context menu items and a separator to the Help menu
195
    action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), tr(SB_CONTENTS), this);
196
197
198
199
    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()));

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

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

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

222
223
224
225
226
    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());
227

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

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

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

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

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

292
293
294
295
296
297
298
    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)));

299
300
301
302
303
    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));
304
    m_mode->setContext(modecontext);
305

con's avatar
con committed
306
307
308
    return true;
}

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

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

    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
324
    // without a qt development version. TODO: is this still really needed, remove
325
326
327
328
329
330
331
    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")));
332
    helpManager->registerDocumentation(filesToRegister);
333
334
}

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

341
void HelpPlugin::setupUi()
342
{
343
344
    // side bar widgets and shortcuts
    Core::ActionManager *am = m_core->actionManager();
345
    Core::Context modecontext(Constants::C_MODE_HELP);
346
347

    IndexWindow *indexWindow = new IndexWindow();
348
    indexWindow->setWindowTitle(tr(SB_INDEX));
349
    m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX));
350
351
352
353
354

    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)));
355
356
357
358

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

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

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

    SearchWidget *searchWidget = new SearchWidget();
380
381
    searchWidget->setWindowTitle(tr(SB_SEARCH));
    m_searchItem = new Core::SideBarItem(searchWidget, QLatin1String(SB_SEARCH));
382
383
    connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
        SLOT(setSourceFromSearch(QUrl)));
384

kh1's avatar
kh1 committed
385
386
387
388
389
390
     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()));
con's avatar
con committed
391
     shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
392

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

kh1's avatar
kh1 committed
400
401
402
403
404
405
     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()));
con's avatar
con committed
406
     shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
407

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

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

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

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

kh1's avatar
kh1 committed
435
436
void HelpPlugin::resetFilter()
{
kh1's avatar
kh1 committed
437
438
439
440
441
442
443
444
445
446
447
    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
448
449
    const QLatin1String weAddedFilterKey("UnfilteredFilterInserted");
    const QLatin1String previousFilterNameKey("UnfilteredFilterName");
kh1's avatar
kh1 committed
450
    if (engine->customValue(weAddedFilterKey).toInt() == 1) {
kh1's avatar
kh1 committed
451
        // we added a filter at some point, remove previously added filter
kh1's avatar
kh1 committed
452
        const QString &filter = engine->customValue(previousFilterNameKey).toString();
453
        if (!filter.isEmpty())
kh1's avatar
kh1 committed
454
            engine->removeCustomFilter(filter);
kh1's avatar
kh1 committed
455
456
457
458
    }

    // potentially remove a filter with new name
    const QString filterName = tr("Unfiltered");
kh1's avatar
kh1 committed
459
460
461
462
463
464
465
466
    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()));
467
468
}

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

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

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

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

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

493
    hboxLayout->addWidget(rightPaneToolBar);
494
495
496
497
    hboxLayout->addStretch();

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

500
501
502
    // close button to the right
    hboxLayout->addWidget(closeButton);

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

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

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

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

con's avatar
con committed
520
521
522
    Aggregation::Aggregate *agg = new Aggregation::Aggregate();
    agg->add(m_helpViewerForSideBar);
    agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
523
524
    m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar,
        Core::Context(Constants::C_HELP_SIDEBAR), this));
525

526
527
    QAction *copy = new QAction(this);
    Core::Command *cmd = m_core->actionManager()->registerAction(copy, Core::Constants::COPY,
528
        Core::Context(Constants::C_HELP_SIDEBAR));
529
530
    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

kh1's avatar
kh1 committed
574
        m_helpManager->setupGuiHelpEngine();
575
        setupUi();
kh1's avatar
kh1 committed
576
        resetFilter();
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

kh1's avatar
kh1 committed
612
    const QHelpEngine &engine = LocalHelpManager::helpEngine();
613
614
615
616
617
618
619
620
    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
void HelpPlugin::setupHelpEngineIfNeeded()
{
kh1's avatar
kh1 committed
626
627
    m_helpManager->setEngineNeedsUpdate();
    if (Core::ModeManager::instance()->currentMode() == m_mode)
628
629
630
        m_helpManager->setupGuiHelpEngine();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return toolWidget;
}

void HelpPlugin::updateFilterComboBox()
{
kh1's avatar
kh1 committed
789
    const QHelpEngine &engine = LocalHelpManager::helpEngine();
con's avatar
con committed
790
791
    QString curFilter = m_filterComboBox->currentText();
    if (curFilter.isEmpty())
792
        curFilter = engine.currentFilter();
con's avatar
con committed
793
    m_filterComboBox->clear();
794
    m_filterComboBox->addItems(engine.customFilters());
con's avatar
con committed
795
796
797
798
799
800
801
802
    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
803
    LocalHelpManager::helpEngine().setCurrentFilter(customFilter);
con's avatar
con committed
804
805
806
807
}

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

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

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

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

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

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

Q_EXPORT_PLUGIN(HelpPlugin)