OSDN Git Service

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