OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / help / helpplugin.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "helpplugin.h"
34
35 #include "bookmarkmanager.h"
36 #include "centralwidget.h"
37 #include "contentwindow.h"
38 #include "docsettingspage.h"
39 #include "externalhelpwindow.h"
40 #include "filtersettingspage.h"
41 #include "generalsettingspage.h"
42 #include "helpconstants.h"
43 #include "helpfindsupport.h"
44 #include "helpindexfilter.h"
45 #include "helpmode.h"
46 #include "helpviewer.h"
47 #include "indexwindow.h"
48 #include "localhelpmanager.h"
49 #include "openpagesmanager.h"
50 #include "openpagesmodel.h"
51 #include "remotehelpfilter.h"
52 #include "searchwidget.h"
53
54 #include <coreplugin/actionmanager/actionmanager.h>
55 #include <coreplugin/actionmanager/actioncontainer.h>
56 #include <coreplugin/actionmanager/command.h>
57 #include <coreplugin/uniqueidmanager.h>
58 #include <coreplugin/coreconstants.h>
59 #include <coreplugin/editormanager/editormanager.h>
60 #include <coreplugin/editormanager/ieditor.h>
61 #include <coreplugin/findplaceholder.h>
62 #include <coreplugin/icore.h>
63 #include <coreplugin/helpmanager.h>
64 #include <coreplugin/minisplitter.h>
65 #include <coreplugin/modemanager.h>
66 #include <coreplugin/rightpane.h>
67 #include <coreplugin/sidebar.h>
68 #include <extensionsystem/pluginmanager.h>
69 #include <find/findplugin.h>
70 #include <texteditor/texteditorconstants.h>
71 #include <utils/styledbar.h>
72 #include <welcome/welcomemode.h>
73
74 #include <QtCore/QDir>
75 #include <QtCore/QFileInfo>
76 #include <QtCore/QLibraryInfo>
77 #include <QtCore/QTimer>
78 #include <QtCore/QTranslator>
79 #include <QtCore/qplugin.h>
80 #include <QtCore/QRegExp>
81
82 #include <QtGui/QAction>
83 #include <QtGui/QComboBox>
84 #include <QtGui/QDesktopServices>
85 #include <QtGui/QMenu>
86 #include <QtGui/QShortcut>
87 #include <QtGui/QStackedLayout>
88 #include <QtGui/QSplitter>
89
90 #include <QtHelp/QHelpEngine>
91
92 #if !defined(QT_NO_WEBKIT)
93 #include <QtWebKit/QWebElement>
94 #include <QtWebKit/QWebElementCollection>
95 #include <QtWebKit/QWebFrame>
96 #include <QtWebKit/QWebHistory>
97 #endif
98
99 using namespace Core::Constants;
100 using namespace Help::Internal;
101
102 const char * const SB_INDEX = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index");
103 const char * const SB_CONTENTS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Contents");
104 const char * const SB_BOOKMARKS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Bookmarks");
105 const char * const SB_SEARCH = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Search");
106
107 const char * const SB_OPENPAGES = "OpenPages";
108
109 #define IMAGEPATH ":/help/images/"
110 #if defined(Q_OS_MAC)
111 #   define DOCPATH "/../Resources/doc/"
112 #else
113 #   define DOCPATH "/../share/doc/qtcreator/"
114 #endif
115
116 namespace {
117     QToolButton* toolButton(QAction *action)
118     {
119         QToolButton *button = new QToolButton;
120         button->setDefaultAction(action);
121         button->setPopupMode(QToolButton::DelayedPopup);
122         return button;
123     }
124 }
125
126 HelpPlugin::HelpPlugin()
127     : m_mode(0),
128     m_core(0),
129     m_centralWidget(0),
130     m_rightPaneSideBarWidget(0),
131     m_helpViewerForSideBar(0),
132     m_contentItem(0),
133     m_indexItem(0),
134     m_searchItem(0),
135     m_bookmarkItem(0),
136     m_sideBar(0),
137     m_firstModeChange(true),
138     m_oldMode(0),
139     m_connectWindow(true),
140     m_externalWindow(0),
141     m_backMenu(0),
142     m_nextMenu(0)
143 {
144 }
145
146 HelpPlugin::~HelpPlugin()
147 {
148     delete m_rightPaneSideBarWidget;
149 }
150
151 bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
152 {
153     Q_UNUSED(arguments)
154     Q_UNUSED(error)
155     m_core = Core::ICore::instance();
156     Core::Context globalcontext(Core::Constants::C_GLOBAL);
157     Core::Context modecontext(Constants::C_MODE_HELP);
158
159     const QString &locale = m_core->userInterfaceLanguage();
160     if (!locale.isEmpty()) {
161         QTranslator *qtr = new QTranslator(this);
162         QTranslator *qhelptr = new QTranslator(this);
163         const QString &creatorTrPath = Core::ICore::instance()->resourcePath()
164             + QLatin1String("/translations");
165         const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
166         const QString &trFile = QLatin1String("assistant_") + locale;
167         const QString &helpTrFile = QLatin1String("qt_help_") + locale;
168         if (qtr->load(trFile, qtTrPath) || qtr->load(trFile, creatorTrPath))
169             qApp->installTranslator(qtr);
170         if (qhelptr->load(helpTrFile, qtTrPath) || qhelptr->load(helpTrFile, creatorTrPath))
171             qApp->installTranslator(qhelptr);
172     }
173
174     addAutoReleasedObject(m_helpManager = new LocalHelpManager(this));
175     addAutoReleasedObject(m_openPagesManager = new OpenPagesManager(this));
176     addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage());
177     addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage());
178     addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage());
179
180     connect(m_generalSettingsPage, SIGNAL(fontChanged()), this,
181         SLOT(fontChanged()));
182     connect(m_generalSettingsPage, SIGNAL(contextHelpOptionChanged()), this,
183         SLOT(contextHelpOptionChanged()));
184     connect(m_generalSettingsPage, SIGNAL(returnOnCloseChanged()), this,
185         SLOT(updateCloseButton()));
186     connect(Core::HelpManager::instance(), SIGNAL(helpRequested(QUrl)), this,
187         SLOT(handleHelpRequest(QUrl)));
188
189     connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this,
190         SLOT(setupHelpEngineIfNeeded()));
191     connect(Core::HelpManager::instance(), SIGNAL(documentationChanged()), this,
192         SLOT(setupHelpEngineIfNeeded()));
193     connect(Core::HelpManager::instance(), SIGNAL(collectionFileChanged()), this,
194         SLOT(setupHelpEngineIfNeeded()));
195
196     m_splitter = new Core::MiniSplitter;
197     m_centralWidget = new Help::Internal::CentralWidget();
198     connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
199         SLOT(updateSideBarSource(QUrl)));
200     connect(m_centralWidget, SIGNAL(openFindToolBar()), this,
201         SLOT(openFindToolBar()));
202
203     // Add Home, Previous and Next actions (used in the toolbar)
204     QAction *action = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")),
205         tr("Home"), this);
206     Core::ActionManager *am = m_core->actionManager();
207     Core::Command *cmd = am->registerAction(action, "Help.Home", globalcontext);
208     connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
209
210     action = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
211         tr("Previous Page"), this);
212     cmd = am->registerAction(action, Core::Id("Help.Previous"), modecontext);
213     cmd->setDefaultKeySequence(QKeySequence::Back);
214     action->setEnabled(m_centralWidget->isBackwardAvailable());
215     connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(backward()));
216     connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), action,
217         SLOT(setEnabled(bool)));
218
219     action = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next Page"),
220         this);
221     cmd = am->registerAction(action, Core::Id("Help.Next"), modecontext);
222     cmd->setDefaultKeySequence(QKeySequence::Forward);
223     action->setEnabled(m_centralWidget->isForwardAvailable());
224     connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(forward()));
225     connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), action,
226         SLOT(setEnabled(bool)));
227
228     action = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")),
229         tr("Add Bookmark"), this);
230     cmd = am->registerAction(action, Core::Id("Help.AddBookmark"),
231         modecontext);
232     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_M));
233     connect(action, SIGNAL(triggered()), this, SLOT(addBookmark()));
234
235     // Add Contents, Index, and Context menu items and a separator to the Help menu
236     action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")),
237         tr(SB_CONTENTS), this);
238     cmd = am->registerAction(action, Core::Id("Help.Contents"), globalcontext);
239     am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
240     connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));
241
242     action = new QAction(tr(SB_INDEX), this);
243     cmd = am->registerAction(action, Core::Id("Help.Index"), globalcontext);
244     am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
245     connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));
246
247     action = new QAction(tr("Context Help"), this);
248     cmd = am->registerAction(action, Core::Id("Help.Context"), globalcontext);
249     am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
250     cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
251     connect(action, SIGNAL(triggered()), this, SLOT(activateContext()));
252
253 #ifndef Q_WS_MAC
254     action = new QAction(this);
255     action->setSeparator(true);
256     cmd = am->registerAction(action, Core::Id("Help.Separator"), globalcontext);
257     am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
258 #endif
259
260     action = new QAction(this);
261     am->registerAction(action, Core::Constants::PRINT, modecontext);
262     connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(print()));
263
264     action = new QAction(this);
265     cmd = am->registerAction(action, Core::Constants::COPY, modecontext);
266     connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(copy()));
267     action->setText(cmd->action()->text());
268     action->setIcon(cmd->action()->icon());
269
270     if (Core::ActionContainer *advancedMenu = am->actionContainer(M_EDIT_ADVANCED)) {
271         // reuse TextEditor constants to avoid a second pair of menu actions
272         action = new QAction(tr("Increase Font Size"), this);
273         cmd = am->registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE,
274             modecontext);
275         connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomIn()));
276         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
277
278         action = new QAction(tr("Decrease Font Size"), this);
279         cmd = am->registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE,
280             modecontext);
281         connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomOut()));
282         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
283
284         action = new QAction(tr("Reset Font Size"), this);
285         cmd = am->registerAction(action, TextEditor::Constants::RESET_FONT_SIZE,
286             modecontext);
287         connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(resetZoom()));
288         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
289     }
290
291     if (Core::ActionContainer *windowMenu = am->actionContainer(M_WINDOW)) {
292         // reuse EditorManager constants to avoid a second pair of menu actions
293         action = new QAction(QApplication::translate("EditorManager",
294             "Next Open Document in History"), this);
295         Core::Command *ctrlTab = am->registerAction(action, GOTOPREVINHISTORY,
296             modecontext);   // Goto Previous In History Action
297         windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE);
298         connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
299             SLOT(gotoPreviousPage()));
300
301         action = new QAction(QApplication::translate("EditorManager",
302             "Previous Open Document in History"), this);
303         Core::Command *ctrlShiftTab = am->registerAction(action, GOTONEXTINHISTORY,
304             modecontext);   // Goto Next In History Action
305         windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE);
306         connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(),
307             SLOT(gotoNextPage()));
308     }
309
310     Aggregation::Aggregate *agg = new Aggregation::Aggregate;
311     agg->add(m_centralWidget);
312     agg->add(new HelpFindSupport(m_centralWidget));
313
314     QWidget *toolBarWidget = new QWidget;
315     QHBoxLayout *toolBarLayout = new QHBoxLayout(toolBarWidget);
316     toolBarLayout->setMargin(0);
317     toolBarLayout->setSpacing(0);
318     toolBarLayout->addWidget(m_externalHelpBar = createIconToolBar(true));
319     toolBarLayout->addWidget(m_internalHelpBar = createIconToolBar(false));
320     toolBarLayout->addWidget(createWidgetToolBar());
321
322     QWidget *mainWidget = new QWidget;
323     m_splitter->addWidget(mainWidget);
324     QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget);
325     mainWidgetLayout->setMargin(0);
326     mainWidgetLayout->setSpacing(0);
327     mainWidgetLayout->addWidget(toolBarWidget);
328     mainWidgetLayout->addWidget(m_centralWidget);
329
330     if (QLayout *layout = m_centralWidget->layout()) {
331         layout->setSpacing(0);
332         Core::FindToolBarPlaceHolder *fth = new Core::FindToolBarPlaceHolder(m_centralWidget);
333         fth->setObjectName(QLatin1String("HelpFindToolBarPlaceHolder"));
334         layout->addWidget(fth);
335     }
336
337     HelpIndexFilter *helpIndexFilter = new HelpIndexFilter();
338     addAutoReleasedObject(helpIndexFilter);
339     connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)), this,
340         SLOT(switchToHelpMode(QUrl)));
341
342     RemoteHelpFilter *remoteHelpFilter = new RemoteHelpFilter();
343     addAutoReleasedObject(remoteHelpFilter);
344     connect(remoteHelpFilter, SIGNAL(linkActivated(QUrl)), this,
345         SLOT(switchToHelpMode(QUrl)));
346
347     QDesktopServices::setUrlHandler("qthelp", this, "handleHelpRequest");
348     connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*,
349         Core::IMode*)), this, SLOT(modeChanged(Core::IMode*, Core::IMode*)));
350
351     m_externalWindow = new ExternalHelpWindow;
352     m_mode = new HelpMode;
353     if (contextHelpOption() == Help::Constants::ExternalHelpAlways) {
354         m_mode->setWidget(new QWidget);
355         m_mode->setEnabled(false);
356         m_externalHelpBar->setVisible(true);
357         m_externalWindow->setCentralWidget(m_splitter);
358         QTimer::singleShot(0, this, SLOT(showExternalWindow()));
359     } else {
360         m_mode->setWidget(m_splitter);
361         m_internalHelpBar->setVisible(true);
362     }
363     addAutoReleasedObject(m_mode);
364
365     return true;
366 }
367
368 void HelpPlugin::extensionsInitialized()
369 {
370     const QString &nsInternal = QString::fromLatin1("com.nokia.qtcreator.%1%2%3")
371         .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
372
373     Core::HelpManager *helpManager = Core::HelpManager::instance();
374     foreach (const QString &ns, helpManager->registeredNamespaces()) {
375         if (ns.startsWith(QLatin1String("com.nokia.qtcreator."))
376             && ns != nsInternal)
377             helpManager->unregisterDocumentation(QStringList() << ns);
378     }
379
380     QStringList filesToRegister;
381     // Explicitly register qml.qch if located in creator directory. This is only
382     // needed for the creator-qml package, were we want to ship the documentation
383     // without a qt development version. TODO: is this still really needed, remove
384     const QString &appPath = QCoreApplication::applicationDirPath();
385     filesToRegister.append(QDir::cleanPath(QDir::cleanPath(appPath
386         + QLatin1String(DOCPATH "qml.qch"))));
387
388     // we might need to register creators inbuild help
389     filesToRegister.append(QDir::cleanPath(appPath
390         + QLatin1String(DOCPATH "qtcreator.qch")));
391     helpManager->registerDocumentation(filesToRegister);
392 }
393
394 ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
395 {
396     if (m_sideBar)
397         m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar"));
398     delete m_externalWindow;
399
400     return SynchronousShutdown;
401 }
402
403 void HelpPlugin::setupUi()
404 {
405     // side bar widgets and shortcuts
406     Core::ActionManager *am = m_core->actionManager();
407     Core::Context modecontext(Constants::C_MODE_HELP);
408
409     IndexWindow *indexWindow = new IndexWindow();
410     indexWindow->setWindowTitle(tr(SB_INDEX));
411     m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX));
412
413     connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
414         SLOT(setSource(QUrl)));
415     connect(indexWindow, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)),
416         m_centralWidget, SLOT(showTopicChooser(QMap<QString, QUrl>, QString)));
417
418     QMap<QString, Core::Command*> shortcutMap;
419     QShortcut *shortcut = new QShortcut(m_splitter);
420     shortcut->setWhatsThis(tr("Activate Index in Help mode"));
421     Core::Command* cmd = am->registerShortcut(shortcut,
422         Core::Id("Help.IndexShortcut"), modecontext);
423     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
424     connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex()));
425     shortcutMap.insert(QLatin1String(SB_INDEX), cmd);
426
427     ContentWindow *contentWindow = new ContentWindow();
428     contentWindow->setWindowTitle(tr(SB_CONTENTS));
429     m_contentItem = new Core::SideBarItem(contentWindow, Core::Id(SB_CONTENTS));
430     connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
431         SLOT(setSource(QUrl)));
432
433     shortcut = new QShortcut(m_splitter);
434     shortcut->setWhatsThis(tr("Activate Contents in Help mode"));
435     cmd = am->registerShortcut(shortcut, Core::Id("Help.ContentsShortcut"),
436         modecontext);
437     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
438     connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents()));
439     shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd);
440
441     SearchWidget *searchWidget = new SearchWidget();
442     searchWidget->setWindowTitle(tr(SB_SEARCH));
443     m_searchItem = new Core::SideBarItem(searchWidget, QLatin1String(SB_SEARCH));
444     connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
445         SLOT(setSourceFromSearch(QUrl)));
446
447      shortcut = new QShortcut(m_splitter);
448      shortcut->setWhatsThis(tr("Activate Search in Help mode"));
449      cmd = am->registerShortcut(shortcut, Core::Id("Help.SearchShortcut"),
450          modecontext);
451      cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Slash));
452      connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
453      shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
454
455     BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
456     BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
457     bookmarkWidget->setWindowTitle(tr(SB_BOOKMARKS));
458     m_bookmarkItem = new Core::SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS));
459     connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
460         SLOT(setSource(QUrl)));
461
462      shortcut = new QShortcut(m_splitter);
463      shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode"));
464      cmd = am->registerShortcut(shortcut, Core::Id("Help.BookmarkShortcut"),
465          modecontext);
466      cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B));
467      connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
468      shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
469
470     QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
471     openPagesWidget->setWindowTitle(tr("Open Pages"));
472     m_openPagesItem = new Core::SideBarItem(openPagesWidget, QLatin1String(SB_OPENPAGES));
473
474     shortcut = new QShortcut(m_splitter);
475     shortcut->setWhatsThis(tr("Activate Open Pages in Help mode"));
476     cmd = am->registerShortcut(shortcut, Core::Id("Help.PagesShortcut"),
477         modecontext);
478     cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_O));
479     connect(shortcut, SIGNAL(activated()), this, SLOT(activateOpenPages()));
480     shortcutMap.insert(QLatin1String(SB_OPENPAGES), cmd);
481
482     QList<Core::SideBarItem*> itemList;
483     itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem
484         << m_openPagesItem;
485     m_sideBar = new Core::SideBar(itemList, QList<Core::SideBarItem*>()
486         << m_contentItem << m_openPagesItem);
487     m_sideBar->setShortcutMap(shortcutMap);
488
489     m_splitter->setOpaqueResize(false);
490     m_splitter->insertWidget(0, m_sideBar);
491     m_splitter->setStretchFactor(0, 0);
492     m_splitter->setStretchFactor(1, 1);
493     m_sideBar->readSettings(m_core->settings(), QLatin1String("HelpSideBar"));
494     m_splitter->setSizes(QList<int>() << m_sideBar->size().width() << 300);
495 }
496
497 void HelpPlugin::resetFilter()
498 {
499     const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
500         .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE);
501     const QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*"));
502
503     QHelpEngineCore *engine = &LocalHelpManager::helpEngine();
504     const QStringList &filters = engine->customFilters();
505     foreach (const QString &filter, filters) {
506         if (filterRegExp.exactMatch(filter) && filter != filterInternal)
507             engine->removeCustomFilter(filter);
508     }
509
510     // we added a filter at some point, remove previously added filter
511     if (engine->customValue(Help::Constants::WeAddedFilterKey).toInt() == 1) {
512         const QString &filter =
513             engine->customValue(Help::Constants::PreviousFilterNameKey).toString();
514         if (!filter.isEmpty())
515             engine->removeCustomFilter(filter);
516     }
517
518     // potentially remove a filter with new name
519     const QString filterName = tr("Unfiltered");
520     engine->removeCustomFilter(filterName);
521     engine->addCustomFilter(filterName, QStringList());
522     engine->setCustomValue(Help::Constants::WeAddedFilterKey, 1);
523     engine->setCustomValue(Help::Constants::PreviousFilterNameKey, filterName);
524     engine->setCurrentFilter(filterName);
525
526     updateFilterComboBox();
527     connect(engine, SIGNAL(setupFinished()), this, SLOT(updateFilterComboBox()));
528 }
529
530 void HelpPlugin::createRightPaneContextViewer()
531 {
532     if (m_rightPaneSideBarWidget)
533         return;
534
535     Utils::StyledBar *toolBar = new Utils::StyledBar();
536
537     QAction *switchToHelp = new QAction(tr("Go to Help Mode"), toolBar);
538     connect(switchToHelp, SIGNAL(triggered()), this, SLOT(switchToHelpMode()));
539     QAction *back = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
540         tr("Previous"), toolBar);
541     QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
542         tr("Next"), toolBar);
543     QAction *close = new QAction(QIcon(QLatin1String(Core::Constants::ICON_CLOSE)),
544         QLatin1String(""), toolBar);
545     connect(close, SIGNAL(triggered()), this, SLOT(slotHideRightPane()));
546
547     setupNavigationMenus(back, next, toolBar);
548
549     QHBoxLayout *layout = new QHBoxLayout(toolBar);
550     layout->setSpacing(0);
551     layout->setMargin(0);
552
553     layout->addWidget(toolButton(switchToHelp));
554     layout->addWidget(toolButton(back));
555     layout->addWidget(toolButton(next));
556     layout->addStretch();
557     layout->addWidget(toolButton(close));
558
559     m_rightPaneSideBarWidget = new QWidget;
560     m_helpViewerForSideBar = new HelpViewer(qreal(0.0));
561     connect(m_helpViewerForSideBar, SIGNAL(openFindToolBar()), this,
562         SLOT(openFindToolBar()));
563 #if !defined(QT_NO_WEBKIT)
564     m_helpViewerForSideBar->pageAction(QWebPage::OpenLinkInNewWindow)->setVisible(false);
565 #endif
566
567     QVBoxLayout *rightPaneLayout = new QVBoxLayout(m_rightPaneSideBarWidget);
568     rightPaneLayout->setMargin(0);
569     rightPaneLayout->setSpacing(0);
570     rightPaneLayout->addWidget(toolBar);
571     rightPaneLayout->addWidget(m_helpViewerForSideBar);
572     Core::FindToolBarPlaceHolder *fth = new Core::FindToolBarPlaceHolder(m_rightPaneSideBarWidget);
573     fth->setObjectName(QLatin1String("HelpRightPaneFindToolBarPlaceHolder"));
574     rightPaneLayout->addWidget(fth);
575     m_rightPaneSideBarWidget->setFocusProxy(m_helpViewerForSideBar);
576
577     Aggregation::Aggregate *agg = new Aggregation::Aggregate();
578     agg->add(m_helpViewerForSideBar);
579     agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar));
580
581     Core::Context context(Constants::C_HELP_SIDEBAR);
582     m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar,
583         context, this));
584
585     QAction *copy = new QAction(this);
586     Core::Command *cmd = m_core->actionManager()->registerAction(copy,
587         Core::Constants::COPY, context);
588     copy->setText(cmd->action()->text());
589     copy->setIcon(cmd->action()->icon());
590     connect(copy, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(copy()));
591
592     next->setEnabled(m_helpViewerForSideBar->isForwardAvailable());
593     connect(next, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(forward()));
594     connect(m_helpViewerForSideBar, SIGNAL(forwardAvailable(bool)), next,
595         SLOT(setEnabled(bool)));
596
597     back->setEnabled(m_helpViewerForSideBar->isBackwardAvailable());
598     connect(back, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(backward()));
599     connect(m_helpViewerForSideBar, SIGNAL(backwardAvailable(bool)), back,
600         SLOT(setEnabled(bool)));
601
602     Core::ActionManager *am = m_core->actionManager();
603     if (Core::ActionContainer *advancedMenu = am->actionContainer(M_EDIT_ADVANCED)) {
604         // reuse TextEditor constants to avoid a second pair of menu actions
605         QAction *action = new QAction(tr("Increase Font Size"), this);
606         cmd = am->registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE,
607             context);
608         connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneUp()));
609         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
610
611         action = new QAction(tr("Decrease Font Size"), this);
612         cmd = am->registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE,
613             context);
614         connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneDown()));
615         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
616
617         action = new QAction(tr("Reset Font Size"), this);
618         cmd = am->registerAction(action, TextEditor::Constants::RESET_FONT_SIZE,
619             context);
620         connect(action, SIGNAL(triggered()), this, SLOT(resetRightPaneScale()));
621         advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT);
622     }
623
624     // force setup, as we might have never switched to full help mode
625     // thus the help engine might still run without collection file setup
626     m_helpManager->setupGuiHelpEngine();
627 }
628
629 void HelpPlugin::scaleRightPaneUp()
630 {
631     if (m_helpViewerForSideBar)
632         m_helpViewerForSideBar->scaleUp();
633 }
634
635 void HelpPlugin::scaleRightPaneDown()
636 {
637     if (m_helpViewerForSideBar)
638         m_helpViewerForSideBar->scaleDown();
639 }
640
641 void HelpPlugin::resetRightPaneScale()
642 {
643     if (m_helpViewerForSideBar)
644         m_helpViewerForSideBar->resetScale();
645 }
646
647 void HelpPlugin::activateHelpMode()
648 {
649     if (contextHelpOption() != Help::Constants::ExternalHelpAlways)
650         m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
651     else
652         showExternalWindow();
653 }
654
655 void HelpPlugin::switchToHelpMode()
656 {
657     switchToHelpMode(m_helpViewerForSideBar->source());
658 }
659
660 void HelpPlugin::switchToHelpMode(const QUrl &source)
661 {
662     activateHelpMode();
663     m_centralWidget->setSource(source);
664     m_centralWidget->setFocus();
665 }
666
667 void HelpPlugin::slotHideRightPane()
668 {
669     Core::RightPaneWidget::instance()->setShown(false);
670 }
671
672 void HelpPlugin::showHideSidebar()
673 {
674     m_sideBar->setVisible(!m_sideBar->isVisible());
675 }
676
677 void HelpPlugin::showExternalWindow()
678 {
679     bool firstTime = m_firstModeChange;
680     doSetupIfNeeded();
681     m_externalWindow->show();
682     connectExternalHelpWindow();
683     m_externalWindow->activateWindow();
684     if (firstTime)
685         Core::ICore::instance()->mainWindow()->activateWindow();
686 }
687
688 void HelpPlugin::modeChanged(Core::IMode *mode, Core::IMode *old)
689 {
690     if (mode == m_mode) {
691         m_oldMode = old;
692         qApp->setOverrideCursor(Qt::WaitCursor);
693         doSetupIfNeeded();
694         qApp->restoreOverrideCursor();
695     }
696 }
697
698 void HelpPlugin::updateSideBarSource()
699 {
700     if (HelpViewer *viewer = m_centralWidget->currentHelpViewer()) {
701         const QUrl &url = viewer->source();
702         if (url.isValid())
703             updateSideBarSource(url);
704     }
705 }
706
707 void HelpPlugin::updateSideBarSource(const QUrl &newUrl)
708 {
709     if (m_helpViewerForSideBar)
710         m_helpViewerForSideBar->setSource(newUrl);
711 }
712
713 void HelpPlugin::updateCloseButton()
714 {
715     Core::HelpManager *manager = Core::HelpManager::instance();
716     const bool closeOnReturn = manager->customValue(QLatin1String("ReturnOnClose"),
717         false).toBool();
718     m_closeButton->setEnabled((OpenPagesManager::instance().pageCount() > 1)
719         | closeOnReturn);
720 }
721
722 void HelpPlugin::fontChanged()
723 {
724     if (!m_helpViewerForSideBar)
725         createRightPaneContextViewer();
726
727     const QHelpEngine &engine = LocalHelpManager::helpEngine();
728     QFont font = qVariantValue<QFont>(engine.customValue(QLatin1String("font"),
729         m_helpViewerForSideBar->viewerFont()));
730
731     m_helpViewerForSideBar->setFont(font);
732     const int count = OpenPagesManager::instance().pageCount();
733     for (int i = 0; i < count; ++i) {
734         if (HelpViewer *viewer = CentralWidget::instance()->viewerAt(i))
735             viewer->setViewerFont(font);
736     }
737 }
738
739 QStackedLayout * layoutForWidget(QWidget *parent, QWidget *widget)
740 {
741     QList<QStackedLayout*> list = parent->findChildren<QStackedLayout*>();
742     foreach (QStackedLayout *layout, list) {
743         const int index = layout->indexOf(widget);
744         if (index >= 0)
745             return layout;
746     }
747     return 0;
748 }
749
750 void HelpPlugin::contextHelpOptionChanged()
751 {
752     doSetupIfNeeded();
753     QWidget *modeWidget = m_mode->widget();
754     if (modeWidget == m_splitter
755         && contextHelpOption() == Help::Constants::ExternalHelpAlways) {
756         if (QWidget *widget = m_splitter->parentWidget()) {
757             if (QStackedLayout *layout = layoutForWidget(widget, m_splitter)) {
758                 const int index = layout->indexOf(m_splitter);
759                 layout->removeWidget(m_splitter);
760                 m_mode->setWidget(new QWidget);
761                 layout->insertWidget(index, m_mode->widget());
762                 m_externalWindow->setCentralWidget(m_splitter);
763                 m_splitter->show();
764
765                 slotHideRightPane();
766                 m_mode->setEnabled(false);
767                 m_externalHelpBar->setVisible(true);
768                 m_internalHelpBar->setVisible(false);
769                 m_externalWindow->show();
770                 connectExternalHelpWindow();
771
772                 if (m_oldMode && m_mode == m_core->modeManager()->currentMode())
773                     m_core->modeManager()->activateMode(m_oldMode->id());
774             }
775         }
776     } else if (modeWidget != m_splitter
777         && contextHelpOption() != Help::Constants::ExternalHelpAlways) {
778         QStackedLayout *wLayout = layoutForWidget(modeWidget->parentWidget(),
779             modeWidget);
780         if (wLayout && m_splitter->parentWidget()->layout()) {
781             const int index = wLayout->indexOf(modeWidget);
782             QWidget *tmp = wLayout->widget(index);
783             wLayout->removeWidget(modeWidget);
784             delete tmp;
785
786             m_splitter->parentWidget()->layout()->removeWidget(m_splitter);
787             m_mode->setWidget(m_splitter);
788             wLayout->insertWidget(index, m_splitter);
789
790             m_mode->setEnabled(true);
791             m_externalWindow->close();
792             m_sideBar->setVisible(true);
793             m_internalHelpBar->setVisible(true);
794             m_externalHelpBar->setVisible(false);
795         }
796     }
797 }
798
799 void HelpPlugin::setupHelpEngineIfNeeded()
800 {
801     m_helpManager->setEngineNeedsUpdate();
802     if (Core::ModeManager::instance()->currentMode() == m_mode
803         || contextHelpOption() == Help::Constants::ExternalHelpAlways)
804         m_helpManager->setupGuiHelpEngine();
805 }
806
807 HelpViewer* HelpPlugin::viewerForContextMode()
808 {
809     using namespace Core;
810
811     if (m_core->modeManager()->currentMode()->id() == Core::Constants::MODE_WELCOME)
812         m_core->modeManager()->activateMode(Core::Constants::MODE_EDIT);
813
814     bool showSideBySide = false;
815     RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current();
816     switch (contextHelpOption()) {
817         case Help::Constants::SideBySideIfPossible: {
818             // side by side if possible
819             if (IEditor *editor = EditorManager::instance()->currentEditor()) {
820                 if (!placeHolder || !placeHolder->isVisible()) {
821                     if (!editor->widget())
822                         break;
823                     if (!editor->widget()->isVisible())
824                         break;
825                     if (editor->widget()->width() < 800)
826                         break;
827                 }
828             }
829         }   // fall through
830         case Help::Constants::SideBySideAlways: {
831             // side by side
832             showSideBySide = true;
833         }   break;
834
835         default: // help mode
836             break;
837     }
838
839     if (placeHolder && showSideBySide) {
840         RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget);
841         RightPaneWidget::instance()->setShown(true);
842         createRightPaneContextViewer();
843         return m_helpViewerForSideBar;
844     }
845
846     activateHelpMode(); // should trigger an createPage...
847     HelpViewer *viewer = m_centralWidget->currentHelpViewer();
848     if (!viewer)
849         viewer = OpenPagesManager::instance().createPage();
850     return viewer;
851 }
852
853 void HelpPlugin::activateContext()
854 {
855     using namespace Core;
856     createRightPaneContextViewer();
857
858     RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
859     if (placeHolder && m_helpViewerForSideBar->hasFocus()) {
860         switchToHelpMode();
861         return;
862     } else if (m_core->modeManager()->currentMode() == m_mode)
863         return;
864
865     // Find out what to show
866     QMap<QString, QUrl> links;
867     if (IContext *context = m_core->currentContextObject()) {
868         m_idFromContext = context->contextHelpId();
869         links = Core::HelpManager::instance()->linksForIdentifier(m_idFromContext);
870     }
871
872     if (HelpViewer* viewer = viewerForContextMode()) {
873         if (links.isEmpty()) {
874             // No link found or no context object
875             viewer->setSource(QUrl(Help::Constants::AboutBlank));
876             viewer->setHtml(tr("<html><head><title>No Documentation</title>"
877                 "</head><body><br/><center><b>%1</b><br/>No documentation "
878                 "available.</center></body></html>").arg(m_idFromContext));
879         } else {
880             int version = 0;
881             const QRegExp exp("(\\d+)");
882             QUrl source = *links.begin();
883             const QLatin1String qtRefDoc = QLatin1String("com.trolltech.qt");
884
885             // workaround to show the latest qt version
886             foreach (const QUrl &tmp, links) {
887                 const QString &authority = tmp.authority();
888                 if (authority.startsWith(qtRefDoc)) {
889                     if (exp.indexIn(authority) >= 0) {
890                         const int tmpVersion = exp.cap(1).toInt();
891                         if (tmpVersion > version) {
892                             source = tmp;
893                             version = tmpVersion;
894                         }
895                     }
896                 }
897             }
898
899             const QUrl &oldSource = viewer->source();
900             if (source != oldSource) {
901 #if !defined(QT_NO_WEBKIT)
902                 viewer->stop();
903 #endif
904                 const QString &fragment = source.fragment();
905                 const bool isQtRefDoc = source.authority().startsWith(qtRefDoc);
906                 if (isQtRefDoc) {
907                     // workaround for qt properties
908                     m_idFromContext = fragment;
909
910                     if (!m_idFromContext.isEmpty()) {
911                         connect(viewer, SIGNAL(loadFinished(bool)), this,
912                             SLOT(highlightSearchTerms()));
913                     }
914                 }
915
916                 viewer->setSource(source);
917
918                 if (isQtRefDoc && !m_idFromContext.isEmpty()) {
919                     if (source.toString().remove(fragment)
920                         == oldSource.toString().remove(oldSource.fragment())) {
921                         highlightSearchTerms();
922                     }
923                 }
924             } else {
925 #if !defined(QT_NO_WEBKIT)
926                 viewer->page()->mainFrame()->scrollToAnchor(source.fragment());
927 #endif
928             }
929             viewer->setFocus();
930         }
931     }
932 }
933
934 void HelpPlugin::activateIndex()
935 {
936     activateHelpMode();
937     m_sideBar->activateItem(m_indexItem);
938 }
939
940 void HelpPlugin::activateContents()
941 {
942     activateHelpMode();
943     m_sideBar->activateItem(m_contentItem);
944 }
945
946 void HelpPlugin::activateSearch()
947 {
948     activateHelpMode();
949     m_sideBar->activateItem(m_searchItem);
950 }
951
952 void HelpPlugin::activateOpenPages()
953 {
954     activateHelpMode();
955     m_sideBar->activateItem(m_openPagesItem);
956 }
957
958 void HelpPlugin::activateBookmarks()
959 {
960     activateHelpMode();
961     m_sideBar->activateItem(m_bookmarkItem);
962 }
963
964 Utils::StyledBar *HelpPlugin::createWidgetToolBar()
965 {
966     m_filterComboBox = new QComboBox;
967     m_filterComboBox->setMinimumContentsLength(15);
968     connect(m_filterComboBox, SIGNAL(activated(QString)), this,
969         SLOT(filterDocumentation(QString)));
970     connect(m_filterComboBox, SIGNAL(currentIndexChanged(int)), this,
971         SLOT(updateSideBarSource()));
972
973     m_closeButton = new QToolButton();
974     m_closeButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_CLOSE)));
975     m_closeButton->setToolTip(tr("Close current page"));
976     connect(m_closeButton, SIGNAL(clicked()), &OpenPagesManager::instance(),
977         SLOT(closeCurrentPage()));
978     connect(&OpenPagesManager::instance(), SIGNAL(pagesChanged()), this,
979         SLOT(updateCloseButton()));
980
981     Utils::StyledBar *toolBar = new Utils::StyledBar;
982
983     QHBoxLayout *layout = new QHBoxLayout(toolBar);
984     layout->setMargin(0);
985     layout->setSpacing(0);
986     layout->addWidget(OpenPagesManager::instance().openPagesComboBox(), 10);
987     layout->addSpacing(5);
988     layout->addWidget(new QLabel(tr("Filtered by:")));
989     layout->addWidget(m_filterComboBox);
990     layout->addStretch();
991     layout->addWidget(m_closeButton);
992
993     return toolBar;
994 }
995
996 Utils::StyledBar *HelpPlugin::createIconToolBar(bool external)
997 {
998     Utils::StyledBar *toolBar = new Utils::StyledBar;
999     toolBar->setVisible(false);
1000
1001     QAction *home, *back, *next, *bookmark;
1002     if (external) {
1003         home = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")),
1004             tr("Home"), toolBar);
1005         connect(home, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
1006
1007         back = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")),
1008             tr("Previous Page"), toolBar);
1009         back->setEnabled(m_centralWidget->isBackwardAvailable());
1010         connect(back, SIGNAL(triggered()), m_centralWidget, SLOT(backward()));
1011         connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), back,
1012             SLOT(setEnabled(bool)));
1013
1014         next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")),
1015             tr("Next Page"), toolBar);
1016         next->setEnabled(m_centralWidget->isForwardAvailable());
1017         connect(next, SIGNAL(triggered()), m_centralWidget, SLOT(forward()));
1018         connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), next,
1019             SLOT(setEnabled(bool)));
1020
1021         bookmark = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")),
1022             tr("Add Bookmark"), toolBar);
1023         connect(bookmark, SIGNAL(triggered()), this, SLOT(addBookmark()));
1024     } else {
1025         Core::ActionManager *am = m_core->actionManager();
1026         home = am->command(Core::Id("Help.Home"))->action();
1027         back = am->command(Core::Id("Help.Previous"))->action();
1028         next = am->command(Core::Id("Help.Next"))->action();
1029         bookmark = am->command(Core::Id("Help.AddBookmark"))->action();
1030     }
1031
1032     setupNavigationMenus(back, next, toolBar);
1033
1034     QHBoxLayout *layout = new QHBoxLayout(toolBar);
1035     layout->setMargin(0);
1036     layout->setSpacing(0);
1037     layout->addWidget(toolButton(home));
1038     layout->addWidget(toolButton(back));
1039     layout->addWidget(toolButton(next));
1040     layout->addWidget(new Utils::StyledSeparator(toolBar));
1041     layout->addWidget(toolButton(bookmark));
1042     layout->addWidget(new Utils::StyledSeparator(toolBar));
1043
1044     return toolBar;
1045 }
1046
1047 void HelpPlugin::updateFilterComboBox()
1048 {
1049     const QHelpEngine &engine = LocalHelpManager::helpEngine();
1050     QString curFilter = m_filterComboBox->currentText();
1051     if (curFilter.isEmpty())
1052         curFilter = engine.currentFilter();
1053     m_filterComboBox->clear();
1054     m_filterComboBox->addItems(engine.customFilters());
1055     int idx = m_filterComboBox->findText(curFilter);
1056     if (idx < 0)
1057         idx = 0;
1058     m_filterComboBox->setCurrentIndex(idx);
1059 }
1060
1061 void HelpPlugin::filterDocumentation(const QString &customFilter)
1062 {
1063     LocalHelpManager::helpEngine().setCurrentFilter(customFilter);
1064 }
1065
1066 void HelpPlugin::addBookmark()
1067 {
1068     HelpViewer *viewer = m_centralWidget->currentHelpViewer();
1069
1070     const QString &url = viewer->source().toString();
1071     if (url.isEmpty() || url == Help::Constants::AboutBlank)
1072         return;
1073
1074     BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
1075     manager->showBookmarkDialog(m_centralWidget, viewer->title(), url);
1076 }
1077
1078 void HelpPlugin::highlightSearchTerms()
1079 {
1080     if (HelpViewer* viewer = viewerForContextMode()) {
1081         disconnect(viewer, SIGNAL(loadFinished(bool)), this,
1082             SLOT(highlightSearchTerms()));
1083
1084 #if !defined(QT_NO_WEBKIT)
1085         const QWebElement &document = viewer->page()->mainFrame()->documentElement();
1086         const QWebElementCollection &collection = document.findAll(QLatin1String("h3.fn a"));
1087
1088         const QLatin1String property("background-color");
1089         foreach (const QWebElement &element, collection) {
1090             const QString &name = element.attribute(QLatin1String("name"));
1091             if (name.isEmpty())
1092                 continue;
1093
1094             if (m_oldAttrValue == name
1095                 || name.startsWith(m_oldAttrValue + QLatin1Char('-'))) {
1096                 QWebElement parent = element.parent();
1097                 parent.setStyleProperty(property, m_styleProperty);
1098             }
1099
1100             if (m_idFromContext == name
1101                 || name.startsWith(m_idFromContext + QLatin1Char('-'))) {
1102                 QWebElement parent = element.parent();
1103                 m_styleProperty = parent.styleProperty(property,
1104                     QWebElement::ComputedStyle);
1105                 parent.setStyleProperty(property, QLatin1String("yellow"));
1106             }
1107         }
1108         m_oldAttrValue = m_idFromContext;
1109 #endif
1110     }
1111 }
1112
1113 void HelpPlugin::handleHelpRequest(const QUrl &url)
1114 {
1115     if (HelpViewer::launchWithExternalApp(url))
1116         return;
1117
1118     QString address = url.toString();
1119     if (!Core::HelpManager::instance()->findFile(url).isValid()) {
1120         if (address.startsWith(HelpViewer::NsNokia)
1121             || address.startsWith(HelpViewer::NsTrolltech)) {
1122                 // local help not installed, resort to external web help
1123                 QString urlPrefix = QLatin1String("http://doc.trolltech.com/");
1124                 if (url.authority() == QLatin1String("com.nokia.qtcreator")) {
1125                     urlPrefix.append(QString::fromLatin1("qtcreator"));
1126                 } else {
1127                     urlPrefix.append(QLatin1String("latest"));
1128                 }
1129             address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/')));
1130         }
1131     }
1132
1133     const QUrl newUrl(address);
1134     if (newUrl.queryItemValue(QLatin1String("view")) == QLatin1String("split")) {
1135         if (HelpViewer* viewer = viewerForContextMode())
1136             viewer->setSource(newUrl);
1137     } else {
1138         switchToHelpMode(newUrl);
1139     }
1140 }
1141
1142 void HelpPlugin::slotAboutToShowBackMenu()
1143 {
1144 #if !defined(QT_NO_WEBKIT)
1145     m_backMenu->clear();
1146     if (QWebHistory *history = viewerForContextMode()->history()) {
1147         const int currentItemIndex = history->currentItemIndex();
1148         QList<QWebHistoryItem> items = history->backItems(history->count());
1149         for (int i = items.count() - 1; i >= 0; --i) {
1150             QAction *action = new QAction(this);
1151             action->setText(items.at(i).title());
1152             action->setData(-1 * (currentItemIndex - i));
1153             m_backMenu->addAction(action);
1154         }
1155     }
1156 #endif
1157 }
1158
1159 void HelpPlugin::slotAboutToShowNextMenu()
1160 {
1161 #if !defined(QT_NO_WEBKIT)
1162     m_nextMenu->clear();
1163     if (QWebHistory *history = viewerForContextMode()->history()) {
1164         const int count = history->count();
1165         QList<QWebHistoryItem> items = history->forwardItems(count);
1166         for (int i = 0; i < items.count(); ++i) {
1167             QAction *action = new QAction(this);
1168             action->setData(count - i);
1169             action->setText(items.at(i).title());
1170             m_nextMenu->addAction(action);
1171         }
1172     }
1173 #endif
1174 }
1175
1176 void HelpPlugin::slotOpenActionUrl(QAction *action)
1177 {
1178 #if !defined(QT_NO_WEBKIT)
1179     if (HelpViewer* viewer = viewerForContextMode()) {
1180         const int offset = action->data().toInt();
1181         QWebHistory *history = viewer->history();
1182         if (offset > 0) {
1183             history->goToItem(history->forwardItems(history->count()
1184                 - offset + 1).back());  // forward
1185         } else if (offset < 0) {
1186             history->goToItem(history->backItems(-1 * offset).first()); // back
1187         }
1188     }
1189 #else
1190     Q_UNUSED(action)
1191 #endif
1192 }
1193
1194 void HelpPlugin::openFindToolBar()
1195 {
1196     if (Find::FindPlugin::instance())
1197         Find::FindPlugin::instance()->openFindToolBar(Find::FindPlugin::FindForward);
1198 }
1199
1200 void HelpPlugin::doSetupIfNeeded()
1201 {
1202     m_helpManager->setupGuiHelpEngine();
1203     if (m_firstModeChange) {
1204         qApp->processEvents();
1205         setupUi();
1206         resetFilter();
1207         m_firstModeChange = false;
1208         OpenPagesManager::instance().setupInitialPages();
1209     }
1210 }
1211
1212 int HelpPlugin::contextHelpOption() const
1213 {
1214     QSettings *settings = Core::ICore::instance()->settings();
1215     const QString key = Help::Constants::ID_MODE_HELP + QLatin1String("/ContextHelpOption");
1216     if (settings->contains(key))
1217         return settings->value(key, Help::Constants::SideBySideIfPossible).toInt();
1218
1219     const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
1220     return engine.customValue(QLatin1String("ContextHelpOption"),
1221         Help::Constants::SideBySideIfPossible).toInt();
1222 }
1223
1224 void HelpPlugin::connectExternalHelpWindow()
1225 {
1226     if (m_connectWindow) {
1227         m_connectWindow = false;
1228         connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
1229             m_externalWindow, SLOT(close()));
1230         connect(m_externalWindow, SIGNAL(activateIndex()), this,
1231             SLOT(activateIndex()));
1232         connect(m_externalWindow, SIGNAL(activateContents()), this,
1233             SLOT(activateContents()));
1234         connect(m_externalWindow, SIGNAL(activateSearch()), this,
1235             SLOT(activateSearch()));
1236         connect(m_externalWindow, SIGNAL(activateBookmarks()), this,
1237             SLOT(activateBookmarks()));
1238         connect(m_externalWindow, SIGNAL(activateOpenPages()), this,
1239             SLOT(activateOpenPages()));
1240         connect(m_externalWindow, SIGNAL(addBookmark()), this,
1241             SLOT(addBookmark()));
1242         connect(m_externalWindow, SIGNAL(showHideSidebar()), this,
1243             SLOT(showHideSidebar()));
1244     }
1245 }
1246
1247 void HelpPlugin::setupNavigationMenus(QAction *back, QAction *next, QWidget *parent)
1248 {
1249 #if !defined(QT_NO_WEBKIT)
1250     if (!m_backMenu) {
1251         m_backMenu = new QMenu(parent);
1252         connect(m_backMenu, SIGNAL(aboutToShow()), this,
1253             SLOT(slotAboutToShowBackMenu()));
1254         connect(m_backMenu, SIGNAL(triggered(QAction*)), this,
1255             SLOT(slotOpenActionUrl(QAction*)));
1256     }
1257
1258     if (!m_nextMenu) {
1259         m_nextMenu = new QMenu(parent);
1260         connect(m_nextMenu, SIGNAL(aboutToShow()), this,
1261             SLOT(slotAboutToShowNextMenu()));
1262         connect(m_nextMenu, SIGNAL(triggered(QAction*)), this,
1263             SLOT(slotOpenActionUrl(QAction*)));
1264     }
1265
1266     back->setMenu(m_backMenu);
1267     next->setMenu(m_nextMenu);
1268 #else
1269     Q_UNUSED(back)
1270     Q_UNUSED(next)
1271     Q_UNUSED(parent)
1272 #endif
1273 }
1274
1275 Q_EXPORT_PLUGIN(HelpPlugin)