/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** No Commercial Usage ** ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "helpplugin.h" #include "bookmarkmanager.h" #include "centralwidget.h" #include "contentwindow.h" #include "docsettingspage.h" #include "externalhelpwindow.h" #include "filtersettingspage.h" #include "generalsettingspage.h" #include "helpconstants.h" #include "helpfindsupport.h" #include "helpindexfilter.h" #include "helpmode.h" #include "helpviewer.h" #include "indexwindow.h" #include "localhelpmanager.h" #include "openpagesmanager.h" #include "openpagesmodel.h" #include "remotehelpfilter.h" #include "searchwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(QT_NO_WEBKIT) #include #include #include #include #endif using namespace Core::Constants; using namespace Help::Internal; const char * const SB_INDEX = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index"); const char * const SB_CONTENTS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Contents"); const char * const SB_BOOKMARKS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Bookmarks"); const char * const SB_SEARCH = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Search"); const char * const SB_OPENPAGES = "OpenPages"; #define IMAGEPATH ":/help/images/" #if defined(Q_OS_MAC) # define DOCPATH "/../Resources/doc/" #else # define DOCPATH "/../share/doc/qtcreator/" #endif namespace { QToolButton* toolButton(QAction *action) { QToolButton *button = new QToolButton; button->setDefaultAction(action); button->setPopupMode(QToolButton::DelayedPopup); return button; } } HelpPlugin::HelpPlugin() : m_mode(0), m_core(0), m_centralWidget(0), m_rightPaneSideBarWidget(0), m_helpViewerForSideBar(0), m_contentItem(0), m_indexItem(0), m_searchItem(0), m_bookmarkItem(0), m_sideBar(0), m_firstModeChange(true), m_oldMode(0), m_connectWindow(true), m_externalWindow(0), m_backMenu(0), m_nextMenu(0) { } HelpPlugin::~HelpPlugin() { delete m_rightPaneSideBarWidget; } bool HelpPlugin::initialize(const QStringList &arguments, QString *error) { Q_UNUSED(arguments) Q_UNUSED(error) m_core = Core::ICore::instance(); Core::Context globalcontext(Core::Constants::C_GLOBAL); Core::Context modecontext(Constants::C_MODE_HELP); const QString &locale = m_core->userInterfaceLanguage(); if (!locale.isEmpty()) { QTranslator *qtr = new QTranslator(this); QTranslator *qhelptr = new QTranslator(this); const QString &creatorTrPath = Core::ICore::instance()->resourcePath() + QLatin1String("/translations"); const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); const QString &trFile = QLatin1String("assistant_") + locale; const QString &helpTrFile = QLatin1String("qt_help_") + locale; if (qtr->load(trFile, qtTrPath) || qtr->load(trFile, creatorTrPath)) qApp->installTranslator(qtr); if (qhelptr->load(helpTrFile, qtTrPath) || qhelptr->load(helpTrFile, creatorTrPath)) qApp->installTranslator(qhelptr); } addAutoReleasedObject(m_helpManager = new LocalHelpManager(this)); addAutoReleasedObject(m_openPagesManager = new OpenPagesManager(this)); addAutoReleasedObject(m_docSettingsPage = new DocSettingsPage()); addAutoReleasedObject(m_filterSettingsPage = new FilterSettingsPage()); addAutoReleasedObject(m_generalSettingsPage = new GeneralSettingsPage()); connect(m_generalSettingsPage, SIGNAL(fontChanged()), this, SLOT(fontChanged())); connect(m_generalSettingsPage, SIGNAL(contextHelpOptionChanged()), this, SLOT(contextHelpOptionChanged())); connect(m_generalSettingsPage, SIGNAL(returnOnCloseChanged()), this, SLOT(updateCloseButton())); connect(Core::HelpManager::instance(), SIGNAL(helpRequested(QUrl)), this, SLOT(handleHelpRequest(QUrl))); connect(m_filterSettingsPage, SIGNAL(filtersChanged()), this, SLOT(setupHelpEngineIfNeeded())); connect(Core::HelpManager::instance(), SIGNAL(documentationChanged()), this, SLOT(setupHelpEngineIfNeeded())); connect(Core::HelpManager::instance(), SIGNAL(collectionFileChanged()), this, SLOT(setupHelpEngineIfNeeded())); m_splitter = new Core::MiniSplitter; m_centralWidget = new Help::Internal::CentralWidget(); connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this, SLOT(updateSideBarSource(QUrl))); connect(m_centralWidget, SIGNAL(openFindToolBar()), this, SLOT(openFindToolBar())); // Add Home, Previous and Next actions (used in the toolbar) QAction *action = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")), tr("Home"), this); Core::ActionManager *am = m_core->actionManager(); Core::Command *cmd = am->registerAction(action, "Help.Home", globalcontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(home())); action = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")), tr("Previous Page"), this); cmd = am->registerAction(action, Core::Id("Help.Previous"), modecontext); cmd->setDefaultKeySequence(QKeySequence::Back); action->setEnabled(m_centralWidget->isBackwardAvailable()); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(backward())); connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), action, SLOT(setEnabled(bool))); action = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next Page"), this); cmd = am->registerAction(action, Core::Id("Help.Next"), modecontext); cmd->setDefaultKeySequence(QKeySequence::Forward); action->setEnabled(m_centralWidget->isForwardAvailable()); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(forward())); connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), action, SLOT(setEnabled(bool))); action = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")), tr("Add Bookmark"), this); cmd = am->registerAction(action, Core::Id("Help.AddBookmark"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_M)); connect(action, SIGNAL(triggered()), this, SLOT(addBookmark())); // Add Contents, Index, and Context menu items and a separator to the Help menu action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), tr(SB_CONTENTS), this); cmd = am->registerAction(action, Core::Id("Help.Contents"), globalcontext); am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); connect(action, SIGNAL(triggered()), this, SLOT(activateContents())); action = new QAction(tr(SB_INDEX), this); cmd = am->registerAction(action, Core::Id("Help.Index"), globalcontext); am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); connect(action, SIGNAL(triggered()), this, SLOT(activateIndex())); action = new QAction(tr("Context Help"), this); cmd = am->registerAction(action, Core::Id("Help.Context"), globalcontext); am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1)); connect(action, SIGNAL(triggered()), this, SLOT(activateContext())); #ifndef Q_WS_MAC action = new QAction(this); action->setSeparator(true); cmd = am->registerAction(action, Core::Id("Help.Separator"), globalcontext); am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); #endif action = new QAction(this); am->registerAction(action, Core::Constants::PRINT, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(print())); action = new QAction(this); cmd = am->registerAction(action, Core::Constants::COPY, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(copy())); action->setText(cmd->action()->text()); action->setIcon(cmd->action()->icon()); if (Core::ActionContainer *advancedMenu = am->actionContainer(M_EDIT_ADVANCED)) { // reuse TextEditor constants to avoid a second pair of menu actions action = new QAction(tr("Increase Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomIn())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); action = new QAction(tr("Decrease Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(zoomOut())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); action = new QAction(tr("Reset Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::RESET_FONT_SIZE, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(resetZoom())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); } if (Core::ActionContainer *windowMenu = am->actionContainer(M_WINDOW)) { // reuse EditorManager constants to avoid a second pair of menu actions action = new QAction(QApplication::translate("EditorManager", "Next Open Document in History"), this); Core::Command *ctrlTab = am->registerAction(action, GOTOPREVINHISTORY, modecontext); // Goto Previous In History Action windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE); connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(), SLOT(gotoPreviousPage())); action = new QAction(QApplication::translate("EditorManager", "Previous Open Document in History"), this); Core::Command *ctrlShiftTab = am->registerAction(action, GOTONEXTINHISTORY, modecontext); // Goto Next In History Action windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE); connect(action, SIGNAL(triggered()), &OpenPagesManager::instance(), SLOT(gotoNextPage())); } Aggregation::Aggregate *agg = new Aggregation::Aggregate; agg->add(m_centralWidget); agg->add(new HelpFindSupport(m_centralWidget)); QWidget *toolBarWidget = new QWidget; QHBoxLayout *toolBarLayout = new QHBoxLayout(toolBarWidget); toolBarLayout->setMargin(0); toolBarLayout->setSpacing(0); toolBarLayout->addWidget(m_externalHelpBar = createIconToolBar(true)); toolBarLayout->addWidget(m_internalHelpBar = createIconToolBar(false)); toolBarLayout->addWidget(createWidgetToolBar()); QWidget *mainWidget = new QWidget; m_splitter->addWidget(mainWidget); QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget); mainWidgetLayout->setMargin(0); mainWidgetLayout->setSpacing(0); mainWidgetLayout->addWidget(toolBarWidget); mainWidgetLayout->addWidget(m_centralWidget); if (QLayout *layout = m_centralWidget->layout()) { layout->setSpacing(0); Core::FindToolBarPlaceHolder *fth = new Core::FindToolBarPlaceHolder(m_centralWidget); fth->setObjectName(QLatin1String("HelpFindToolBarPlaceHolder")); layout->addWidget(fth); } HelpIndexFilter *helpIndexFilter = new HelpIndexFilter(); addAutoReleasedObject(helpIndexFilter); connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)), this, SLOT(switchToHelpMode(QUrl))); RemoteHelpFilter *remoteHelpFilter = new RemoteHelpFilter(); addAutoReleasedObject(remoteHelpFilter); connect(remoteHelpFilter, SIGNAL(linkActivated(QUrl)), this, SLOT(switchToHelpMode(QUrl))); QDesktopServices::setUrlHandler("qthelp", this, "handleHelpRequest"); connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*, Core::IMode*)), this, SLOT(modeChanged(Core::IMode*, Core::IMode*))); m_externalWindow = new ExternalHelpWindow; m_mode = new HelpMode; if (contextHelpOption() == Help::Constants::ExternalHelpAlways) { m_mode->setWidget(new QWidget); m_mode->setEnabled(false); m_externalHelpBar->setVisible(true); m_externalWindow->setCentralWidget(m_splitter); QTimer::singleShot(0, this, SLOT(showExternalWindow())); } else { m_mode->setWidget(m_splitter); m_internalHelpBar->setVisible(true); } addAutoReleasedObject(m_mode); return true; } void HelpPlugin::extensionsInitialized() { const QString &nsInternal = QString::fromLatin1("com.nokia.qtcreator.%1%2%3") .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE); Core::HelpManager *helpManager = Core::HelpManager::instance(); foreach (const QString &ns, helpManager->registeredNamespaces()) { if (ns.startsWith(QLatin1String("com.nokia.qtcreator.")) && ns != nsInternal) helpManager->unregisterDocumentation(QStringList() << ns); } QStringList filesToRegister; // Explicitly register qml.qch if located in creator directory. This is only // needed for the creator-qml package, were we want to ship the documentation // without a qt development version. TODO: is this still really needed, remove const QString &appPath = QCoreApplication::applicationDirPath(); filesToRegister.append(QDir::cleanPath(QDir::cleanPath(appPath + QLatin1String(DOCPATH "qml.qch")))); // we might need to register creators inbuild help filesToRegister.append(QDir::cleanPath(appPath + QLatin1String(DOCPATH "qtcreator.qch"))); helpManager->registerDocumentation(filesToRegister); } ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown() { if (m_sideBar) m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar")); delete m_externalWindow; return SynchronousShutdown; } void HelpPlugin::setupUi() { // side bar widgets and shortcuts Core::ActionManager *am = m_core->actionManager(); Core::Context modecontext(Constants::C_MODE_HELP); IndexWindow *indexWindow = new IndexWindow(); indexWindow->setWindowTitle(tr(SB_INDEX)); m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX)); connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget, SLOT(setSource(QUrl))); connect(indexWindow, SIGNAL(linksActivated(QMap, QString)), m_centralWidget, SLOT(showTopicChooser(QMap, QString))); QMap shortcutMap; QShortcut *shortcut = new QShortcut(m_splitter); shortcut->setWhatsThis(tr("Activate Index in Help mode")); Core::Command* cmd = am->registerShortcut(shortcut, Core::Id("Help.IndexShortcut"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex())); shortcutMap.insert(QLatin1String(SB_INDEX), cmd); ContentWindow *contentWindow = new ContentWindow(); contentWindow->setWindowTitle(tr(SB_CONTENTS)); m_contentItem = new Core::SideBarItem(contentWindow, Core::Id(SB_CONTENTS)); connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget, SLOT(setSource(QUrl))); shortcut = new QShortcut(m_splitter); shortcut->setWhatsThis(tr("Activate Contents in Help mode")); cmd = am->registerShortcut(shortcut, Core::Id("Help.ContentsShortcut"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C)); connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents())); shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd); SearchWidget *searchWidget = new SearchWidget(); searchWidget->setWindowTitle(tr(SB_SEARCH)); m_searchItem = new Core::SideBarItem(searchWidget, QLatin1String(SB_SEARCH)); connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget, SLOT(setSourceFromSearch(QUrl))); shortcut = new QShortcut(m_splitter); shortcut->setWhatsThis(tr("Activate Search in Help mode")); cmd = am->registerShortcut(shortcut, Core::Id("Help.SearchShortcut"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Slash)); connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch())); shortcutMap.insert(QLatin1String(SB_SEARCH), cmd); BookmarkManager *manager = &LocalHelpManager::bookmarkManager(); BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false); bookmarkWidget->setWindowTitle(tr(SB_BOOKMARKS)); m_bookmarkItem = new Core::SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS)); connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget, SLOT(setSource(QUrl))); shortcut = new QShortcut(m_splitter); shortcut->setWhatsThis(tr("Activate Bookmarks in Help mode")); cmd = am->registerShortcut(shortcut, Core::Id("Help.BookmarkShortcut"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B)); connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks())); shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd); QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget(); openPagesWidget->setWindowTitle(tr("Open Pages")); m_openPagesItem = new Core::SideBarItem(openPagesWidget, QLatin1String(SB_OPENPAGES)); shortcut = new QShortcut(m_splitter); shortcut->setWhatsThis(tr("Activate Open Pages in Help mode")); cmd = am->registerShortcut(shortcut, Core::Id("Help.PagesShortcut"), modecontext); cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_O)); connect(shortcut, SIGNAL(activated()), this, SLOT(activateOpenPages())); shortcutMap.insert(QLatin1String(SB_OPENPAGES), cmd); QList itemList; itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem << m_openPagesItem; m_sideBar = new Core::SideBar(itemList, QList() << m_contentItem << m_openPagesItem); m_sideBar->setShortcutMap(shortcutMap); m_splitter->setOpaqueResize(false); m_splitter->insertWidget(0, m_sideBar); m_splitter->setStretchFactor(0, 0); m_splitter->setStretchFactor(1, 1); m_sideBar->readSettings(m_core->settings(), QLatin1String("HelpSideBar")); m_splitter->setSizes(QList() << m_sideBar->size().width() << 300); } void HelpPlugin::resetFilter() { const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3") .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR).arg(IDE_VERSION_RELEASE); const QRegExp filterRegExp(QLatin1String("Qt Creator \\d*\\.\\d*\\.\\d*")); QHelpEngineCore *engine = &LocalHelpManager::helpEngine(); const QStringList &filters = engine->customFilters(); foreach (const QString &filter, filters) { if (filterRegExp.exactMatch(filter) && filter != filterInternal) engine->removeCustomFilter(filter); } // we added a filter at some point, remove previously added filter if (engine->customValue(Help::Constants::WeAddedFilterKey).toInt() == 1) { const QString &filter = engine->customValue(Help::Constants::PreviousFilterNameKey).toString(); if (!filter.isEmpty()) engine->removeCustomFilter(filter); } // potentially remove a filter with new name const QString filterName = tr("Unfiltered"); engine->removeCustomFilter(filterName); engine->addCustomFilter(filterName, QStringList()); engine->setCustomValue(Help::Constants::WeAddedFilterKey, 1); engine->setCustomValue(Help::Constants::PreviousFilterNameKey, filterName); engine->setCurrentFilter(filterName); updateFilterComboBox(); connect(engine, SIGNAL(setupFinished()), this, SLOT(updateFilterComboBox())); } void HelpPlugin::createRightPaneContextViewer() { if (m_rightPaneSideBarWidget) return; Utils::StyledBar *toolBar = new Utils::StyledBar(); QAction *switchToHelp = new QAction(tr("Go to Help Mode"), toolBar); connect(switchToHelp, SIGNAL(triggered()), this, SLOT(switchToHelpMode())); QAction *back = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")), tr("Previous"), toolBar); QAction *next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next"), toolBar); QAction *close = new QAction(QIcon(QLatin1String(Core::Constants::ICON_CLOSE)), QLatin1String(""), toolBar); connect(close, SIGNAL(triggered()), this, SLOT(slotHideRightPane())); setupNavigationMenus(back, next, toolBar); QHBoxLayout *layout = new QHBoxLayout(toolBar); layout->setSpacing(0); layout->setMargin(0); layout->addWidget(toolButton(switchToHelp)); layout->addWidget(toolButton(back)); layout->addWidget(toolButton(next)); layout->addStretch(); layout->addWidget(toolButton(close)); m_rightPaneSideBarWidget = new QWidget; m_helpViewerForSideBar = new HelpViewer(qreal(0.0)); connect(m_helpViewerForSideBar, SIGNAL(openFindToolBar()), this, SLOT(openFindToolBar())); #if !defined(QT_NO_WEBKIT) m_helpViewerForSideBar->pageAction(QWebPage::OpenLinkInNewWindow)->setVisible(false); #endif QVBoxLayout *rightPaneLayout = new QVBoxLayout(m_rightPaneSideBarWidget); rightPaneLayout->setMargin(0); rightPaneLayout->setSpacing(0); rightPaneLayout->addWidget(toolBar); rightPaneLayout->addWidget(m_helpViewerForSideBar); Core::FindToolBarPlaceHolder *fth = new Core::FindToolBarPlaceHolder(m_rightPaneSideBarWidget); fth->setObjectName(QLatin1String("HelpRightPaneFindToolBarPlaceHolder")); rightPaneLayout->addWidget(fth); m_rightPaneSideBarWidget->setFocusProxy(m_helpViewerForSideBar); Aggregation::Aggregate *agg = new Aggregation::Aggregate(); agg->add(m_helpViewerForSideBar); agg->add(new HelpViewerFindSupport(m_helpViewerForSideBar)); Core::Context context(Constants::C_HELP_SIDEBAR); m_core->addContextObject(new Core::BaseContext(m_helpViewerForSideBar, context, this)); QAction *copy = new QAction(this); Core::Command *cmd = m_core->actionManager()->registerAction(copy, Core::Constants::COPY, context); copy->setText(cmd->action()->text()); copy->setIcon(cmd->action()->icon()); connect(copy, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(copy())); next->setEnabled(m_helpViewerForSideBar->isForwardAvailable()); connect(next, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(forward())); connect(m_helpViewerForSideBar, SIGNAL(forwardAvailable(bool)), next, SLOT(setEnabled(bool))); back->setEnabled(m_helpViewerForSideBar->isBackwardAvailable()); connect(back, SIGNAL(triggered()), m_helpViewerForSideBar, SLOT(backward())); connect(m_helpViewerForSideBar, SIGNAL(backwardAvailable(bool)), back, SLOT(setEnabled(bool))); Core::ActionManager *am = m_core->actionManager(); if (Core::ActionContainer *advancedMenu = am->actionContainer(M_EDIT_ADVANCED)) { // reuse TextEditor constants to avoid a second pair of menu actions QAction *action = new QAction(tr("Increase Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::INCREASE_FONT_SIZE, context); connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneUp())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); action = new QAction(tr("Decrease Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::DECREASE_FONT_SIZE, context); connect(action, SIGNAL(triggered()), this, SLOT(scaleRightPaneDown())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); action = new QAction(tr("Reset Font Size"), this); cmd = am->registerAction(action, TextEditor::Constants::RESET_FONT_SIZE, context); connect(action, SIGNAL(triggered()), this, SLOT(resetRightPaneScale())); advancedMenu->addAction(cmd, Core::Constants::G_EDIT_FONT); } // force setup, as we might have never switched to full help mode // thus the help engine might still run without collection file setup m_helpManager->setupGuiHelpEngine(); } void HelpPlugin::scaleRightPaneUp() { if (m_helpViewerForSideBar) m_helpViewerForSideBar->scaleUp(); } void HelpPlugin::scaleRightPaneDown() { if (m_helpViewerForSideBar) m_helpViewerForSideBar->scaleDown(); } void HelpPlugin::resetRightPaneScale() { if (m_helpViewerForSideBar) m_helpViewerForSideBar->resetScale(); } void HelpPlugin::activateHelpMode() { if (contextHelpOption() != Help::Constants::ExternalHelpAlways) m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP)); else showExternalWindow(); } void HelpPlugin::switchToHelpMode() { switchToHelpMode(m_helpViewerForSideBar->source()); } void HelpPlugin::switchToHelpMode(const QUrl &source) { activateHelpMode(); m_centralWidget->setSource(source); m_centralWidget->setFocus(); } void HelpPlugin::slotHideRightPane() { Core::RightPaneWidget::instance()->setShown(false); } void HelpPlugin::showHideSidebar() { m_sideBar->setVisible(!m_sideBar->isVisible()); } void HelpPlugin::showExternalWindow() { bool firstTime = m_firstModeChange; doSetupIfNeeded(); m_externalWindow->show(); connectExternalHelpWindow(); m_externalWindow->activateWindow(); if (firstTime) Core::ICore::instance()->mainWindow()->activateWindow(); } void HelpPlugin::modeChanged(Core::IMode *mode, Core::IMode *old) { if (mode == m_mode) { m_oldMode = old; qApp->setOverrideCursor(Qt::WaitCursor); doSetupIfNeeded(); qApp->restoreOverrideCursor(); } } void HelpPlugin::updateSideBarSource() { if (HelpViewer *viewer = m_centralWidget->currentHelpViewer()) { const QUrl &url = viewer->source(); if (url.isValid()) updateSideBarSource(url); } } void HelpPlugin::updateSideBarSource(const QUrl &newUrl) { if (m_helpViewerForSideBar) m_helpViewerForSideBar->setSource(newUrl); } void HelpPlugin::updateCloseButton() { Core::HelpManager *manager = Core::HelpManager::instance(); const bool closeOnReturn = manager->customValue(QLatin1String("ReturnOnClose"), false).toBool(); m_closeButton->setEnabled((OpenPagesManager::instance().pageCount() > 1) | closeOnReturn); } void HelpPlugin::fontChanged() { if (!m_helpViewerForSideBar) createRightPaneContextViewer(); const QHelpEngine &engine = LocalHelpManager::helpEngine(); QFont font = qVariantValue(engine.customValue(QLatin1String("font"), m_helpViewerForSideBar->viewerFont())); m_helpViewerForSideBar->setFont(font); const int count = OpenPagesManager::instance().pageCount(); for (int i = 0; i < count; ++i) { if (HelpViewer *viewer = CentralWidget::instance()->viewerAt(i)) viewer->setViewerFont(font); } } QStackedLayout * layoutForWidget(QWidget *parent, QWidget *widget) { QList list = parent->findChildren(); foreach (QStackedLayout *layout, list) { const int index = layout->indexOf(widget); if (index >= 0) return layout; } return 0; } void HelpPlugin::contextHelpOptionChanged() { doSetupIfNeeded(); QWidget *modeWidget = m_mode->widget(); if (modeWidget == m_splitter && contextHelpOption() == Help::Constants::ExternalHelpAlways) { if (QWidget *widget = m_splitter->parentWidget()) { if (QStackedLayout *layout = layoutForWidget(widget, m_splitter)) { const int index = layout->indexOf(m_splitter); layout->removeWidget(m_splitter); m_mode->setWidget(new QWidget); layout->insertWidget(index, m_mode->widget()); m_externalWindow->setCentralWidget(m_splitter); m_splitter->show(); slotHideRightPane(); m_mode->setEnabled(false); m_externalHelpBar->setVisible(true); m_internalHelpBar->setVisible(false); m_externalWindow->show(); connectExternalHelpWindow(); if (m_oldMode && m_mode == m_core->modeManager()->currentMode()) m_core->modeManager()->activateMode(m_oldMode->id()); } } } else if (modeWidget != m_splitter && contextHelpOption() != Help::Constants::ExternalHelpAlways) { QStackedLayout *wLayout = layoutForWidget(modeWidget->parentWidget(), modeWidget); if (wLayout && m_splitter->parentWidget()->layout()) { const int index = wLayout->indexOf(modeWidget); QWidget *tmp = wLayout->widget(index); wLayout->removeWidget(modeWidget); delete tmp; m_splitter->parentWidget()->layout()->removeWidget(m_splitter); m_mode->setWidget(m_splitter); wLayout->insertWidget(index, m_splitter); m_mode->setEnabled(true); m_externalWindow->close(); m_sideBar->setVisible(true); m_internalHelpBar->setVisible(true); m_externalHelpBar->setVisible(false); } } } void HelpPlugin::setupHelpEngineIfNeeded() { m_helpManager->setEngineNeedsUpdate(); if (Core::ModeManager::instance()->currentMode() == m_mode || contextHelpOption() == Help::Constants::ExternalHelpAlways) m_helpManager->setupGuiHelpEngine(); } HelpViewer* HelpPlugin::viewerForContextMode() { using namespace Core; if (m_core->modeManager()->currentMode()->id() == Core::Constants::MODE_WELCOME) m_core->modeManager()->activateMode(Core::Constants::MODE_EDIT); bool showSideBySide = false; RightPanePlaceHolder *placeHolder = RightPanePlaceHolder::current(); switch (contextHelpOption()) { case Help::Constants::SideBySideIfPossible: { // side by side if possible if (IEditor *editor = EditorManager::instance()->currentEditor()) { if (!placeHolder || !placeHolder->isVisible()) { if (!editor->widget()) break; if (!editor->widget()->isVisible()) break; if (editor->widget()->width() < 800) break; } } } // fall through case Help::Constants::SideBySideAlways: { // side by side showSideBySide = true; } break; default: // help mode break; } if (placeHolder && showSideBySide) { RightPaneWidget::instance()->setWidget(m_rightPaneSideBarWidget); RightPaneWidget::instance()->setShown(true); createRightPaneContextViewer(); return m_helpViewerForSideBar; } activateHelpMode(); // should trigger an createPage... HelpViewer *viewer = m_centralWidget->currentHelpViewer(); if (!viewer) viewer = OpenPagesManager::instance().createPage(); return viewer; } void HelpPlugin::activateContext() { using namespace Core; createRightPaneContextViewer(); RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current(); if (placeHolder && m_helpViewerForSideBar->hasFocus()) { switchToHelpMode(); return; } else if (m_core->modeManager()->currentMode() == m_mode) return; // Find out what to show QMap links; if (IContext *context = m_core->currentContextObject()) { m_idFromContext = context->contextHelpId(); links = Core::HelpManager::instance()->linksForIdentifier(m_idFromContext); } if (HelpViewer* viewer = viewerForContextMode()) { if (links.isEmpty()) { // No link found or no context object viewer->setSource(QUrl(Help::Constants::AboutBlank)); viewer->setHtml(tr("No Documentation" "
%1
No documentation " "available.
").arg(m_idFromContext)); } else { int version = 0; const QRegExp exp("(\\d+)"); QUrl source = *links.begin(); const QLatin1String qtRefDoc = QLatin1String("com.trolltech.qt"); // workaround to show the latest qt version foreach (const QUrl &tmp, links) { const QString &authority = tmp.authority(); if (authority.startsWith(qtRefDoc)) { if (exp.indexIn(authority) >= 0) { const int tmpVersion = exp.cap(1).toInt(); if (tmpVersion > version) { source = tmp; version = tmpVersion; } } } } const QUrl &oldSource = viewer->source(); if (source != oldSource) { #if !defined(QT_NO_WEBKIT) viewer->stop(); #endif const QString &fragment = source.fragment(); const bool isQtRefDoc = source.authority().startsWith(qtRefDoc); if (isQtRefDoc) { // workaround for qt properties m_idFromContext = fragment; if (!m_idFromContext.isEmpty()) { connect(viewer, SIGNAL(loadFinished(bool)), this, SLOT(highlightSearchTerms())); } } viewer->setSource(source); if (isQtRefDoc && !m_idFromContext.isEmpty()) { if (source.toString().remove(fragment) == oldSource.toString().remove(oldSource.fragment())) { highlightSearchTerms(); } } } else { #if !defined(QT_NO_WEBKIT) viewer->page()->mainFrame()->scrollToAnchor(source.fragment()); #endif } viewer->setFocus(); } } } void HelpPlugin::activateIndex() { activateHelpMode(); m_sideBar->activateItem(m_indexItem); } void HelpPlugin::activateContents() { activateHelpMode(); m_sideBar->activateItem(m_contentItem); } void HelpPlugin::activateSearch() { activateHelpMode(); m_sideBar->activateItem(m_searchItem); } void HelpPlugin::activateOpenPages() { activateHelpMode(); m_sideBar->activateItem(m_openPagesItem); } void HelpPlugin::activateBookmarks() { activateHelpMode(); m_sideBar->activateItem(m_bookmarkItem); } Utils::StyledBar *HelpPlugin::createWidgetToolBar() { m_filterComboBox = new QComboBox; m_filterComboBox->setMinimumContentsLength(15); connect(m_filterComboBox, SIGNAL(activated(QString)), this, SLOT(filterDocumentation(QString))); connect(m_filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSideBarSource())); m_closeButton = new QToolButton(); m_closeButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_CLOSE))); m_closeButton->setToolTip(tr("Close current page")); connect(m_closeButton, SIGNAL(clicked()), &OpenPagesManager::instance(), SLOT(closeCurrentPage())); connect(&OpenPagesManager::instance(), SIGNAL(pagesChanged()), this, SLOT(updateCloseButton())); Utils::StyledBar *toolBar = new Utils::StyledBar; QHBoxLayout *layout = new QHBoxLayout(toolBar); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(OpenPagesManager::instance().openPagesComboBox(), 10); layout->addSpacing(5); layout->addWidget(new QLabel(tr("Filtered by:"))); layout->addWidget(m_filterComboBox); layout->addStretch(); layout->addWidget(m_closeButton); return toolBar; } Utils::StyledBar *HelpPlugin::createIconToolBar(bool external) { Utils::StyledBar *toolBar = new Utils::StyledBar; toolBar->setVisible(false); QAction *home, *back, *next, *bookmark; if (external) { home = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")), tr("Home"), toolBar); connect(home, SIGNAL(triggered()), m_centralWidget, SLOT(home())); back = new QAction(QIcon(QLatin1String(IMAGEPATH "previous.png")), tr("Previous Page"), toolBar); back->setEnabled(m_centralWidget->isBackwardAvailable()); connect(back, SIGNAL(triggered()), m_centralWidget, SLOT(backward())); connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), back, SLOT(setEnabled(bool))); next = new QAction(QIcon(QLatin1String(IMAGEPATH "next.png")), tr("Next Page"), toolBar); next->setEnabled(m_centralWidget->isForwardAvailable()); connect(next, SIGNAL(triggered()), m_centralWidget, SLOT(forward())); connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), next, SLOT(setEnabled(bool))); bookmark = new QAction(QIcon(QLatin1String(IMAGEPATH "bookmark.png")), tr("Add Bookmark"), toolBar); connect(bookmark, SIGNAL(triggered()), this, SLOT(addBookmark())); } else { Core::ActionManager *am = m_core->actionManager(); home = am->command(Core::Id("Help.Home"))->action(); back = am->command(Core::Id("Help.Previous"))->action(); next = am->command(Core::Id("Help.Next"))->action(); bookmark = am->command(Core::Id("Help.AddBookmark"))->action(); } setupNavigationMenus(back, next, toolBar); QHBoxLayout *layout = new QHBoxLayout(toolBar); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(toolButton(home)); layout->addWidget(toolButton(back)); layout->addWidget(toolButton(next)); layout->addWidget(new Utils::StyledSeparator(toolBar)); layout->addWidget(toolButton(bookmark)); layout->addWidget(new Utils::StyledSeparator(toolBar)); return toolBar; } void HelpPlugin::updateFilterComboBox() { const QHelpEngine &engine = LocalHelpManager::helpEngine(); QString curFilter = m_filterComboBox->currentText(); if (curFilter.isEmpty()) curFilter = engine.currentFilter(); m_filterComboBox->clear(); m_filterComboBox->addItems(engine.customFilters()); int idx = m_filterComboBox->findText(curFilter); if (idx < 0) idx = 0; m_filterComboBox->setCurrentIndex(idx); } void HelpPlugin::filterDocumentation(const QString &customFilter) { LocalHelpManager::helpEngine().setCurrentFilter(customFilter); } void HelpPlugin::addBookmark() { HelpViewer *viewer = m_centralWidget->currentHelpViewer(); const QString &url = viewer->source().toString(); if (url.isEmpty() || url == Help::Constants::AboutBlank) return; BookmarkManager *manager = &LocalHelpManager::bookmarkManager(); manager->showBookmarkDialog(m_centralWidget, viewer->title(), url); } void HelpPlugin::highlightSearchTerms() { if (HelpViewer* viewer = viewerForContextMode()) { disconnect(viewer, SIGNAL(loadFinished(bool)), this, SLOT(highlightSearchTerms())); #if !defined(QT_NO_WEBKIT) const QWebElement &document = viewer->page()->mainFrame()->documentElement(); const QWebElementCollection &collection = document.findAll(QLatin1String("h3.fn a")); const QLatin1String property("background-color"); foreach (const QWebElement &element, collection) { const QString &name = element.attribute(QLatin1String("name")); if (name.isEmpty()) continue; if (m_oldAttrValue == name || name.startsWith(m_oldAttrValue + QLatin1Char('-'))) { QWebElement parent = element.parent(); parent.setStyleProperty(property, m_styleProperty); } if (m_idFromContext == name || name.startsWith(m_idFromContext + QLatin1Char('-'))) { QWebElement parent = element.parent(); m_styleProperty = parent.styleProperty(property, QWebElement::ComputedStyle); parent.setStyleProperty(property, QLatin1String("yellow")); } } m_oldAttrValue = m_idFromContext; #endif } } void HelpPlugin::handleHelpRequest(const QUrl &url) { if (HelpViewer::launchWithExternalApp(url)) return; QString address = url.toString(); if (!Core::HelpManager::instance()->findFile(url).isValid()) { if (address.startsWith(HelpViewer::NsNokia) || address.startsWith(HelpViewer::NsTrolltech)) { // local help not installed, resort to external web help QString urlPrefix = QLatin1String("http://doc.trolltech.com/"); if (url.authority() == QLatin1String("com.nokia.qtcreator")) { urlPrefix.append(QString::fromLatin1("qtcreator")); } else { urlPrefix.append(QLatin1String("latest")); } address = urlPrefix + address.mid(address.lastIndexOf(QLatin1Char('/'))); } } const QUrl newUrl(address); if (newUrl.queryItemValue(QLatin1String("view")) == QLatin1String("split")) { if (HelpViewer* viewer = viewerForContextMode()) viewer->setSource(newUrl); } else { switchToHelpMode(newUrl); } } void HelpPlugin::slotAboutToShowBackMenu() { #if !defined(QT_NO_WEBKIT) m_backMenu->clear(); if (QWebHistory *history = viewerForContextMode()->history()) { const int currentItemIndex = history->currentItemIndex(); QList items = history->backItems(history->count()); for (int i = items.count() - 1; i >= 0; --i) { QAction *action = new QAction(this); action->setText(items.at(i).title()); action->setData(-1 * (currentItemIndex - i)); m_backMenu->addAction(action); } } #endif } void HelpPlugin::slotAboutToShowNextMenu() { #if !defined(QT_NO_WEBKIT) m_nextMenu->clear(); if (QWebHistory *history = viewerForContextMode()->history()) { const int count = history->count(); QList items = history->forwardItems(count); for (int i = 0; i < items.count(); ++i) { QAction *action = new QAction(this); action->setData(count - i); action->setText(items.at(i).title()); m_nextMenu->addAction(action); } } #endif } void HelpPlugin::slotOpenActionUrl(QAction *action) { #if !defined(QT_NO_WEBKIT) if (HelpViewer* viewer = viewerForContextMode()) { const int offset = action->data().toInt(); QWebHistory *history = viewer->history(); if (offset > 0) { history->goToItem(history->forwardItems(history->count() - offset + 1).back()); // forward } else if (offset < 0) { history->goToItem(history->backItems(-1 * offset).first()); // back } } #else Q_UNUSED(action) #endif } void HelpPlugin::openFindToolBar() { if (Find::FindPlugin::instance()) Find::FindPlugin::instance()->openFindToolBar(Find::FindPlugin::FindForward); } void HelpPlugin::doSetupIfNeeded() { m_helpManager->setupGuiHelpEngine(); if (m_firstModeChange) { qApp->processEvents(); setupUi(); resetFilter(); m_firstModeChange = false; OpenPagesManager::instance().setupInitialPages(); } } int HelpPlugin::contextHelpOption() const { QSettings *settings = Core::ICore::instance()->settings(); const QString key = Help::Constants::ID_MODE_HELP + QLatin1String("/ContextHelpOption"); if (settings->contains(key)) return settings->value(key, Help::Constants::SideBySideIfPossible).toInt(); const QHelpEngineCore &engine = LocalHelpManager::helpEngine(); return engine.customValue(QLatin1String("ContextHelpOption"), Help::Constants::SideBySideIfPossible).toInt(); } void HelpPlugin::connectExternalHelpWindow() { if (m_connectWindow) { m_connectWindow = false; connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()), m_externalWindow, SLOT(close())); connect(m_externalWindow, SIGNAL(activateIndex()), this, SLOT(activateIndex())); connect(m_externalWindow, SIGNAL(activateContents()), this, SLOT(activateContents())); connect(m_externalWindow, SIGNAL(activateSearch()), this, SLOT(activateSearch())); connect(m_externalWindow, SIGNAL(activateBookmarks()), this, SLOT(activateBookmarks())); connect(m_externalWindow, SIGNAL(activateOpenPages()), this, SLOT(activateOpenPages())); connect(m_externalWindow, SIGNAL(addBookmark()), this, SLOT(addBookmark())); connect(m_externalWindow, SIGNAL(showHideSidebar()), this, SLOT(showHideSidebar())); } } void HelpPlugin::setupNavigationMenus(QAction *back, QAction *next, QWidget *parent) { #if !defined(QT_NO_WEBKIT) if (!m_backMenu) { m_backMenu = new QMenu(parent); connect(m_backMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowBackMenu())); connect(m_backMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotOpenActionUrl(QAction*))); } if (!m_nextMenu) { m_nextMenu = new QMenu(parent); connect(m_nextMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowNextMenu())); connect(m_nextMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotOpenActionUrl(QAction*))); } back->setMenu(m_backMenu); next->setMenu(m_nextMenu); #else Q_UNUSED(back) Q_UNUSED(next) Q_UNUSED(parent) #endif } Q_EXPORT_PLUGIN(HelpPlugin)