summaryrefslogtreecommitdiff
path: root/src/plugins/help
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/help')
-rw-r--r--src/plugins/help/Help.pluginspec12
-rw-r--r--src/plugins/help/centralwidget.cpp687
-rw-r--r--src/plugins/help/centralwidget.h157
-rw-r--r--src/plugins/help/contentstoolwindow.cpp180
-rw-r--r--src/plugins/help/contentstoolwindow.h102
-rw-r--r--src/plugins/help/docsettingspage.cpp143
-rw-r--r--src/plugins/help/docsettingspage.h81
-rw-r--r--src/plugins/help/docsettingspage.ui77
-rw-r--r--src/plugins/help/filtersettingspage.cpp220
-rw-r--r--src/plugins/help/filtersettingspage.h82
-rw-r--r--src/plugins/help/filtersettingspage.ui72
-rw-r--r--src/plugins/help/help.pri3
-rw-r--r--src/plugins/help/help.pro36
-rw-r--r--src/plugins/help/help.qrc16
-rw-r--r--src/plugins/help/help_global.h57
-rw-r--r--src/plugins/help/helpengine.cpp606
-rw-r--r--src/plugins/help/helpengine.h182
-rw-r--r--src/plugins/help/helpfindsupport.cpp78
-rw-r--r--src/plugins/help/helpfindsupport.h74
-rw-r--r--src/plugins/help/helpindexfilter.cpp114
-rw-r--r--src/plugins/help/helpindexfilter.h82
-rw-r--r--src/plugins/help/helpmode.cpp53
-rw-r--r--src/plugins/help/helpmode.h61
-rw-r--r--src/plugins/help/helpplugin.cpp684
-rw-r--r--src/plugins/help/helpplugin.h169
-rw-r--r--src/plugins/help/images/book.pngbin0 -> 1669 bytes
-rw-r--r--src/plugins/help/images/bookmark.pngbin0 -> 913 bytes
-rw-r--r--src/plugins/help/images/find.pngbin0 -> 2011 bytes
-rw-r--r--src/plugins/help/images/home.pngbin0 -> 1493 bytes
-rw-r--r--src/plugins/help/images/mac/addtab.pngbin0 -> 469 bytes
-rw-r--r--src/plugins/help/images/mac/closetab.pngbin0 -> 516 bytes
-rw-r--r--src/plugins/help/images/next.pngbin0 -> 908 bytes
-rw-r--r--src/plugins/help/images/previous.pngbin0 -> 911 bytes
-rw-r--r--src/plugins/help/images/win/addtab.pngbin0 -> 314 bytes
-rw-r--r--src/plugins/help/images/win/closetab.pngbin0 -> 375 bytes
-rw-r--r--src/plugins/help/indextoolwindow.cpp215
-rw-r--r--src/plugins/help/indextoolwindow.h113
-rw-r--r--src/plugins/help/indexwindow.h82
-rw-r--r--src/plugins/help/searchwidget.cpp213
-rw-r--r--src/plugins/help/searchwidget.h88
40 files changed, 4739 insertions, 0 deletions
diff --git a/src/plugins/help/Help.pluginspec b/src/plugins/help/Help.pluginspec
new file mode 100644
index 0000000000..b60b320827
--- /dev/null
+++ b/src/plugins/help/Help.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="Help" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Help system.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/help/centralwidget.cpp b/src/plugins/help/centralwidget.cpp
new file mode 100644
index 0000000000..6c63c28b1e
--- /dev/null
+++ b/src/plugins/help/centralwidget.cpp
@@ -0,0 +1,687 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "centralwidget.h"
+#include "helpviewer.h"
+#include "topicchooser.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QEvent>
+#include <QtCore/QTimer>
+
+#include <QtGui/QMenu>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QPrinter>
+#include <QtGui/QLineEdit>
+#include <QtGui/QCheckBox>
+#include <QtGui/QTabBar>
+#include <QtGui/QTabWidget>
+#include <QtGui/QToolButton>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QMainWindow>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QTextCursor>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QApplication>
+#include <QtGui/QTextDocumentFragment>
+#include <QtGui/QPrintPreviewDialog>
+#include <QtGui/QPageSetupDialog>
+
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+namespace {
+ HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget, const QPoint &point)
+ {
+ QTabBar *tabBar = qFindChild<QTabBar*>(widget);
+ for (int i = 0; i < tabBar->count(); ++i) {
+ if (tabBar->tabRect(i).contains(point))
+ return qobject_cast<HelpViewer*>(widget->widget(i));
+ }
+ return 0;
+ }
+ CentralWidget *staticCentralWidget = 0;
+}
+
+CentralWidget::CentralWidget(QHelpEngine *engine, QWidget *parent)
+ : QWidget(parent)
+ , findBar(0)
+ , tabWidget(0)
+ , helpEngine(engine)
+ , printer(0)
+{
+ lastTabPage = 0;
+ globalActionList.clear();
+ collectionFile = helpEngine->collectionFile();
+
+ QString system = QLatin1String("win");
+
+#ifdef Q_OS_MAC
+ system = QLatin1String("mac");
+#endif
+
+ tabWidget = new QTabWidget;
+ tabWidget->setDocumentMode(true);
+ tabWidget->setMovable(true);
+ connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
+ connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentPageChanged(int)));
+
+ QToolButton *newTabButton = new QToolButton(this);
+ newTabButton->setAutoRaise(true);
+ newTabButton->setToolTip(tr("Add new page"));
+ newTabButton->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/addtab.png").arg(system)));
+
+ tabWidget->setCornerWidget(newTabButton, Qt::TopLeftCorner);
+ connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab()));
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+ vboxLayout->setMargin(0);
+ vboxLayout->addWidget(tabWidget);
+
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+ if (tabBar) {
+ tabBar->installEventFilter(this);
+ tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tabBar, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(showTabBarContextMenu(const QPoint&)));
+ }
+
+ staticCentralWidget = this;
+}
+
+CentralWidget::~CentralWidget()
+{
+ QDir dir;
+ QString currentPages;
+ QHelpEngineCore engine(collectionFile, 0);
+
+ if (engine.setupData()) {
+ for (int i = 0; i < tabWidget->count(); ++i) {
+ HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
+ if (viewer && viewer->source().isValid())
+ currentPages.append(viewer->source().toString()).append(QLatin1Char('|'));
+ }
+ engine.setCustomValue(QLatin1String("LastTabPage"), lastTabPage);
+ engine.setCustomValue(QLatin1String("LastShownPages"), currentPages);
+ }
+}
+
+CentralWidget *CentralWidget::instance()
+{
+ return staticCentralWidget;
+}
+
+void CentralWidget::newTab()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ setSourceInNewTab(viewer->source());
+}
+
+void CentralWidget::zoomIn()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->zoomIn();
+}
+
+void CentralWidget::zoomOut()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->zoomOut();
+}
+
+void CentralWidget::nextPage()
+{
+ if (tabWidget->currentIndex() < tabWidget->count() -1)
+ tabWidget->setCurrentIndex(tabWidget->currentIndex() +1);
+ else
+ tabWidget->setCurrentIndex(0);
+}
+
+void CentralWidget::resetZoom()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->resetZoom();
+}
+
+void CentralWidget::previousPage()
+{
+ int index = tabWidget->currentIndex() -1;
+ if (index >= 0)
+ tabWidget->setCurrentIndex(index);
+ else
+ tabWidget->setCurrentIndex(tabWidget->count() -1);
+}
+
+void CentralWidget::closeTab()
+{
+ closeTab(tabWidget->currentIndex());
+}
+
+void CentralWidget::closeTab(int index)
+{
+ HelpViewer* viewer = helpViewerAtIndex(index);
+ if (!viewer || tabWidget->count() == 1)
+ return;
+
+ tabWidget->removeTab(index);
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+}
+
+void CentralWidget::setSource(const QUrl &url)
+{
+ HelpViewer* viewer = currentHelpViewer();
+ HelpViewer* lastViewer = qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage));
+
+ if (!viewer && !lastViewer) {
+ viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ lastTabPage = tabWidget->addTab(viewer, QString());
+ tabWidget->setCurrentIndex(lastTabPage);
+ connectSignals();
+ qApp->processEvents();
+ } else
+ viewer = lastViewer;
+
+ viewer->setSource(url);
+ currentPageChanged(lastTabPage);
+ viewer->setFocus(Qt::OtherFocusReason);
+ tabWidget->setCurrentIndex(lastTabPage);
+ tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle()));
+}
+
+void CentralWidget::setLastShownPages()
+{
+ const QStringList lastShownPageList = helpEngine->customValue(QLatin1String("LastShownPages")).
+ toString().split(QLatin1Char('|'), QString::SkipEmptyParts);
+
+ if (!lastShownPageList.isEmpty()) {
+ foreach (const QString page, lastShownPageList)
+ setSourceInNewTab(page);
+
+ tabWidget->setCurrentIndex(helpEngine->customValue(QLatin1String("LastTabPage"), 0).toInt());
+ } else {
+ QUrl url = helpEngine->findFile(QUrl("qthelp://com.trolltech.qt.440/qdoc/index.html"));
+ if (url.isValid())
+ setSource(url);
+ else
+ setSource(QUrl("qthelp://com.trolltech.qt.440/qdoc/index.html"));
+ }
+
+ updateBrowserFont();
+}
+
+bool CentralWidget::hasSelection() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ return viewer ? viewer->hasSelection() : false;
+}
+
+QUrl CentralWidget::currentSource() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->source();
+
+ return QUrl();
+}
+
+QString CentralWidget::currentTitle() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->documentTitle();
+
+ return QString();
+}
+
+void CentralWidget::copySelection()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->copy();
+}
+
+void CentralWidget::initPrinter()
+{
+#ifndef QT_NO_PRINTER
+ if (!printer)
+ printer = new QPrinter(QPrinter::HighResolution);
+#endif
+}
+
+void CentralWidget::print()
+{
+#ifndef QT_NO_PRINTER
+ HelpViewer* viewer = currentHelpViewer();
+ if (!viewer)
+ return;
+
+ initPrinter();
+
+ QPrintDialog *dlg = new QPrintDialog(printer, this);
+#if !defined(USE_WEBKIT)
+ if (viewer->textCursor().hasSelection())
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
+#endif
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange);
+ dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies);
+ dlg->setWindowTitle(tr("Print Document"));
+ if (dlg->exec() == QDialog::Accepted) {
+ viewer->print(printer);
+ }
+ delete dlg;
+#endif
+}
+
+void CentralWidget::printPreview()
+{
+#ifndef QT_NO_PRINTER
+ initPrinter();
+ QPrintPreviewDialog preview(printer, this);
+ connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *)));
+ preview.exec();
+#endif
+}
+
+void CentralWidget::printPreview(QPrinter *p)
+{
+#ifndef QT_NO_PRINTER
+ HelpViewer *viewer = currentHelpViewer();
+ if (viewer)
+ viewer->print(p);
+#endif
+}
+
+void CentralWidget::pageSetup()
+{
+#ifndef QT_NO_PRINTER
+ initPrinter();
+ QPageSetupDialog dlg(printer);
+ dlg.exec();
+#endif
+}
+
+bool CentralWidget::isHomeAvailable() const
+{
+ return currentHelpViewer() ? true : false;
+}
+
+void CentralWidget::home()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->home();
+}
+
+bool CentralWidget::isForwardAvailable() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->isForwardAvailable();
+
+ return false;
+}
+
+void CentralWidget::forward()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->forward();
+}
+
+bool CentralWidget::isBackwardAvailable() const
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ return viewer->isBackwardAvailable();
+
+ return false;
+}
+
+void CentralWidget::backward()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->backward();
+}
+
+
+QList<QAction*> CentralWidget::globalActions() const
+{
+ return globalActionList;
+}
+
+void CentralWidget::setGlobalActions(const QList<QAction*> &actions)
+{
+ globalActionList = actions;
+}
+void CentralWidget::setSourceInNewTab(const QUrl &url)
+{
+ HelpViewer* viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ viewer->setSource(url);
+ viewer->setFocus(Qt::OtherFocusReason);
+ tabWidget->setCurrentIndex(tabWidget->addTab(viewer, viewer->documentTitle()));
+
+ QFont font = qApp->font();
+ if (helpEngine->customValue(QLatin1String("useBrowserFont")).toBool())
+ font = qVariantValue<QFont>(helpEngine->customValue(QLatin1String("browserFont")));
+
+ viewer->setFont(font);
+
+ connectSignals();
+}
+
+HelpViewer *CentralWidget::newEmptyTab()
+{
+ HelpViewer* viewer = new HelpViewer(helpEngine, this);
+ viewer->installEventFilter(this);
+ viewer->setFocus(Qt::OtherFocusReason);
+#if !defined(USE_WEBKIT)
+ viewer->setDocumentTitle(tr("unknown"));
+#endif
+ tabWidget->setCurrentIndex(tabWidget->addTab(viewer, tr("unknown")));
+
+ connectSignals();
+ return viewer;
+}
+
+void CentralWidget::connectSignals()
+{
+ const HelpViewer* viewer = currentHelpViewer();
+ if (viewer) {
+ connect(viewer, SIGNAL(copyAvailable(bool)), this, SIGNAL(copyAvailable(bool)));
+ connect(viewer, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
+ connect(viewer, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
+ connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SIGNAL(sourceChanged(const QUrl&)));
+ connect(viewer, SIGNAL(highlighted(const QString&)), this, SIGNAL(highlighted(const QString&)));
+
+ connect(viewer, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(setTabTitle(const QUrl&)));
+ }
+}
+
+HelpViewer *CentralWidget::helpViewerAtIndex(int index) const
+{
+ return qobject_cast<HelpViewer*>(tabWidget->widget(index));
+}
+
+HelpViewer *CentralWidget::currentHelpViewer() const
+{
+ return qobject_cast<HelpViewer*>(tabWidget->currentWidget());
+}
+
+void CentralWidget::activateTab(bool onlyHelpViewer)
+{
+ if (currentHelpViewer()) {
+ currentHelpViewer()->setFocus();
+ } else {
+ int idx = 0;
+ if (onlyHelpViewer)
+ idx = lastTabPage;
+ tabWidget->setCurrentIndex(idx);
+ tabWidget->currentWidget()->setFocus();
+ }
+}
+
+void CentralWidget::setTabTitle(const QUrl& url)
+{
+ int tab = lastTabPage;
+ HelpViewer* viewer = currentHelpViewer();
+
+#if defined(USE_WEBKIT)
+ if (!viewer || viewer->source() != url) {
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+ for (tab = 0; tab < tabBar->count(); ++tab) {
+ viewer = qobject_cast<HelpViewer*>(tabWidget->widget(tab));
+ if (viewer && viewer->source() == url)
+ break;
+ }
+ }
+#endif
+
+ if (viewer) {
+ tabWidget->setTabText(tab,
+ quoteTabTitle(viewer->documentTitle().trimmed()));
+ }
+}
+
+void CentralWidget::currentPageChanged(int index)
+{
+ const HelpViewer *viewer = currentHelpViewer();
+
+ if (viewer || tabWidget->count() == 1)
+ lastTabPage = index;
+
+ bool enabled = false;
+ if (viewer)
+ enabled = tabWidget->count() > 1;
+
+ tabWidget->setTabsClosable(enabled);
+ tabWidget->cornerWidget(Qt::TopLeftCorner)->setEnabled(true);
+
+ emit currentViewerChanged();
+}
+
+void CentralWidget::showTabBarContextMenu(const QPoint &point)
+{
+ HelpViewer* viewer = helpViewerFromTabPosition(tabWidget, point);
+ if (!viewer)
+ return;
+
+ QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
+
+ QMenu menu(QLatin1String(""), tabBar);
+ QAction *new_page = menu.addAction(tr("Add New Page"));
+ QAction *close_page = menu.addAction(tr("Close This Page"));
+ QAction *close_pages = menu.addAction(tr("Close Other Pages"));
+ menu.addSeparator();
+ QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page..."));
+
+ if (tabBar->count() == 1) {
+ close_page->setEnabled(false);
+ close_pages->setEnabled(false);
+ }
+
+ QAction *picked_action = menu.exec(tabBar->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == new_page)
+ setSourceInNewTab(viewer->source());
+
+ if (picked_action == close_page) {
+ tabWidget->removeTab(tabWidget->indexOf(viewer));
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+ }
+
+ if (picked_action == close_pages) {
+ int currentPage = tabWidget->indexOf(viewer);
+ for (int i = tabBar->count() -1; i >= 0; --i) {
+ viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
+ if (i != currentPage && viewer) {
+ tabWidget->removeTab(i);
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+
+ if (i < currentPage)
+ --currentPage;
+ }
+ }
+ }
+
+ if (picked_action == newBookmark)
+ emit addNewBookmark(viewer->documentTitle(), viewer->source().toString());
+}
+
+// if we have a current help viewer then this is the 'focus proxy', otherwise
+// it's the tab widget itself
+// this is needed, so an embedding program can just set the focus to the central widget
+// and it does TheRightThing
+void CentralWidget::focusInEvent(QFocusEvent * /* event */)
+{
+ if (currentHelpViewer())
+ QTimer::singleShot(1, currentHelpViewer(), SLOT(setFocus()));
+ else
+ QTimer::singleShot(1, tabWidget, SLOT(setFocus()));
+}
+
+bool CentralWidget::eventFilter(QObject *object, QEvent *e)
+{
+ if (currentHelpViewer() == object && e->type() == QEvent::KeyPress){
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key() == Qt::Key_Backspace) {
+ HelpViewer *viewer = currentHelpViewer();
+ if (viewer && viewer->isBackwardAvailable())
+ viewer->backward();
+ return true;
+ }
+ }
+
+ QTabBar *tabBar = qobject_cast<QTabBar*>(object);
+ bool mousRel = e->type() == QEvent::MouseButtonRelease;
+ bool dblClick = e->type() == QEvent::MouseButtonDblClick;
+
+ if (tabBar && (mousRel || dblClick)) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e);
+ HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, mouseEvent->pos());
+ if (tabWidget->count() <= 1)
+ return QWidget::eventFilter(object, e);
+
+ if (viewer && (mouseEvent->button() == Qt::MidButton || dblClick)) {
+ tabWidget->removeTab(tabWidget->indexOf(viewer));
+ QTimer::singleShot(0, viewer, SLOT(deleteLater()));
+ currentPageChanged(tabWidget->currentIndex());
+ return true;
+ }
+ }
+ return QWidget::eventFilter(object, e);
+}
+
+void CentralWidget::updateBrowserFont()
+{
+ QFont font = qApp->font();
+ if (helpEngine->customValue(QLatin1String("useBrowserFont")).toBool())
+ font = qVariantValue<QFont>(helpEngine->customValue(QLatin1String("browserFont")));
+
+ QWidget* widget = 0;
+ for (int i = 0; i < tabWidget->count(); ++i) {
+ widget = tabWidget->widget(i);
+ if (widget->font() != font)
+ widget->setFont(font);
+ }
+}
+
+bool CentralWidget::find(const QString &txt, QTextDocument::FindFlags findFlags, bool incremental)
+{
+ HelpViewer* viewer = currentHelpViewer();
+
+#if defined(USE_WEBKIT)
+ Q_UNUSED(incremental);
+ if (viewer) {
+ QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument;
+ if (findFlags & QTextDocument::FindBackward)
+ options |= QWebPage::FindBackward;
+ if (findFlags & QTextDocument::FindCaseSensitively)
+ options |= QWebPage::FindCaseSensitively;
+
+ return viewer->findText(txt, options);
+ }
+ return false;
+#else
+ QTextCursor cursor;
+ QTextDocument *doc = 0;
+ QTextBrowser *browser = 0;
+
+ if (viewer) {
+ doc = viewer->document();
+ cursor = viewer->textCursor();
+ browser = qobject_cast<QTextBrowser*>(viewer);
+ }
+ /*
+ if (tabWidget->currentWidget() == m_searchWidget) {
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(m_searchWidget);
+ if (browser) {
+ doc = browser->document();
+ cursor = browser->textCursor();
+ }
+ }
+ */
+ if (!browser || !doc || cursor.isNull())
+ return false;
+ if (incremental)
+ cursor.setPosition(cursor.selectionStart());
+
+ QTextCursor found = doc->find(txt, cursor, findFlags);
+ if (found.isNull()) {
+ if ((findFlags&QTextDocument::FindBackward) == 0)
+ cursor.movePosition(QTextCursor::Start);
+ else
+ cursor.movePosition(QTextCursor::End);
+ found = doc->find(txt, cursor, findFlags);
+ if (found.isNull()) {
+ return false;
+ }
+ }
+ if (!found.isNull()) {
+ viewer->setTextCursor(found);
+ }
+ return true;
+#endif
+}
+
+void CentralWidget::showTopicChooser(const QMap<QString, QUrl> &links,
+ const QString &keyword)
+{
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted)
+ setSource(tc.link());
+}
+
+void CentralWidget::copy()
+{
+ HelpViewer* viewer = currentHelpViewer();
+ if (viewer)
+ viewer->copy();
+}
+
+QString CentralWidget::quoteTabTitle(const QString &title) const
+{
+ QString s = title;
+ return s.replace(QLatin1Char('&'), QLatin1String("&&"));
+}
diff --git a/src/plugins/help/centralwidget.h b/src/plugins/help/centralwidget.h
new file mode 100644
index 0000000000..a75e999b07
--- /dev/null
+++ b/src/plugins/help/centralwidget.h
@@ -0,0 +1,157 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CENTRALWIDGET_H
+#define CENTRALWIDGET_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QPoint>
+#include <QtCore/QObject>
+
+#include <QtGui/QWidget>
+#include <QtGui/QTextDocument>
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QLabel;
+class QAction;
+class QCheckBox;
+class QLineEdit;
+class QToolButton;
+class QTabWidget;
+class QHelpEngine;
+class QFocusEvent;
+class CentralWidget;
+class HelpViewer;
+
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class PrintHelper;
+
+}
+}
+
+QT_BEGIN_NAMESPACE
+
+class CentralWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CentralWidget(QHelpEngine *engine, QWidget *parent = 0);
+ ~CentralWidget();
+
+ bool hasSelection() const;
+ QUrl currentSource() const;
+ QString currentTitle() const;
+ bool isHomeAvailable() const;
+ bool isForwardAvailable() const;
+ bool isBackwardAvailable() const;
+ QList<QAction*> globalActions() const;
+ void setGlobalActions(const QList<QAction*> &actions);
+ HelpViewer *currentHelpViewer() const;
+ void activateTab(bool onlyHelpViewer = false);
+ bool find(const QString &txt, QTextDocument::FindFlags findFlags, bool incremental);
+ void setLastShownPages();
+
+ static CentralWidget *instance();
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+ void nextPage();
+ void resetZoom();
+ void previousPage();
+ void copySelection();
+ void print();
+ void pageSetup();
+ void printPreview();
+ void updateBrowserFont();
+ void setSource(const QUrl &url);
+ void setSourceInNewTab(const QUrl &url);
+ HelpViewer *newEmptyTab();
+ void home();
+ void forward();
+ void backward();
+ void showTopicChooser(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void copy();
+
+protected:
+ void focusInEvent(QFocusEvent *event);
+
+signals:
+ void currentViewerChanged();
+ void copyAvailable(bool yes);
+ void sourceChanged(const QUrl &url);
+ void highlighted(const QString &link);
+ void forwardAvailable(bool available);
+ void backwardAvailable(bool available);
+ void addNewBookmark(const QString &title, const QString &url);
+
+private slots:
+ void newTab();
+ void closeTab();
+ void closeTab(int index);
+ void setTabTitle(const QUrl& url);
+ void currentPageChanged(int index);
+ void showTabBarContextMenu(const QPoint &point);
+ void printPreview(QPrinter *printer);
+
+private:
+ void connectSignals();
+ bool eventFilter(QObject *object, QEvent *e);
+ void initPrinter();
+ HelpViewer *helpViewerAtIndex(int index) const;
+ QString quoteTabTitle(const QString &title) const;
+
+private:
+ int lastTabPage;
+ QString collectionFile;
+ QList<QAction*> globalActionList;
+
+ QWidget *findBar;
+ QTabWidget* tabWidget;
+ QHelpEngine *helpEngine;
+ QPrinter *printer;
+};
+
+QT_END_NAMESPACE
+//} // namespace Internal
+//} // namespace Help
+
+#endif // CENTRALWIDGET_H
diff --git a/src/plugins/help/contentstoolwindow.cpp b/src/plugins/help/contentstoolwindow.cpp
new file mode 100644
index 0000000000..1af3aff3b1
--- /dev/null
+++ b/src/plugins/help/contentstoolwindow.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QKeyEvent>
+
+#include "contentstoolwindow.h"
+#include "helpengine.h"
+
+using namespace Help::Internal;
+
+ContentsToolWidget::ContentsToolWidget()
+{
+ wasInitialized = false;
+
+ setRootIsDecorated(true);
+ setItemHidden(headerItem(), true);
+ setUniformRowHeights(true);
+ setColumnCount(1);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ setWindowTitle(tr("Contents"));
+ setWindowIcon(QIcon(":/help/images/book.png"));
+}
+
+void ContentsToolWidget::focusInEvent(QFocusEvent *e)
+{
+ if (wasInitialized) {
+ if (e && e->reason() != Qt::MouseFocusReason
+ && !currentItem() && topLevelItemCount())
+ setCurrentItem(topLevelItem(0));
+ return;
+ }
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+}
+
+void ContentsToolWidget::showEvent(QShowEvent *)
+{
+ if (wasInitialized)
+ return;
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+}
+
+void ContentsToolWidget::keyPressEvent(QKeyEvent *e)
+{
+ if (e && e->key() == Qt::Key_Escape) {
+ emit escapePressed();
+ e->accept();
+ return;
+ }
+ QTreeWidget::keyPressEvent(e);
+}
+
+
+enum
+{
+ LinkRole = Qt::UserRole + 1000
+};
+
+ContentsToolWindow::ContentsToolWindow(const QList<int> &context, HelpEngine *help)
+{
+ m_widget = new ContentsToolWidget;
+ helpEngine = help;
+ connect(helpEngine, SIGNAL(contentsInitialized()), this, SLOT(contentsDone()));
+ connect(m_widget, SIGNAL(buildRequested()), helpEngine, SLOT(buildContents()));
+
+ m_context = context;
+ m_context << 0;
+
+ connect(m_widget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()));
+}
+
+ContentsToolWindow::~ContentsToolWindow()
+{
+ delete m_widget;
+}
+
+const QList<int> &ContentsToolWindow::context() const
+{
+ return m_context;
+}
+
+QWidget *ContentsToolWindow::widget()
+{
+ return m_widget;
+}
+
+void ContentsToolWindow::contentsDone()
+{
+ m_widget->setCursor(QCursor(Qt::WaitCursor));
+ QList<QPair<QString, ContentList> > contentList = helpEngine->contents();
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ QTreeWidgetItem *newEntry;
+ QTreeWidgetItem *contentEntry;
+ QStack<QTreeWidgetItem*> stack;
+ stack.clear();
+ int depth = 0;
+ bool root = false;
+
+ QTreeWidgetItem *lastItem[64];
+ for(int j = 0; j < 64; ++j)
+ lastItem[j] = 0;
+
+ ContentList lst = (*it).second;
+ for (ContentList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
+ ContentItem item = *it;
+ if (item.depth == 0) {
+ newEntry = new QTreeWidgetItem(m_widget, 0);
+ newEntry->setIcon(0, QIcon(QString::fromUtf8(":/help/images/book.png")));
+ newEntry->setText(0, item.title);
+ newEntry->setData(0, LinkRole, item.reference);
+ stack.push(newEntry);
+ depth = 1;
+ root = true;
+ }
+ else{
+ if((item.depth > depth) && root) {
+ depth = item.depth;
+ stack.push(contentEntry);
+ }
+ if(item.depth == depth) {
+ contentEntry = new QTreeWidgetItem(stack.top(), lastItem[ depth ]);
+ lastItem[ depth ] = contentEntry;
+ contentEntry->setText(0, item.title);
+ contentEntry->setData(0, LinkRole, item.reference);
+ }
+ else if(item.depth < depth) {
+ stack.pop();
+ depth--;
+ item = *(--it);
+ }
+ }
+ }
+ }
+ m_widget->setCursor(QCursor(Qt::ArrowCursor));
+}
+
+void ContentsToolWindow::indexRequested()
+{
+ QTreeWidgetItem *itm = m_widget->currentItem();
+ if (!itm)
+ return;
+ emit showLinkRequested(itm->data(0, LinkRole).toString(), false);
+}
diff --git a/src/plugins/help/contentstoolwindow.h b/src/plugins/help/contentstoolwindow.h
new file mode 100644
index 0000000000..51163c1ea1
--- /dev/null
+++ b/src/plugins/help/contentstoolwindow.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CONTENTSTOOLWINDOW_H
+#define CONTENTSTOOLWINDOW_H
+
+#include <QtGui/QTreeWidget>
+
+#include <coreplugin/iview.h>
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+class ContentsToolWindow;
+
+class ContentsToolWidget : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ ContentsToolWidget();
+
+signals:
+ void buildRequested();
+ void escapePressed();
+
+private:
+ friend class ContentsToolWindow;
+ void showEvent(QShowEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+
+ bool wasInitialized;
+};
+
+class ContentsToolWindow : public Core::IView
+{
+ Q_OBJECT
+
+public:
+ ContentsToolWindow(const QList<int> &context, HelpEngine *help);
+ ~ContentsToolWindow();
+
+ const QList<int> &context() const;
+ QWidget *widget();
+
+ QList<QWidget*> dockToolBarWidgets() const { return QList<QWidget*>(); }
+
+ const char *uniqueViewName() const { return "Help.ContentsToolWindow"; }
+ const char *globalMenuGroup() const { return "Help.Group"; }
+ inline QKeySequence defaultShortcut() const { return QKeySequence(); }
+ Qt::DockWidgetArea defaultArea() const { return Qt::RightDockWidgetArea; }
+ IView::ViewPosition defaultPosition() const { return IView::First; }
+
+signals:
+ void showLinkRequested(const QString &link, bool newWindow);
+ void escapePressed();
+
+private slots:
+ void contentsDone();
+ void indexRequested();
+
+private:
+ HelpEngine *helpEngine;
+
+ QList<int> m_context;
+ ContentsToolWidget *m_widget;
+};
+
+} //namespace Internal
+} //namespace Help
+
+#endif
diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp
new file mode 100644
index 0000000000..763d134c23
--- /dev/null
+++ b/src/plugins/help/docsettingspage.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "docsettingspage.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+DocSettingsPage::DocSettingsPage(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine),
+ m_registeredDocs(false)
+{
+
+}
+
+QString DocSettingsPage::name() const
+{
+ return "Documentation";
+}
+
+QString DocSettingsPage::category() const
+{
+ return "Help";
+}
+
+QString DocSettingsPage::trCategory() const
+{
+ return tr("Help");
+}
+
+QWidget *DocSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_ui.setupUi(w);
+
+ connect(m_ui.addButton, SIGNAL(clicked()),
+ this, SLOT(addDocumentation()));
+ connect(m_ui.removeButton, SIGNAL(clicked()),
+ this, SLOT(removeDocumentation()));
+
+ m_ui.docsListWidget->addItems(m_helpEngine->registeredDocumentations());
+ m_registeredDocs = false;
+ m_removeDocs.clear();
+
+ return w;
+}
+
+void DocSettingsPage::addDocumentation()
+{
+ QStringList files = QFileDialog::getOpenFileNames(m_ui.addButton->parentWidget(),
+ tr("Add Documentation"),
+ QString(), tr("Qt Help Files (*.qch)"));
+
+ if (files.isEmpty())
+ return;
+
+ foreach (const QString &file, files) {
+ QString nsName = QHelpEngineCore::namespaceName(file);
+ if (nsName.isEmpty()) {
+ QMessageBox::warning(m_ui.addButton->parentWidget(),
+ tr("Add Documentation"),
+ tr("The file %1 is not a valid Qt Help file!")
+ .arg(file));
+ continue;
+ }
+ m_helpEngine->registerDocumentation(file);
+ m_ui.docsListWidget->addItem(nsName);
+ }
+ m_registeredDocs = true;
+ emit documentationAdded();
+}
+
+void DocSettingsPage::removeDocumentation()
+{
+ QListWidgetItem *item = m_ui.docsListWidget->currentItem();
+ if (!item)
+ return;
+
+ m_removeDocs.append(item->text());
+ int row = m_ui.docsListWidget->currentRow();
+ m_ui.docsListWidget->takeItem(row);
+ if (row > 0)
+ --row;
+ if (m_ui.docsListWidget->count())
+ m_ui.docsListWidget->setCurrentRow(row);
+
+ delete item;
+}
+
+void DocSettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ emit dialogAccepted();
+}
+
+bool DocSettingsPage::applyChanges()
+{
+ QStringList::const_iterator it = m_removeDocs.constBegin();
+ while (it != m_removeDocs.constEnd()) {
+ if (!m_helpEngine->unregisterDocumentation((*it))) {
+ QMessageBox::warning(m_ui.addButton->parentWidget(),
+ tr("Documentation"),
+ tr("Cannot unregister documentation file %1!")
+ .arg((*it)));
+ }
+ ++it;
+ }
+ return m_registeredDocs || m_removeDocs.count();
+}
diff --git a/src/plugins/help/docsettingspage.h b/src/plugins/help/docsettingspage.h
new file mode 100644
index 0000000000..efafb94034
--- /dev/null
+++ b/src/plugins/help/docsettingspage.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef DOCSETTINGSPAGE_H
+#define DOCSETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_docsettingspage.h"
+
+QT_FORWARD_DECLARE_CLASS(QHelpEngine)
+
+namespace Help {
+namespace Internal {
+
+class DocSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ DocSettingsPage(QHelpEngine *helpEngine);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool applyChanges();
+
+signals:
+ void documentationAdded();
+ void dialogAccepted();
+
+private slots:
+ void addDocumentation();
+ void removeDocumentation();
+
+private:
+ QHelpEngine *m_helpEngine;
+ bool m_registeredDocs;
+ QStringList m_removeDocs;
+ Ui::DocSettingsPage m_ui;
+};
+
+} // namespace Help
+} // namespace Internal
+
+#endif // DOCSETTINGSPAGE_H
diff --git a/src/plugins/help/docsettingspage.ui b/src/plugins/help/docsettingspage.ui
new file mode 100644
index 0000000000..311be060c7
--- /dev/null
+++ b/src/plugins/help/docsettingspage.ui
@@ -0,0 +1,77 @@
+<ui version="4.0" >
+ <class>DocSettingsPage</class>
+ <widget class="QWidget" name="DocSettingsPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>364</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Registered Documentation:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="_3" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="docsListWidget" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="_4" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="addButton" >
+ <property name="text" >
+ <string>Add...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp
new file mode 100644
index 0000000000..6087a94084
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.cpp
@@ -0,0 +1,220 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "filtersettingspage.h"
+#include "filternamedialog.h"
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtHelp/QHelpEngine>
+
+using namespace Help::Internal;
+
+FilterSettingsPage::FilterSettingsPage(QHelpEngine *helpEngine)
+{
+ m_helpEngine = helpEngine;
+}
+
+QString FilterSettingsPage::name() const
+{
+ return "Filters";
+}
+
+QString FilterSettingsPage::category() const
+{
+ return "Help";
+}
+
+QString FilterSettingsPage::trCategory() const
+{
+ return tr("Help");
+}
+
+QWidget *FilterSettingsPage::createPage(QWidget *parent)
+{
+ m_currentPage = new QWidget(parent);
+ m_ui.setupUi(m_currentPage);
+ m_ui.attributeWidget->header()->hide();
+ m_ui.attributeWidget->setRootIsDecorated(false);
+
+ connect(m_ui.attributeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
+ this, SLOT(updateFilterMap()));
+ connect(m_ui.filterWidget,
+ SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
+ this, SLOT(updateAttributes(QListWidgetItem*)));
+ connect(m_ui.filterAddButton, SIGNAL(clicked()),
+ this, SLOT(addFilter()));
+ connect(m_ui.filterRemoveButton, SIGNAL(clicked()),
+ this, SLOT(removeFilter()));
+ updateFilterPage();
+
+ return m_currentPage;
+}
+
+void FilterSettingsPage::updateFilterPage()
+{
+ if (!m_helpEngine)
+ return;
+
+ m_ui.filterWidget->clear();
+ m_ui.attributeWidget->clear();
+
+ QHelpEngineCore help(m_helpEngine->collectionFile(), 0);
+ help.setupData();
+ m_filterMapBackup.clear();
+ const QStringList filters = help.customFilters();
+ foreach (const QString filter, filters) {
+ QStringList atts = help.filterAttributes(filter);
+ m_filterMapBackup.insert(filter, atts);
+ if (!m_filterMap.contains(filter))
+ m_filterMap.insert(filter, atts);
+ }
+
+ m_ui.filterWidget->addItems(m_filterMap.keys());
+
+ foreach (const QString a, help.filterAttributes())
+ new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a);
+
+ if (m_filterMap.keys().count())
+ m_ui.filterWidget->setCurrentRow(0);
+}
+
+void FilterSettingsPage::updateAttributes(QListWidgetItem *item)
+{
+ QStringList checkedList;
+ if (item)
+ checkedList = m_filterMap.value(item->text());
+ QTreeWidgetItem *itm;
+ for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) {
+ itm = m_ui.attributeWidget->topLevelItem(i);
+ if (checkedList.contains(itm->text(0)))
+ itm->setCheckState(0, Qt::Checked);
+ else
+ itm->setCheckState(0, Qt::Unchecked);
+ }
+}
+
+void FilterSettingsPage::updateFilterMap()
+{
+ if (!m_ui.filterWidget->currentItem())
+ return;
+ QString filter = m_ui.filterWidget->currentItem()->text();
+ if (!m_filterMap.contains(filter))
+ return;
+
+ QStringList newAtts;
+ QTreeWidgetItem *itm = 0;
+ for (int i=0; i<m_ui.attributeWidget->topLevelItemCount(); ++i) {
+ itm = m_ui.attributeWidget->topLevelItem(i);
+ if (itm->checkState(0) == Qt::Checked)
+ newAtts.append(itm->text(0));
+ }
+ m_filterMap[filter] = newAtts;
+}
+
+void FilterSettingsPage::addFilter()
+{
+ FilterNameDialog dia(m_currentPage);
+ if (dia.exec() == QDialog::Rejected)
+ return;
+
+ QString filterName = dia.filterName();
+ if (!m_filterMap.contains(filterName)) {
+ m_filterMap.insert(filterName, QStringList());
+ m_ui.filterWidget->addItem(filterName);
+ }
+
+ QList<QListWidgetItem*> lst = m_ui.filterWidget
+ ->findItems(filterName, Qt::MatchCaseSensitive);
+ m_ui.filterWidget->setCurrentItem(lst.first());
+}
+
+void FilterSettingsPage::removeFilter()
+{
+ QListWidgetItem *item = m_ui.filterWidget
+ ->takeItem(m_ui.filterWidget->currentRow());
+ if (!item)
+ return;
+
+ m_filterMap.remove(item->text());
+ m_removedFilters.append(item->text());
+ delete item;
+ if (m_ui.filterWidget->count())
+ m_ui.filterWidget->setCurrentRow(0);
+}
+
+void FilterSettingsPage::finished(bool)
+{
+}
+
+bool FilterSettingsPage::applyChanges()
+{
+ bool changed = false;
+ if (m_filterMap.count() != m_filterMapBackup.count()) {
+ changed = true;
+ } else {
+ QMapIterator<QString, QStringList> it(m_filterMapBackup);
+ while (it.hasNext() && !changed) {
+ it.next();
+ if (!m_filterMap.contains(it.key())) {
+ changed = true;
+ } else {
+ QStringList a = it.value();
+ QStringList b = m_filterMap.value(it.key());
+ if (a.count() != b.count()) {
+ changed = true;
+ } else {
+ QStringList::const_iterator i(a.constBegin());
+ while (i != a.constEnd()) {
+ if (!b.contains(*i)) {
+ changed = true;
+ break;
+ }
+ ++i;
+ }
+ }
+ }
+ }
+ }
+ if (changed) {
+ foreach (QString filter, m_removedFilters)
+ m_helpEngine->removeCustomFilter(filter);
+ QMapIterator<QString, QStringList> it(m_filterMap);
+ while (it.hasNext()) {
+ it.next();
+ m_helpEngine->addCustomFilter(it.key(), it.value());
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/src/plugins/help/filtersettingspage.h b/src/plugins/help/filtersettingspage.h
new file mode 100644
index 0000000000..5cf83619a2
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef FILTERSETTINGSPAGE_H
+#define FILTERSETTINGSPAGE_H
+
+#include <QtGui/QWidget>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include "ui_filtersettingspage.h"
+
+QT_FORWARD_DECLARE_CLASS(QHelpEngine)
+
+namespace Help {
+namespace Internal {
+
+class FilterSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ FilterSettingsPage(QHelpEngine *helpEngine);
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ bool applyChanges();
+
+private slots:
+ void updateAttributes(QListWidgetItem *item);
+ void updateFilterMap();
+ void updateFilterPage();
+ void addFilter();
+ void removeFilter();
+
+private:
+ QHelpEngine *m_helpEngine;
+ Ui::FilterSettingsPage m_ui;
+ QMap<QString, QStringList> m_filterMapBackup;
+ QMap<QString, QStringList> m_filterMap;
+ QStringList m_removedFilters;
+ QWidget *m_currentPage;
+};
+
+} // namespace Help
+} // namespace Internal
+
+#endif // DOCSETTINGSPAGE_H
diff --git a/src/plugins/help/filtersettingspage.ui b/src/plugins/help/filtersettingspage.ui
new file mode 100644
index 0000000000..367e7ce0a9
--- /dev/null
+++ b/src/plugins/help/filtersettingspage.ui
@@ -0,0 +1,72 @@
+<ui version="4.0" >
+ <class>FilterSettingsPage</class>
+ <widget class="QWidget" name="FilterSettingsPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="label_2" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text" >
+ <string>Attributes:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QListWidget" name="filterWidget" />
+ </item>
+ <item rowspan="2" row="1" column="2" >
+ <widget class="QTreeWidget" name="attributeWidget" >
+ <property name="showDropIndicator" stdset="0" >
+ <bool>false</bool>
+ </property>
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="filterAddButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="filterRemoveButton" >
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/help/help.pri b/src/plugins/help/help.pri
new file mode 100644
index 0000000000..cea3ed71f9
--- /dev/null
+++ b/src/plugins/help/help.pri
@@ -0,0 +1,3 @@
+include(help_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(Help)
diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro
new file mode 100644
index 0000000000..a7de200f74
--- /dev/null
+++ b/src/plugins/help/help.pro
@@ -0,0 +1,36 @@
+TEMPLATE = lib
+TARGET = Help
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/quickopen/quickopen.pri)
+QT += network
+CONFIG += help
+DEFINES += QT_CLUCENE_SUPPORT \
+ HELP_LIBRARY
+HEADERS += helpplugin.h \
+ docsettingspage.h \
+ filtersettingspage.h \
+ helpmode.h \
+ centralwidget.h \
+ searchwidget.h \
+ helpfindsupport.h \
+ help_global.h \
+ helpindexfilter.h \
+ indexwindow.h
+SOURCES += helpplugin.cpp \
+ docsettingspage.cpp \
+ filtersettingspage.cpp \
+ helpmode.cpp \
+ centralwidget.cpp \
+ searchwidget.cpp \
+ helpfindsupport.cpp \
+ helpindexfilter.cpp
+FORMS += docsettingspage.ui \
+ filtersettingspage.ui
+RESOURCES += help.qrc
+include(../../../shared/help/help.pri)
+contains(QT_CONFIG, webkit) {
+ DEFINES += USE_WEBKIT
+ QT += webkit
+}
diff --git a/src/plugins/help/help.qrc b/src/plugins/help/help.qrc
new file mode 100644
index 0000000000..0b529633f8
--- /dev/null
+++ b/src/plugins/help/help.qrc
@@ -0,0 +1,16 @@
+<RCC>
+ <qresource prefix="/help" >
+ <file>images/find.png</file>
+ <file>images/book.png</file>
+ <file>images/previous.png</file>
+ <file>images/next.png</file>
+ <file>images/home.png</file>
+ <file>images/bookmark.png</file>
+ </qresource>
+ <qresource prefix="/trolltech/assistant" >
+ <file>images/mac/addtab.png</file>
+ <file>images/mac/closetab.png</file>
+ <file>images/win/addtab.png</file>
+ <file>images/win/closetab.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/help/help_global.h b/src/plugins/help/help_global.h
new file mode 100644
index 0000000000..104511ac88
--- /dev/null
+++ b/src/plugins/help/help_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef HELP_GLOBAL_H
+#define HELP_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(HELP_LIBRARY)
+# define HELP_EXPORT Q_DECL_EXPORT
+#else
+# define HELP_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // HELP_GLOBAL_H
diff --git a/src/plugins/help/helpengine.cpp b/src/plugins/help/helpengine.cpp
new file mode 100644
index 0000000000..790e4bf54a
--- /dev/null
+++ b/src/plugins/help/helpengine.cpp
@@ -0,0 +1,606 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QDateTime>
+#include <QtCore/QCoreApplication>
+
+#include "helpengine.h"
+#include "config.h"
+
+using namespace Help::Internal;
+
+static bool verifyDirectory(const QString &str)
+{
+ QFileInfo dirInfo(str);
+ if (!dirInfo.exists())
+ return QDir().mkdir(str);
+ if (!dirInfo.isDir()) {
+ qWarning("'%s' exists but is not a directory", str.toLatin1().constData());
+ return false;
+ }
+ return true;
+}
+
+struct IndexKeyword {
+ IndexKeyword(const QString &kw, const QString &l)
+ : keyword(kw), link(l) {}
+ IndexKeyword() : keyword(QString()), link(QString()) {}
+ bool operator<(const IndexKeyword &ik) const {
+ return keyword.toLower() < ik.keyword.toLower();
+ }
+ bool operator<=(const IndexKeyword &ik) const {
+ return keyword.toLower() <= ik.keyword.toLower();
+ }
+ bool operator>(const IndexKeyword &ik) const {
+ return keyword.toLower() > ik.keyword.toLower();
+ }
+ Q_DUMMY_COMPARISON_OPERATOR(IndexKeyword)
+ QString keyword;
+ QString link;
+};
+
+QDataStream &operator>>(QDataStream &s, IndexKeyword &ik)
+{
+ s >> ik.keyword;
+ s >> ik.link;
+ return s;
+}
+
+QDataStream &operator<<(QDataStream &s, const IndexKeyword &ik)
+{
+ s << ik.keyword;
+ s << ik.link;
+ return s;
+}
+
+
+/**
+ * Compare in a human-preferred alphanumeric way,
+ * e.g. 'Qt tutorial 2' will be less than 'Qt tutorial 11'.
+ */
+bool caseInsensitiveLessThan(const QString &as, const QString &bs)
+{
+ const QChar *a = as.unicode();
+ const QChar *b = bs.unicode();
+ int result = 0;
+ while (result == 0)
+ {
+ ushort aa = a->unicode();
+ ushort bb = b->unicode();
+
+ if (aa == 0 || bb == 0) {
+ result = aa - bb;
+ break;
+ }
+ else if (a->isDigit() && b->isDigit())
+ {
+ const QChar *a_begin = a;
+ const QChar *b_begin = b;
+ bool loop = true;
+ do {
+ if (a->isDigit()) ++a;
+ else if (b->isDigit()) ++b;
+ else loop = false;
+ } while (loop);
+
+ // optimization: comparing the length of the two numbers is more efficient than constructing two qstrings.
+ result = (a - a_begin) - (b - b_begin);
+ if (result == 0) {
+ QString astr(a_begin, a - a_begin);
+ QString bstr(b_begin, b - b_begin);
+ long la = astr.toLong();
+ long lb = bstr.toLong();
+ result = la - lb;
+ }
+ } else {
+ aa = QChar(aa).toLower().unicode();
+ bb = QChar(bb).toLower().unicode();
+ result = aa - bb;
+ ++a;
+ ++b;
+ }
+ }
+
+ return result < 0 ? true : false;
+}
+
+/**
+ * \a real is kinda a hack for the smart search, need a way to match a regexp to an item
+ * How would you say the best match for Q.*Wiget is QWidget?
+ */
+QModelIndex IndexListModel::filter(const QString &s, const QString &real)
+{
+ QStringList list;
+
+ int goodMatch = -1;
+ int perfectMatch = -1;
+ if (s.isEmpty())
+ perfectMatch = 0;
+
+ const QRegExp regExp(s);
+ QMultiMap<QString, QString>::iterator it = contents.begin();
+ QString lastKey;
+ for (; it != contents.end(); ++it) {
+ if (it.key() == lastKey)
+ continue;
+ lastKey = it.key();
+ const QString key = it.key();
+ if (key.contains(regExp) || key.contains(s, Qt::CaseInsensitive)) {
+ list.append(key);
+ //qDebug() << regExp << regExp.indexIn(s) << s << key << regExp.matchedLength();
+ if (perfectMatch == -1 && (key.startsWith(real, Qt::CaseInsensitive))) {
+ if (goodMatch == -1)
+ goodMatch = list.count() - 1;
+ if (s.length() == key.length())
+ perfectMatch = list.count() - 1;
+ } else if (perfectMatch > -1 && s == key) {
+ perfectMatch = list.count() - 1;
+ }
+ }
+ }
+
+ int bestMatch = perfectMatch;
+ if (bestMatch == -1)
+ bestMatch = goodMatch;
+
+ bestMatch = qMax(0, bestMatch);
+
+ // sort the new list
+ QString match;
+ if (bestMatch >= 0 && list.count() > bestMatch)
+ match = list[bestMatch];
+ qSort(list.begin(), list.end(), caseInsensitiveLessThan);
+ setStringList(list);
+ for (int i = 0; i < list.size(); ++i) {
+ if (list.at(i) == match){
+ bestMatch = i;
+ break;
+ }
+ }
+ return index(bestMatch, 0, QModelIndex());
+}
+
+
+
+
+
+
+
+
+
+HelpEngine::HelpEngine(QObject *parent, const QString &defaultQtVersionPath)
+ : QObject(parent)
+{
+ titleMapThread = new TitleMapThread(this);
+ connect(titleMapThread, SIGNAL(errorOccured(const QString&)),
+ this, SIGNAL(errorOccured(const QString&)));
+ connect(titleMapThread, SIGNAL(finished()), this, SLOT(titleMapFinished()));
+ indexThread = new IndexThread(this);
+ connect(indexThread, SIGNAL(errorOccured(const QString&)),
+ this, SIGNAL(errorOccured(const QString&)));
+ connect(indexThread, SIGNAL(finished()), this, SLOT(indexFinished()));
+
+ indexModel = new IndexListModel(this);
+
+ Config::loadConfig(defaultQtVersionPath);
+ cacheFilesPath = QDir::homePath() + QLatin1String("/.assistant");
+}
+
+HelpEngine::~HelpEngine()
+{
+ Config::configuration()->save();
+}
+
+void HelpEngine::init()
+{
+}
+
+QString HelpEngine::cacheFilePath() const
+{
+ return cacheFilesPath;
+}
+
+IndexListModel *HelpEngine::indices()
+{
+ return indexModel;
+}
+
+void HelpEngine::buildContents()
+{
+ contentsOnly = true;
+ if (!titleMapThread->isRunning()) {
+ titleMapThread->start(QThread::NormalPriority);
+ }
+}
+
+void HelpEngine::buildIndex()
+{
+ if (!titleMapThread->isRunning()) {
+ contentsOnly = false;
+ titleMapThread->start(QThread::NormalPriority);
+ }
+ if (!indexThread->isRunning())
+ indexThread->start(QThread::NormalPriority);
+}
+
+void HelpEngine::titleMapFinished()
+{
+ contentList = titleMapThread->contents();
+ titleMap = titleMapThread->documentTitleMap();
+ if (contentsOnly) {
+ contentsOnly = false;
+ emit contentsInitialized();
+ }
+}
+
+void HelpEngine::indexFinished()
+{
+ indexModel = indexThread->model();
+ emit indexInitialized();
+}
+
+void HelpEngine::removeOldCacheFiles(bool onlyFulltextSearchIndex)
+{
+ if (!verifyDirectory(cacheFilesPath)) {
+ qWarning("Failed to created assistant directory");
+ return;
+ }
+ QString pname = QLatin1String(".") + Config::configuration()->profileName();
+
+ QStringList fileList;
+ fileList << QLatin1String("indexdb40.dict")
+ << QLatin1String("indexdb40.doc");
+
+ if (!onlyFulltextSearchIndex)
+ fileList << QLatin1String("indexdb40") << QLatin1String("contentdb40");
+
+ QStringList::iterator it = fileList.begin();
+ for (; it != fileList.end(); ++it) {
+ if (QFile::exists(cacheFilesPath + QDir::separator() + *it + pname)) {
+ QFile f(cacheFilesPath + QDir::separator() + *it + pname);
+ f.remove();
+ }
+ }
+}
+
+quint32 HelpEngine::getFileAges()
+{
+ QStringList addDocuFiles = Config::configuration()->docFiles();
+ QStringList::const_iterator i = addDocuFiles.begin();
+
+ quint32 fileAges = 0;
+ for(; i != addDocuFiles.end(); ++i) {
+ QFileInfo fi(*i);
+ if (fi.exists())
+ fileAges += fi.lastModified().toTime_t();
+ }
+
+ return fileAges;
+}
+
+QString HelpEngine::removeAnchorFromLink(const QString &link)
+{
+ int i = link.length();
+ int j = link.lastIndexOf('/');
+ int l = link.lastIndexOf(QDir::separator());
+ if (l > j)
+ j = l;
+ if (j > -1) {
+ QString fileName = link.mid(j+1);
+ int k = fileName.lastIndexOf('#');
+ if (k > -1)
+ i = j + k + 1;
+ }
+ return link.left(i);
+}
+
+QString HelpEngine::titleOfLink(const QString &link)
+{
+ QString s = HelpEngine::removeAnchorFromLink(link);
+ s = titleMap[s];
+ if (s.isEmpty())
+ return link;
+ return s;
+}
+
+QString HelpEngine::home() const
+{
+ QString link = Config::configuration()->homePage();
+ if (!link.startsWith(QLatin1String("file:")))
+ link.prepend("file:");
+ return link;
+}
+
+
+
+
+
+
+
+
+
+
+TitleMapThread::TitleMapThread(HelpEngine *he)
+ : QThread(he)
+{
+ engine = he;
+ done = false;
+}
+
+TitleMapThread::~TitleMapThread()
+{
+
+}
+
+void TitleMapThread::run()
+{
+ if (done) {
+ engine->mutex.lock();
+ engine->titleMapDoneCondition.wakeAll();
+ engine->mutex.unlock();
+ return;
+ }
+
+ bool needRebuild = false;
+ if (Config::configuration()->profileName() == QLatin1String("default")) {
+ const QStringList docuFiles = Config::configuration()->docFiles();
+ for(QStringList::ConstIterator it = docuFiles.begin(); it != docuFiles.end(); it++) {
+ if (!QFile::exists(*it)) {
+ Config::configuration()->saveProfile(Profile::createDefaultProfile());
+ Config::configuration()->loadDefaultProfile();
+ needRebuild = true;
+ break;
+ }
+ }
+ }
+
+ if (Config::configuration()->docRebuild() || needRebuild) {
+ engine->removeOldCacheFiles();
+ Config::configuration()->setDocRebuild(false);
+ Config::configuration()->save();
+ }
+ if (contentList.isEmpty())
+ getAllContents();
+
+ titleMap.clear();
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ ContentList lst = (*it).second;
+ foreach (ContentItem item, lst) {
+ titleMap[item.reference] = item.title.trimmed();
+ }
+ }
+ done = true;
+ engine->mutex.lock();
+ engine->titleMapDoneCondition.wakeAll();
+ engine->mutex.unlock();
+}
+
+void TitleMapThread::getAllContents()
+{
+ QFile contentFile(engine->cacheFilePath() + QDir::separator() + QLatin1String("contentdb40.")
+ + Config::configuration()->profileName());
+ contentList.clear();
+ if (!contentFile.open(QFile::ReadOnly)) {
+ buildContentDict();
+ return;
+ }
+
+ QDataStream ds(&contentFile);
+ quint32 fileAges;
+ ds >> fileAges;
+ if (fileAges != engine->getFileAges()) {
+ contentFile.close();
+ engine->removeOldCacheFiles(true);
+ buildContentDict();
+ return;
+ }
+ QString key;
+ QList<ContentItem> lst;
+ while (!ds.atEnd()) {
+ ds >> key;
+ ds >> lst;
+ contentList += qMakePair(key, QList<ContentItem>(lst));
+ }
+ contentFile.close();
+
+}
+
+void TitleMapThread::buildContentDict()
+{
+ QStringList docuFiles = Config::configuration()->docFiles();
+
+ quint32 fileAges = 0;
+ for(QStringList::iterator it = docuFiles.begin(); it != docuFiles.end(); it++) {
+ QFile file(*it);
+ if (!file.exists()) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 does not exist!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ fileAges += QFileInfo(file).lastModified().toTime_t();
+ DocuParser *handler = DocuParser::createParser(*it);
+ if(!handler) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 is not compatible!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ bool ok = handler->parse(&file);
+ file.close();
+ if(ok) {
+ contentList += qMakePair(*it, QList<ContentItem>(handler->getContentItems()));
+ delete handler;
+ } else {
+#ifdef _SHOW_ERRORS_
+ QString msg = QString::fromLatin1("In file %1:\n%2")
+ .arg(QFileInfo(file).absoluteFilePath())
+ .arg(handler->errorProtocol());
+ emit errorOccured(msg);
+#endif
+ continue;
+ }
+ }
+
+ QFile contentOut(engine->cacheFilePath() + QDir::separator() + QLatin1String("contentdb40.")
+ + Config::configuration()->profileName());
+ if (contentOut.open(QFile::WriteOnly)) {
+ QDataStream s(&contentOut);
+ s << fileAges;
+ for(QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) {
+ s << *it;
+ }
+ contentOut.close();
+ }
+}
+
+
+
+
+
+IndexThread::IndexThread(HelpEngine *he)
+ : QThread(he)
+{
+ engine = he;
+ indexModel = new IndexListModel(this);
+ indexDone = false;
+}
+
+void IndexThread::run()
+{
+ if (indexDone)
+ return;
+ engine->mutex.lock();
+ if (engine->titleMapThread->isRunning())
+ engine->titleMapDoneCondition.wait(&(engine->mutex));
+ engine->mutex.unlock();
+
+ keywordDocuments.clear();
+ QList<IndexKeyword> lst;
+ QFile indexFile(engine->cacheFilePath() + QDir::separator() + QLatin1String("indexdb40.") +
+ Config::configuration()->profileName());
+ if (!indexFile.open(QFile::ReadOnly)) {
+ buildKeywordDB();
+ if (!indexFile.open(QFile::ReadOnly)) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Failed to load keyword index file!"));
+#endif
+ return;
+ }
+ }
+
+ QDataStream ds(&indexFile);
+ quint32 fileAges;
+ ds >> fileAges;
+ if (fileAges != engine->getFileAges()) {
+ indexFile.close();
+ buildKeywordDB();
+ if (!indexFile.open(QFile::ReadOnly)) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Cannot open the index file %1")
+ .arg(QFileInfo(indexFile).absoluteFilePath()));
+#endif
+ return;
+ }
+ ds.setDevice(&indexFile);
+ ds >> fileAges;
+ }
+ ds >> lst;
+ indexFile.close();
+
+ for (int i=0; i<lst.count(); ++i) {
+ const IndexKeyword &idx = lst.at(i);
+ indexModel->addLink(idx.keyword, idx.link);
+ keywordDocuments << HelpEngine::removeAnchorFromLink(idx.link);
+ }
+ indexModel->publish();
+ indexDone = true;
+}
+
+void IndexThread::buildKeywordDB()
+{
+ QStringList addDocuFiles = Config::configuration()->docFiles();
+ QStringList::iterator i = addDocuFiles.begin();
+
+ int steps = 0;
+ for(; i != addDocuFiles.end(); i++)
+ steps += QFileInfo(*i).size();
+
+ QList<IndexKeyword> lst;
+ quint32 fileAges = 0;
+ for(i = addDocuFiles.begin(); i != addDocuFiles.end(); i++){
+ QFile file(*i);
+ if (!file.exists()) {
+#ifdef _SHOW_ERRORS_
+ emit errorOccured(tr("Documentation file %1 does not exist!\n"
+ "Skipping file.").arg(QFileInfo(file).absoluteFilePath()));
+#endif
+ continue;
+ }
+ fileAges += QFileInfo(file).lastModified().toTime_t();
+ DocuParser *handler = DocuParser::createParser(*i);
+ bool ok = handler->parse(&file);
+ file.close();
+ if(!ok){
+#ifdef _SHOW_ERRORS_
+ QString msg = QString::fromLatin1("In file %1:\n%2")
+ .arg(QFileInfo(file).absoluteFilePath())
+ .arg(handler->errorProtocol());
+ emit errorOccured(msg);
+#endif
+ delete handler;
+ continue;
+ }
+
+ QList<IndexItem*> indLst = handler->getIndexItems();
+ foreach (IndexItem *indItem, indLst) {
+ QFileInfo fi(indItem->reference);
+ lst.append(IndexKeyword(indItem->keyword, indItem->reference));
+ }
+ delete handler;
+ }
+ if (!lst.isEmpty())
+ qSort(lst);
+
+ QFile indexout(engine->cacheFilePath() + QDir::separator() + QLatin1String("indexdb40.")
+ + Config::configuration()->profileName());
+ if (verifyDirectory(engine->cacheFilePath()) && indexout.open(QFile::WriteOnly)) {
+ QDataStream s(&indexout);
+ s << fileAges;
+ s << lst;
+ indexout.close();
+ }
+}
diff --git a/src/plugins/help/helpengine.h b/src/plugins/help/helpengine.h
new file mode 100644
index 0000000000..9aa79f4e52
--- /dev/null
+++ b/src/plugins/help/helpengine.h
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPENGINE_H
+#define HELPENGINE_H
+
+#include <QtCore/QThread>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+#include <QtGui/QStringListModel>
+
+#include "docuparser.h"
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+
+typedef QList<ContentItem> ContentList;
+
+class IndexListModel: public QStringListModel
+{
+public:
+ IndexListModel(QObject *parent = 0)
+ : QStringListModel(parent) {}
+
+ void clear() { contents.clear(); setStringList(QStringList()); }
+
+ QString description(int index) const { return stringList().at(index); }
+ QStringList links(int index) const { return contents.values(stringList().at(index)); }
+ void addLink(const QString &description, const QString &link) { contents.insert(description, link); }
+
+ void publish() { filter(QString(), QString()); }
+
+ QModelIndex filter(const QString &s, const QString &real);
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const
+ { return QStringListModel::flags(index) & ~Qt::ItemIsEditable; }
+
+private:
+ QMultiMap<QString, QString> contents;
+};
+
+class TitleMapThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ TitleMapThread(HelpEngine *he);
+ ~TitleMapThread();
+ void setup();
+ QList<QPair<QString, ContentList> > contents() const { return contentList; }
+ QMap<QString, QString> documentTitleMap() const { return titleMap; }
+
+signals:
+ void errorOccured(const QString &errMsg);
+
+protected:
+ void run();
+
+private:
+ void getAllContents();
+ void buildContentDict();
+
+ QList<QPair<QString, ContentList> > contentList;
+ QMap<QString, QString> titleMap;
+
+ HelpEngine *engine;
+ bool done;
+};
+
+class IndexThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ IndexThread(HelpEngine *he);
+ void setup();
+ IndexListModel *model() const { return indexModel; }
+
+protected:
+ void run();
+
+signals:
+ void errorOccured(const QString &errMsg);
+
+private:
+ void buildKeywordDB();
+
+ HelpEngine *engine;
+ QStringList keywordDocuments;
+ IndexListModel *indexModel;
+ bool indexDone;
+};
+
+class HelpEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ HelpEngine(QObject *parent, const QString& defaultQtVersionPath);
+ ~HelpEngine();
+ void init();
+ QList<QPair<QString, ContentList> > contents() const { return contentList; }
+ IndexListModel *indices();
+
+ QString titleOfLink(const QString &link);
+ static QString removeAnchorFromLink(const QString &link);
+
+ QString home() const;
+
+signals:
+ void indexInitialized();
+ void contentsInitialized();
+ void errorOccured(const QString &errMsg);
+
+public slots:
+ void buildContents();
+ void buildIndex();
+
+private slots:
+ void titleMapFinished();
+ void indexFinished();
+
+private:
+ friend class TitleMapThread;
+ friend class IndexThread;
+
+ void removeOldCacheFiles(bool onlyFulltextSearchIndex = false);
+ QString cacheFilePath() const;
+ quint32 getFileAges();
+
+ QList<QPair<QString, ContentList> > contentList;
+ QMap<QString, QString> titleMap;
+
+ QString cacheFilesPath;
+ IndexListModel *indexModel;
+
+ QWaitCondition titleMapDoneCondition;
+ QMutex mutex;
+
+ TitleMapThread *titleMapThread;
+ IndexThread *indexThread;
+
+ bool contentsOnly;
+};
+
+} //namespace Internal
+} //namespace Help
+
+#endif
diff --git a/src/plugins/help/helpfindsupport.cpp b/src/plugins/help/helpfindsupport.cpp
new file mode 100644
index 0000000000..306a1d5f40
--- /dev/null
+++ b/src/plugins/help/helpfindsupport.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpfindsupport.h"
+#include "helpviewer.h"
+
+using namespace Help::Internal;
+
+HelpFindSupport::HelpFindSupport(CentralWidget *centralWidget)
+ : m_centralWidget(centralWidget)
+{
+}
+
+HelpFindSupport::~HelpFindSupport()
+{
+}
+
+bool HelpFindSupport::isEnabled() const
+{
+ return true;
+}
+QString HelpFindSupport::currentFindString() const
+{
+ Q_ASSERT(m_centralWidget);
+ HelpViewer* viewer = m_centralWidget->currentHelpViewer();
+ if (!viewer)
+ return QString();
+#if defined(USE_WEBKIT)
+ return viewer->selectedText();
+#else
+ return viewer->textCursor().selectedText();
+#endif
+}
+
+
+QString HelpFindSupport::completedFindString() const { return QString(); }
+
+bool HelpFindSupport::findIncremental(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_centralWidget);
+ findFlags &= ~QTextDocument::FindBackward;
+ return m_centralWidget->find(txt, findFlags, true);
+}
+
+bool HelpFindSupport::findStep(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ Q_ASSERT(m_centralWidget);
+ return m_centralWidget->find(txt, findFlags, false);
+}
diff --git a/src/plugins/help/helpfindsupport.h b/src/plugins/help/helpfindsupport.h
new file mode 100644
index 0000000000..082e908c75
--- /dev/null
+++ b/src/plugins/help/helpfindsupport.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPFINDSUPPORT_H
+#define HELPFINDSUPPORT_H
+
+#include "centralwidget.h"
+
+#include <find/ifindsupport.h>
+
+namespace Help {
+namespace Internal {
+
+class HelpFindSupport : public Find::IFindSupport
+{
+ Q_OBJECT
+
+public:
+ HelpFindSupport(CentralWidget *centralWidget);
+ ~HelpFindSupport();
+
+ bool isEnabled() const;
+ bool supportsReplace() const { return false; }
+ void resetIncrementalSearch() {}
+ void clearResults() {}
+ QString currentFindString() const;
+ QString completedFindString() const;
+
+ bool findIncremental(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool findStep(const QString &txt, QTextDocument::FindFlags findFlags);
+ bool replaceStep(const QString &, const QString &,
+ QTextDocument::FindFlags ) { return false; }
+ int replaceAll(const QString &, const QString &,
+ QTextDocument::FindFlags ) { return 0; }
+
+private:
+ bool find(const QString &ttf, QTextDocument::FindFlags findFlags, bool incremental);
+
+ CentralWidget *m_centralWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPFINDSUPPORT_H
diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp
new file mode 100644
index 0000000000..b8aa2edfba
--- /dev/null
+++ b/src/plugins/help/helpindexfilter.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpindexfilter.h"
+#include "helpplugin.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpIndexModel>
+
+using namespace QuickOpen;
+using namespace Help;
+using namespace Help::Internal;
+
+Q_DECLARE_METATYPE(IQuickOpenFilter*);
+
+HelpIndexFilter::HelpIndexFilter(HelpPlugin *plugin, QHelpEngine *helpEngine):
+ m_plugin(plugin),
+ m_helpEngine(helpEngine),
+ m_icon(QIcon()) // TODO: Put an icon next to the results
+{
+ setIncludedByDefault(false);
+ setShortcutString("?");
+
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()),
+ this, SLOT(updateIndices()));
+}
+
+void HelpIndexFilter::updateIndices()
+{
+ const QString currentFilter = m_plugin->indexFilter();
+ if (!currentFilter.isEmpty())
+ m_plugin->setIndexFilter(QString());
+
+ m_helpIndex = m_helpEngine->indexModel()->stringList();
+
+ if (!currentFilter.isEmpty())
+ m_plugin->setIndexFilter(currentFilter);
+}
+
+QString HelpIndexFilter::trName() const
+{
+ return tr("Help index");
+}
+
+QString HelpIndexFilter::name() const
+{
+ return QLatin1String("HelpIndexFilter");
+}
+
+IQuickOpenFilter::Priority HelpIndexFilter::priority() const
+{
+ return Medium;
+}
+
+QList<FilterEntry> HelpIndexFilter::matchesFor(const QString &entry)
+{
+ QList<FilterEntry> entries;
+ foreach (const QString &string, m_helpIndex) {
+ if (string.contains(entry, Qt::CaseInsensitive)) {
+ FilterEntry entry(this, string, QVariant(), m_icon);
+ entries.append(entry);
+ }
+ }
+ return entries;
+}
+
+void HelpIndexFilter::accept(FilterEntry selection) const
+{
+ QMap<QString, QUrl> links = m_helpEngine->indexModel()->linksForKeyword(selection.displayName);
+ if (links.size() == 1) {
+ emit linkActivated(links.begin().value());
+ } else if (!links.isEmpty()) {
+ emit linksActivated(links, selection.displayName);
+ }
+}
+
+void HelpIndexFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+ // Nothing to refresh
+}
diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h
new file mode 100644
index 0000000000..0d62a9b5e1
--- /dev/null
+++ b/src/plugins/help/helpindexfilter.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPINDEXFILTER_H
+#define HELPINDEXFILTER_H
+
+#include <quickopen/iquickopenfilter.h>
+
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QHelpEngine;
+class QUrl;
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class HelpPlugin;
+
+class HelpIndexFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ HelpIndexFilter(HelpPlugin *plugin, QHelpEngine *helpEngine);
+
+ // IQuickOpenFilter
+ QString trName() const;
+ QString name() const;
+ Priority priority() const;
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+
+signals:
+ void linkActivated(const QUrl &link) const;
+ void linksActivated(const QMap<QString, QUrl> &urls, const QString &keyword) const;
+
+private slots:
+ void updateIndices();
+
+private:
+ HelpPlugin *m_plugin;
+ QHelpEngine *m_helpEngine;
+ QStringList m_helpIndex;
+ QIcon m_icon;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPINDEXFILTER_H
diff --git a/src/plugins/help/helpmode.cpp b/src/plugins/help/helpmode.cpp
new file mode 100644
index 0000000000..b57da2da22
--- /dev/null
+++ b/src/plugins/help/helpmode.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "helpmode.h"
+#include "helpplugin.h"
+
+#include <QtCore/QLatin1String>
+#include <QtGui/QWidget>
+#include <coreplugin/findplaceholder.h>
+
+using namespace Help;
+using namespace Help::Internal;
+
+HelpMode::HelpMode(QWidget *widget, QWidget *centralWidget, QObject *parent):
+ BaseMode(tr("Help"),
+ Constants::ID_MODE_HELP,
+ QIcon((QLatin1String(":/fancyactionbar/images/mode_Reference.png"))), Constants::P_MODE_HELP, widget, parent),
+ m_centralWidget(centralWidget)
+{
+ m_centralWidget->layout()->setSpacing(0);
+ m_centralWidget->layout()->addWidget(new Core::FindToolBarPlaceHolder(this));
+}
+
+
diff --git a/src/plugins/help/helpmode.h b/src/plugins/help/helpmode.h
new file mode 100644
index 0000000000..19b5c73a29
--- /dev/null
+++ b/src/plugins/help/helpmode.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef HELPMODE_H
+#define HELPMODE_H
+
+#include <QtCore/QObject>
+
+#include <coreplugin/basemode.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class HelpMode : public Core::BaseMode
+{
+ Q_OBJECT
+
+public:
+ HelpMode(QWidget *widget, QWidget *centralWidget, QObject *parent = 0);
+
+private:
+ QWidget *m_centralWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPMODE_H
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
new file mode 100644
index 0000000000..17712cd576
--- /dev/null
+++ b/src/plugins/help/helpplugin.cpp
@@ -0,0 +1,684 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "helpplugin.h"
+#include "docsettingspage.h"
+#include "filtersettingspage.h"
+#include "helpindexfilter.h"
+#include "helpmode.h"
+#include "helpviewer.h"
+#include "contentwindow.h"
+#include "indexwindow.h"
+#include "bookmarkmanager.h"
+#include "centralwidget.h"
+#include "helpfindsupport.h"
+#include "searchwidget.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/qplugin.h>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QDir>
+#include <QtCore/QResource>
+#include <QtGui/QAction>
+#include <QtGui/QShortcut>
+#include <QtGui/QSplitter>
+#include <QtGui/QStyle>
+#include <QtGui/QToolBar>
+#include <QtGui/QComboBox>
+#include <QtHelp/QHelpEngine>
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/rightpane.h>
+#include <coreplugin/sidebar.h>
+#include <coreplugin/welcomemode.h>
+
+using namespace Help;
+using namespace Help::Internal;
+
+HelpManager::HelpManager(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine)
+{
+}
+
+void HelpManager::registerDocumentation(const QStringList &fileNames)
+{
+ bool needsSetup = false;
+ {
+ QHelpEngineCore hc(m_helpEngine->collectionFile());
+ hc.setupData();
+ foreach (const QString &fileName, fileNames) {
+ if (!QFile::exists(fileName))
+ continue;
+ QString fileNamespace = QHelpEngineCore::namespaceName(fileName);
+ if (!fileNamespace.isEmpty() && !hc.registeredDocumentations().contains(fileNamespace)) {
+ if (hc.registerDocumentation(fileName))
+ needsSetup = true;
+ else
+ qDebug() << "error registering" << fileName << hc.error();
+ }
+ }
+ }
+ if (needsSetup)
+ qDebug() << m_helpEngine->setupData();
+}
+
+HelpPlugin::HelpPlugin() :
+ m_core(0),
+ m_helpEngine(0),
+ m_contextHelpEngine(0),
+ m_contentWidget(0),
+ m_indexWidget(0),
+ m_centralWidget(0),
+ m_helpViewerForSideBar(0),
+ m_mode(0),
+ m_shownLastPages(false),
+ m_contentItem(0),
+ m_indexItem(0),
+ m_searchItem(0),
+ m_bookmarkItem(0),
+ m_rightPaneSideBar(0)
+{
+}
+
+HelpPlugin::~HelpPlugin()
+{
+}
+
+bool HelpPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ QList<int> globalcontext;
+ globalcontext << Core::Constants::C_GLOBAL_ID;
+ QList<int> modecontext;
+ modecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_MODE_HELP);
+
+ // FIXME shouldn't the help engine create the directory if it doesn't exist?
+ QFileInfo fi(m_core->settings()->fileName());
+ QDir directory(fi.absolutePath());
+ if (!directory.exists())
+ directory.mkpath(directory.absolutePath());
+ m_helpEngine = new QHelpEngine(directory.absolutePath()
+ + QLatin1String("/helpcollection.qhc"), this);
+ connect(m_helpEngine, SIGNAL(setupFinished()),
+ this, SLOT(updateFilterComboBox()));
+
+ addAutoReleasedObject(new HelpManager(m_helpEngine));
+
+ m_docSettingsPage = new DocSettingsPage(m_helpEngine);
+ addAutoReleasedObject(m_docSettingsPage);
+
+ m_filterSettingsPage = new FilterSettingsPage(m_helpEngine);
+ addAutoReleasedObject(m_filterSettingsPage);
+ connect(m_docSettingsPage, SIGNAL(documentationAdded()),
+ m_filterSettingsPage, SLOT(updateFilterPage()));
+ connect(m_docSettingsPage, SIGNAL(dialogAccepted()),
+ this, SLOT(checkForHelpChanges()));
+
+ m_contentWidget = new ContentWindow(m_helpEngine);
+ m_contentWidget->setWindowTitle(tr("Contents"));
+ m_indexWidget = new IndexWindow(m_helpEngine);
+ m_indexWidget->setWindowTitle(tr("Index"));
+ m_searchWidget = new SearchWidget(m_helpEngine->searchEngine());
+ m_searchWidget->setWindowTitle(tr("Search"));
+ m_bookmarkManager = new BookmarkManager(m_helpEngine);
+ m_bookmarkWidget = new BookmarkWidget(m_bookmarkManager, 0, false);
+ m_bookmarkWidget->setWindowTitle(tr("Bookmarks"));
+ connect(m_bookmarkWidget, SIGNAL(addBookmark()),
+ this, SLOT(addBookmark()));
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ Core::ICommand *cmd;
+
+ // Add Home, Previous and Next actions (used in the toolbar)
+ QAction *homeAction = new QAction(QIcon(QLatin1String(":/help/images/home.png")), tr("Home"), this);
+ cmd = am->registerAction(homeAction, QLatin1String("Help.Home"), globalcontext);
+
+ QAction *previousAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")),
+ tr("Previous"), this);
+ cmd = am->registerAction(previousAction, QLatin1String("Help.Previous"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_Backspace));
+
+ QAction *nextAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Next"), this);
+ cmd = am->registerAction(nextAction, QLatin1String("Help.Next"), modecontext);
+
+ QAction *addBookmarkAction = new QAction(QIcon(QLatin1String(":/help/images/bookmark.png")),
+ tr("Add Bookmark"), this);
+ cmd = am->registerAction(addBookmarkAction, QLatin1String("Help.AddBookmark"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_M));
+
+ // Add Index, Contents, and Context menu items and a separator to the Help menu
+ QAction *indexAction = new QAction(tr("Index"), this);
+ cmd = am->registerAction(indexAction, QLatin1String("Help.Index"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *contentsAction = new QAction(tr("Contents"), this);
+ cmd = am->registerAction(contentsAction, QLatin1String("Help.Contents"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *searchAction = new QAction(tr("Search"), this);
+ cmd = am->registerAction(searchAction, QLatin1String("Help.Search"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+ QAction *contextAction = new QAction(tr("Context Help"), this);
+ cmd = am->registerAction(contextAction, QLatin1String("Help.Context"), globalcontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::Key_F1));
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+
+#ifndef Q_OS_MAC
+ QAction *sep = new QAction(this);
+ sep->setSeparator(true);
+ cmd = am->registerAction(sep, QLatin1String("Help.Separator"), globalcontext);
+ am->actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
+#endif
+
+ m_centralWidget = new CentralWidget(m_helpEngine);
+ Aggregation::Aggregate *agg = new Aggregation::Aggregate;
+ agg->add(m_centralWidget);
+ agg->add(new HelpFindSupport(m_centralWidget));
+ QWidget *mainWidget = new QWidget;
+ QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget);
+ mainWidgetLayout->setMargin(0);
+ mainWidgetLayout->setSpacing(0);
+ mainWidgetLayout->addWidget(createToolBar());
+ mainWidgetLayout->addWidget(m_centralWidget);
+
+ m_contentItem = new Core::SideBarItem(m_contentWidget);
+ m_indexItem = new Core::SideBarItem(m_indexWidget);
+ m_searchItem = new Core::SideBarItem(m_searchWidget);
+ m_bookmarkItem = new Core::SideBarItem(m_bookmarkWidget);
+ QList<Core::SideBarItem*> itemList;
+ itemList << m_contentItem << m_indexItem << m_searchItem << m_bookmarkItem;
+ m_sideBar = new Core::SideBar(itemList, QList<Core::SideBarItem*>() << m_indexItem);
+
+ QSplitter *splitter = new Core::MiniSplitter;
+ splitter->setOpaqueResize(false);
+ splitter->addWidget(m_sideBar);
+ splitter->addWidget(mainWidget);
+ splitter->setStretchFactor(0, 0);
+ splitter->setStretchFactor(1, 1);
+ splitter->setSizes(QList<int>() << 300 << 300);
+
+ m_mode = new HelpMode(splitter, m_centralWidget);
+ m_mode->setContext(QList<int>() << modecontext);
+ addAutoReleasedObject(m_mode);
+
+ QAction *printAction = new QAction(this);
+ am->registerAction(printAction, Core::Constants::PRINT, modecontext);
+ connect(printAction, SIGNAL(triggered()), m_centralWidget, SLOT(print()));
+
+ QAction *copyAction = new QAction(this);
+ cmd = am->registerAction(copyAction, Core::Constants::COPY, modecontext);
+ connect(copyAction, SIGNAL(triggered()), m_centralWidget, SLOT(copy()));
+ copyAction->setText(cmd->action()->text());
+ copyAction->setIcon(cmd->action()->icon());
+
+ QMap<QString, Core::ICommand*> shortcutMap;
+ QShortcut *shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Index in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.IndexShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_I));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateIndex()));
+ shortcutMap.insert(m_indexWidget->windowTitle(), cmd);
+
+ shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Contents in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.ContentsShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_T));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateContents()));
+ shortcutMap.insert(m_contentWidget->windowTitle(), cmd);
+
+ shortcut = new QShortcut(splitter);
+ shortcut->setWhatsThis(tr("Activate Search in Help mode"));
+ cmd = am->registerShortcut(shortcut, QLatin1String("Help.SearchShortcut"), modecontext);
+ cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
+ connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
+ shortcutMap.insert(m_searchWidget->windowTitle(), cmd);
+ shortcutMap.insert(m_bookmarkWidget->windowTitle(), 0);
+
+ m_sideBar->setShortcutMap(shortcutMap);
+
+ connect(homeAction, SIGNAL(triggered()), m_centralWidget, SLOT(home()));
+ connect(previousAction, SIGNAL(triggered()), m_centralWidget, SLOT(backward()));
+ connect(nextAction, SIGNAL(triggered()), m_centralWidget, SLOT(forward()));
+ connect(addBookmarkAction, SIGNAL(triggered()), this, SLOT(addBookmark()));
+ connect(m_contentWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_searchWidget, SIGNAL(requestShowLink(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(const QUrl&)),
+ m_centralWidget, SLOT(setSourceInNewTab(const QUrl&)));
+ connect(m_bookmarkWidget, SIGNAL(requestShowLink(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+
+ connect(m_centralWidget, SIGNAL(backwardAvailable(bool)),
+ previousAction, SLOT(setEnabled(bool)));
+ connect(m_centralWidget, SIGNAL(forwardAvailable(bool)),
+ nextAction, SLOT(setEnabled(bool)));
+ connect(m_centralWidget, SIGNAL(addNewBookmark(const QString&, const QString&)),
+ this, SLOT(addNewBookmark(const QString&, const QString&)));
+
+ QList<QAction*> actionList;
+ actionList << previousAction
+ << nextAction
+ << homeAction
+#ifndef Q_OS_MAC
+ << sep
+#endif
+ << copyAction;
+ m_centralWidget->setGlobalActions(actionList);
+
+ connect(contextAction, SIGNAL(triggered()), this, SLOT(activateContext()));
+ connect(indexAction, SIGNAL(triggered()), this, SLOT(activateIndex()));
+ connect(contentsAction, SIGNAL(triggered()), this, SLOT(activateContents()));
+ connect(searchAction, SIGNAL(triggered()), this, SLOT(activateSearch()));
+
+ connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*)),
+ this, SLOT(modeChanged(Core::IMode*)));
+
+ connect(m_contentWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linkActivated(const QUrl&)),
+ m_centralWidget, SLOT(setSource(const QUrl&)));
+ connect(m_indexWidget, SIGNAL(linksActivated(const QMap<QString, QUrl>&, const QString&)),
+ m_centralWidget, SLOT(showTopicChooser(const QMap<QString, QUrl>&, const QString&)));
+
+ HelpIndexFilter *helpIndexFilter = new HelpIndexFilter(this, m_helpEngine);
+ addAutoReleasedObject(helpIndexFilter);
+ connect(helpIndexFilter, SIGNAL(linkActivated(QUrl)),
+ this, SLOT(switchToHelpMode(QUrl)));
+ connect(helpIndexFilter, SIGNAL(linksActivated(const QMap<QString, QUrl>&, const QString&)),
+ this, SLOT(switchToHelpMode(const QMap<QString, QUrl>&, const QString&)));
+
+ previousAction->setEnabled(m_centralWidget->isBackwardAvailable());
+ nextAction->setEnabled(m_centralWidget->isForwardAvailable());
+
+ createRightPaneSideBar();
+
+ return true;
+}
+
+void HelpPlugin::createRightPaneSideBar()
+{
+ QAction *switchToHelpMode = new QAction("Go to Help Mode", this);
+ m_rightPaneBackwardAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")), tr("Previous"), this);
+ m_rightPaneForwardAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Next"), this);
+
+ QToolBar *rightPaneToolBar = new QToolBar();
+ rightPaneToolBar->addAction(switchToHelpMode);
+ rightPaneToolBar->addAction(m_rightPaneBackwardAction);
+ rightPaneToolBar->addAction(m_rightPaneForwardAction);
+
+ connect(switchToHelpMode, SIGNAL(triggered()), this, SLOT(switchToHelpMode()));
+ connect(m_rightPaneBackwardAction, SIGNAL(triggered()), this, SLOT(rightPaneBackward()));
+ connect(m_rightPaneForwardAction, SIGNAL(triggered()), this, SLOT(rightPaneForward()));
+
+ QToolButton *closeButton = new QToolButton();
+ closeButton->setProperty("type", QLatin1String("dockbutton"));
+ closeButton->setIcon(QIcon(":/qworkbench/images/closebutton.png"));
+
+ // Dummy layout to align the close button to the right
+ QHBoxLayout *hboxLayout = new QHBoxLayout();
+ hboxLayout->setSpacing(0);
+ hboxLayout->setMargin(0);
+ hboxLayout->addStretch(5);
+ hboxLayout->addWidget(closeButton);
+
+ QWidget *w = new QWidget(rightPaneToolBar);
+ w->setLayout(hboxLayout);
+ rightPaneToolBar->addWidget(w);
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(slotHideRightPane()));
+
+ QVBoxLayout *rightPaneLayout = new QVBoxLayout;
+ rightPaneLayout->setMargin(0);
+ rightPaneLayout->setSpacing(0);
+ rightPaneLayout->addWidget(rightPaneToolBar);
+
+ m_helpViewerForSideBar = new HelpViewer(m_helpEngine, 0);
+ rightPaneLayout->addWidget(m_helpViewerForSideBar);
+
+ m_rightPaneSideBar = new QWidget;
+ m_rightPaneSideBar->setLayout(rightPaneLayout);
+ m_rightPaneSideBar->setFocusProxy(m_helpViewerForSideBar);
+ addAutoReleasedObject(new Core::BaseRightPaneWidget(m_rightPaneSideBar));
+}
+
+void HelpPlugin::rightPaneBackward()
+{
+ m_helpViewerForSideBar->backward();
+}
+
+void HelpPlugin::rightPaneForward()
+{
+ m_helpViewerForSideBar->forward();
+}
+
+void HelpPlugin::switchToHelpMode()
+{
+ switchToHelpMode(m_helpViewerForSideBar->source());
+ Core::RightPaneWidget::instance()->setShown(false);
+}
+
+void HelpPlugin::switchToHelpMode(const QUrl &source)
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->setSource(source);
+ m_centralWidget->setFocus();
+}
+
+void HelpPlugin::switchToHelpMode(const QMap<QString, QUrl> &urls, const QString &keyword)
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->showTopicChooser(urls, keyword);
+}
+
+void HelpPlugin::slotHideRightPane()
+{
+ Core::RightPaneWidget::instance()->setShown(false);
+}
+
+void HelpPlugin::extensionsInitialized()
+{
+ m_sideBar->readSettings(m_core->settings());
+ if (!m_helpEngine->setupData()) {
+ qWarning() << "Could not initialize help engine: " << m_helpEngine->error();
+ return;
+ }
+
+ bool needsSetup = false;
+ bool assistantInternalDocRegistered = false;
+
+ foreach (QString ns, m_helpEngine->registeredDocumentations()) {
+ if (ns == QString("com.nokia.qtcreator.%1%2")
+ .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR)) {
+ assistantInternalDocRegistered = true;
+ break;
+ }
+ }
+
+ if (!assistantInternalDocRegistered) {
+ QFileInfo fi(m_helpEngine->collectionFile());
+
+ const QString qchFileName =
+ QDir::cleanPath(QCoreApplication::applicationDirPath()
+#if defined(Q_OS_MAC)
+ + QLatin1String("/../Resources/doc/qtcreator.qch"));
+#else
+ + QLatin1String("/../doc/qtcreator.qch"));
+#endif
+ QHelpEngineCore hc(fi.absoluteFilePath());
+ hc.setupData();
+ if (!hc.registerDocumentation(qchFileName))
+ qDebug() << hc.error();
+ needsSetup = true;
+ }
+
+ int i = m_helpEngine->customValue(
+ QLatin1String("UnfilteredFilterInserted")).toInt();
+ if (i != 1) {
+ {
+ QHelpEngineCore hc(m_helpEngine->collectionFile());
+ hc.setupData();
+ hc.addCustomFilter(tr("Unfiltered"), QStringList());
+ hc.setCustomValue(QLatin1String("UnfilteredFilterInserted"), 1);
+ }
+ m_helpEngine->blockSignals(true);
+ m_helpEngine->setCurrentFilter(tr("Unfiltered"));
+ m_helpEngine->blockSignals(false);
+ needsSetup = true;
+ }
+
+ if (needsSetup)
+ m_helpEngine->setupData();
+
+ updateFilterComboBox();
+ m_bookmarkManager->setupBookmarkModels();
+
+ if (Core::Internal::WelcomeMode *welcomeMode = qobject_cast<Core::Internal::WelcomeMode*>(m_core->modeManager()->mode(Core::Constants::MODE_WELCOME))) {
+ connect(welcomeMode, SIGNAL(requestHelp(QString)), this, SLOT(openGettingStarted()));
+ }
+}
+
+void HelpPlugin::shutdown()
+{
+ m_sideBar->saveSettings(m_core->settings());
+ m_bookmarkManager->saveBookmarks();
+ delete m_bookmarkManager;
+}
+
+void HelpPlugin::setIndexFilter(const QString &filter)
+{
+ m_indexWidget->setSearchLineEditText(filter);
+}
+
+QString HelpPlugin::indexFilter() const
+{
+ return m_indexWidget->searchLineEditText();
+}
+
+void HelpPlugin::modeChanged(Core::IMode *mode)
+{
+ if (mode == m_mode && !m_shownLastPages) {
+ m_shownLastPages = true;
+ qApp->processEvents();
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ m_centralWidget->setLastShownPages();
+ qApp->restoreOverrideCursor();
+ }
+}
+
+void HelpPlugin::activateContext()
+{
+ using namespace Core;
+ // case 1 sidebar shown and has focus, we show whatever we have in the
+ // sidebar in big
+ RightPanePlaceHolder* placeHolder = RightPanePlaceHolder::current();
+ if(placeHolder && Core::RightPaneWidget::instance()->hasFocus()) {
+ switchToHelpMode();
+ return;
+ }
+
+ bool useSideBar = false;
+ if (placeHolder && !Core::RightPaneWidget::instance()->hasFocus())
+ useSideBar = true;
+
+ // Find out what to show
+ HelpViewer *viewer = 0;
+ if (IContext *context = m_core->currentContextObject()) {
+ if (!m_contextHelpEngine) {
+ m_contextHelpEngine = new QHelpEngineCore(m_helpEngine->collectionFile(), this);
+ //m_contextHelpEngine->setAutoSaveFilter(false);
+ m_contextHelpEngine->setupData();
+ m_contextHelpEngine->setCurrentFilter(tr("Unfiltered"));
+ }
+
+ const QString &id = context->contextHelpId();
+ QMap<QString, QUrl> links = m_contextHelpEngine->linksForIdentifier(id);
+ if (!links.isEmpty()) {
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ QUrl source = *links.begin();
+ if (viewer->source() != source)
+ viewer->setSource(source);
+ viewer->setFocus();
+ }
+ } else {
+ // No link found
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ viewer->setHtml(tr("<title>No Documentation</title><br><br>"
+ "<center><b>%1</b><br><br>No documentation available.").
+ arg(id));
+ viewer->setSource(QUrl());
+ //activateIndex();
+ }
+ }
+ } else {
+ // No context object
+ if (useSideBar) {
+ Core::RightPaneWidget::instance()->setShown(true);
+ viewer = m_helpViewerForSideBar;
+ } else {
+ viewer = m_centralWidget->currentHelpViewer();
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ }
+
+ if (viewer) {
+ viewer->setSource(QUrl());
+ viewer->setHtml("<title>No Documentation</title><br><br><center>No"
+ " documentation available.");
+ //activateIndex();
+ }
+ }
+}
+
+void HelpPlugin::activateIndex()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_indexItem);
+}
+
+void HelpPlugin::activateContents()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_contentItem);
+}
+
+void HelpPlugin::activateSearch()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_sideBar->activateItem(m_searchItem);
+}
+
+QToolBar *HelpPlugin::createToolBar()
+{
+ QToolBar *toolWidget = new QToolBar;
+ Core::ActionManagerInterface *am = m_core->actionManager();
+ toolWidget->addAction(am->command(QLatin1String("Help.Home"))->action());
+ toolWidget->addAction(am->command(QLatin1String("Help.Previous"))->action());
+ toolWidget->addAction(am->command(QLatin1String("Help.Next"))->action());
+ toolWidget->addSeparator();
+ toolWidget->addAction(am->command(QLatin1String("Help.AddBookmark"))->action());
+ //int size = toolWidget->style()->pixelMetric(QStyle::PM_SmallIconSize);
+ //toolWidget->setIconSize(QSize(size, size));
+ toolWidget->setMovable(false);
+
+ toolWidget->addSeparator();
+
+ QWidget *w = new QWidget;
+ QHBoxLayout *layout = new QHBoxLayout(w);
+ layout->setMargin(0);
+ layout->addSpacing(10);
+ layout->addWidget(new QLabel(tr("Filtered by:")));
+ m_filterComboBox = new QComboBox;
+ m_filterComboBox->setMinimumContentsLength(20);
+ connect(m_filterComboBox, SIGNAL(activated(const QString&)),
+ this, SLOT(filterDocumentation(const QString&)));
+ layout->addWidget(m_filterComboBox);
+ toolWidget->addWidget(w);
+
+ return toolWidget;
+}
+
+void HelpPlugin::updateFilterComboBox()
+{
+ QString curFilter = m_filterComboBox->currentText();
+ if (curFilter.isEmpty())
+ curFilter = m_helpEngine->currentFilter();
+ m_filterComboBox->clear();
+ m_filterComboBox->addItems(m_helpEngine->customFilters());
+ int idx = m_filterComboBox->findText(curFilter);
+ if (idx < 0)
+ idx = 0;
+ m_filterComboBox->setCurrentIndex(idx);
+}
+
+void HelpPlugin::checkForHelpChanges()
+{
+ bool changed = m_docSettingsPage->applyChanges();
+ changed |= m_filterSettingsPage->applyChanges();
+ if (changed)
+ m_helpEngine->setupData();
+}
+
+void HelpPlugin::filterDocumentation(const QString &customFilter)
+{
+ m_helpEngine->setCurrentFilter(customFilter);
+}
+
+void HelpPlugin::addBookmark()
+{
+ addNewBookmark(m_centralWidget->currentTitle(), m_centralWidget->currentSource().toString());
+}
+
+void HelpPlugin::addNewBookmark(const QString &title, const QString &url)
+{
+ if (url.isEmpty())
+ return;
+
+ m_bookmarkManager->showBookmarkDialog(m_centralWidget, title, url);
+}
+
+void HelpPlugin::openGettingStarted()
+{
+ m_core->modeManager()->activateMode(QLatin1String(Constants::ID_MODE_HELP));
+ m_centralWidget->setSource(
+ QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html")
+ .arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
+}
+
+
+Q_EXPORT_PLUGIN(HelpPlugin)
diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h
new file mode 100644
index 0000000000..21dab96dc9
--- /dev/null
+++ b/src/plugins/help/helpplugin.h
@@ -0,0 +1,169 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef HELPPLUGIN_H
+#define HELPPLUGIN_H
+
+#include "help_global.h"
+#include <extensionsystem/iplugin.h>
+
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QComboBox;
+class QHelpEngineCore;
+class QHelpEngine;
+class QShortcut;
+class QToolBar;
+class QUrl;
+
+class IndexWindow;
+class ContentWindow;
+class BookmarkManager;
+class BookmarkWidget;
+class CentralWidget;
+class HelpViewer;
+QT_END_NAMESPACE
+
+
+namespace Core {
+class ICore;
+class IMode;
+class SideBar;
+class SideBarItem;
+}
+
+namespace Help {
+
+namespace Constants {
+ const char * const HELPVIEWER_KIND = "Qt Help Viewer";
+ const char * const C_MODE_HELP = "Help Mode";
+ const int P_MODE_HELP = 70;
+ const char * const ID_MODE_HELP = "Help.HelpMode";
+}
+
+class HELP_EXPORT HelpManager : public QObject
+{
+ Q_OBJECT
+public:
+ HelpManager(QHelpEngine *helpEngine);
+
+ void registerDocumentation(const QStringList &fileNames);
+
+private:
+ QHelpEngine *m_helpEngine;
+};
+
+namespace Internal {
+
+class HelpMode;
+class HelpPluginEditorFactory;
+class DocSettingsPage;
+class FilterSettingsPage;
+class SearchWidget;
+
+class HelpPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ HelpPlugin();
+ virtual ~HelpPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ void shutdown();
+
+ // Necessary to get the unfiltered list in the help index filter
+ void setIndexFilter(const QString &filter);
+ QString indexFilter() const;
+
+private slots:
+ void modeChanged(Core::IMode *mode);
+ void activateContext();
+ void activateIndex();
+ void activateContents();
+ void activateSearch();
+ void checkForHelpChanges();
+ void updateFilterComboBox();
+ void filterDocumentation(const QString &customFilter);
+ void addBookmark();
+ void addNewBookmark(const QString &title, const QString &url);
+
+ void rightPaneBackward();
+ void rightPaneForward();
+ void switchToHelpMode();
+ void switchToHelpMode(const QUrl &source);
+ void switchToHelpMode(const QMap<QString, QUrl> &urls, const QString &keyword);
+ void slotHideRightPane();
+
+ void openGettingStarted();
+
+private:
+ QToolBar *createToolBar();
+ void createRightPaneSideBar();
+
+ Core::ICore *m_core;
+ QHelpEngine *m_helpEngine;
+ QHelpEngineCore *m_contextHelpEngine;
+ ContentWindow *m_contentWidget;
+ IndexWindow *m_indexWidget;
+ BookmarkWidget *m_bookmarkWidget;
+ BookmarkManager *m_bookmarkManager;
+ SearchWidget *m_searchWidget;
+ CentralWidget *m_centralWidget;
+ HelpViewer *m_helpViewerForSideBar;
+ HelpMode *m_mode;
+ bool m_shownLastPages;
+
+ Core::SideBarItem *m_contentItem;
+ Core::SideBarItem *m_indexItem;
+ Core::SideBarItem *m_searchItem;
+ Core::SideBarItem *m_bookmarkItem;
+
+ DocSettingsPage *m_docSettingsPage;
+ FilterSettingsPage *m_filterSettingsPage;
+
+ QComboBox *m_filterComboBox;
+ Core::SideBar *m_sideBar;
+ QWidget *m_rightPaneSideBar;
+
+ QAction *m_rightPaneBackwardAction;
+ QAction *m_rightPaneForwardAction;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // HELPPLUGIN_H
diff --git a/src/plugins/help/images/book.png b/src/plugins/help/images/book.png
new file mode 100644
index 0000000000..ecd311b31f
--- /dev/null
+++ b/src/plugins/help/images/book.png
Binary files differ
diff --git a/src/plugins/help/images/bookmark.png b/src/plugins/help/images/bookmark.png
new file mode 100644
index 0000000000..7b2e5fd0ce
--- /dev/null
+++ b/src/plugins/help/images/bookmark.png
Binary files differ
diff --git a/src/plugins/help/images/find.png b/src/plugins/help/images/find.png
new file mode 100644
index 0000000000..fafcd3bb21
--- /dev/null
+++ b/src/plugins/help/images/find.png
Binary files differ
diff --git a/src/plugins/help/images/home.png b/src/plugins/help/images/home.png
new file mode 100644
index 0000000000..9cee3025d0
--- /dev/null
+++ b/src/plugins/help/images/home.png
Binary files differ
diff --git a/src/plugins/help/images/mac/addtab.png b/src/plugins/help/images/mac/addtab.png
new file mode 100644
index 0000000000..20928fb402
--- /dev/null
+++ b/src/plugins/help/images/mac/addtab.png
Binary files differ
diff --git a/src/plugins/help/images/mac/closetab.png b/src/plugins/help/images/mac/closetab.png
new file mode 100644
index 0000000000..ab9d669eee
--- /dev/null
+++ b/src/plugins/help/images/mac/closetab.png
Binary files differ
diff --git a/src/plugins/help/images/next.png b/src/plugins/help/images/next.png
new file mode 100644
index 0000000000..7700d6fce6
--- /dev/null
+++ b/src/plugins/help/images/next.png
Binary files differ
diff --git a/src/plugins/help/images/previous.png b/src/plugins/help/images/previous.png
new file mode 100644
index 0000000000..99dc8733c7
--- /dev/null
+++ b/src/plugins/help/images/previous.png
Binary files differ
diff --git a/src/plugins/help/images/win/addtab.png b/src/plugins/help/images/win/addtab.png
new file mode 100644
index 0000000000..4bb0feb92d
--- /dev/null
+++ b/src/plugins/help/images/win/addtab.png
Binary files differ
diff --git a/src/plugins/help/images/win/closetab.png b/src/plugins/help/images/win/closetab.png
new file mode 100644
index 0000000000..ef9e02086c
--- /dev/null
+++ b/src/plugins/help/images/win/closetab.png
Binary files differ
diff --git a/src/plugins/help/indextoolwindow.cpp b/src/plugins/help/indextoolwindow.cpp
new file mode 100644
index 0000000000..f80bd453cb
--- /dev/null
+++ b/src/plugins/help/indextoolwindow.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include <QtCore/QDebug>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QListView>
+#include <QtGui/QApplication>
+
+#include "indextoolwindow.h"
+#include "helpengine.h"
+#include "topicchooser.h"
+
+using namespace Help::Internal;
+
+IndexToolWidget::IndexToolWidget()
+{
+ wasInitialized = false;
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+
+ QLabel *l = new QLabel(tr("Look for:"), this);
+ layout->addWidget(l);
+
+ findLineEdit = new QLineEdit(this);
+ findLineEdit->installEventFilter(this);
+ layout->addWidget(findLineEdit);
+
+ indicesView = new QListView(this);
+ indicesView->setLayoutMode(QListView::Batched);
+ indicesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ layout->addWidget(indicesView);
+
+ setWindowTitle(tr("Index"));
+ setWindowIcon(QIcon(":/help/images/find.png"));
+}
+
+void IndexToolWidget::focusInEvent(QFocusEvent *e)
+{
+ showEvent(0);
+ if (e && e->reason() != Qt::MouseFocusReason) {
+ findLineEdit->selectAll();
+ findLineEdit->setFocus();
+ }
+}
+
+void IndexToolWidget::showEvent(QShowEvent *)
+{
+ if (!wasInitialized) {
+ wasInitialized = true;
+ setCursor(QCursor(Qt::WaitCursor));
+ emit buildRequested();
+ }
+}
+
+bool IndexToolWidget::eventFilter(QObject * o, QEvent * e)
+{
+ if (o == findLineEdit && e->type() == QEvent::KeyPress) {
+ switch (static_cast<QKeyEvent*>(e)->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageDown:
+ case Qt::Key_PageUp:
+ QApplication::sendEvent(indicesView, e);
+ break;
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+ default:
+ break;
+ }
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+
+IndexToolWindow::IndexToolWindow(const QList<int> &context, HelpEngine *help)
+{
+ m_context = context;
+ m_context << 0;
+
+ m_widget = new IndexToolWidget;
+
+ helpEngine = help;
+ connect(helpEngine, SIGNAL(indexInitialized()), this, SLOT(indexDone()));
+ model = 0;
+
+ connect(m_widget->findLineEdit, SIGNAL(textEdited(const QString&)),
+ this, SLOT(searchInIndex(const QString &)));
+ connect(m_widget->findLineEdit, SIGNAL(returnPressed()), this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(buildRequested()), helpEngine, SLOT(buildIndex()));
+
+ connect(m_widget->indicesView, SIGNAL(activated(const QModelIndex&)),
+ this, SLOT(indexRequested()));
+ connect(m_widget, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()));
+
+}
+
+IndexToolWindow::~IndexToolWindow()
+{
+ delete m_widget;
+}
+
+const QList<int> &IndexToolWindow::context() const
+{
+ return m_context;
+}
+
+QWidget *IndexToolWindow::widget()
+{
+ return m_widget;
+}
+
+void IndexToolWindow::indexDone()
+{
+ model = helpEngine->indices();
+ m_widget->indicesView->setModel(model);
+ m_widget->setCursor(QCursor(Qt::ArrowCursor));
+}
+
+void IndexToolWindow::searchInIndex(const QString &str)
+{
+ if (!model)
+ return;
+ QRegExp atoz("[A-Z]");
+ int matches = str.count(atoz);
+ if (matches > 0 && !str.contains(".*"))
+ {
+ int start = 0;
+ QString newSearch;
+ for (; matches > 0; --matches) {
+ int match = str.indexOf(atoz, start+1);
+ if (match <= start)
+ continue;
+ newSearch += str.mid(start, match-start);
+ newSearch += ".*";
+ start = match;
+ }
+ newSearch += str.mid(start);
+ m_widget->indicesView->setCurrentIndex(model->filter(newSearch, str));
+ }
+ else
+ m_widget->indicesView->setCurrentIndex(model->filter(str, str));
+}
+
+void IndexToolWindow::indexRequested()
+{
+ if (!model)
+ return;
+ int row = m_widget->indicesView->currentIndex().row();
+ if (row == -1 || row >= model->rowCount())
+ return;
+
+ QString description = model->description(row);
+ QStringList links = model->links(row);
+
+ bool blocked = m_widget->findLineEdit->blockSignals(true);
+ m_widget->findLineEdit->setText(description);
+ m_widget->findLineEdit->blockSignals(blocked);
+
+ if (links.count() == 1) {
+ emit showLinkRequested(links.first(), false);
+ } else {
+ qSort(links);
+ QStringList::Iterator it = links.begin();
+ QStringList linkList;
+ QStringList linkNames;
+ for (; it != links.end(); ++it) {
+ linkList << *it;
+ linkNames << helpEngine->titleOfLink(*it);
+ }
+ QString link = TopicChooser::getLink(m_widget, linkNames, linkList, description);
+ if (!link.isEmpty())
+ emit showLinkRequested(link, false);
+ }
+
+ model->publish();
+ m_widget->indicesView->setCurrentIndex(model->index(model->stringList().indexOf(description)));
+ m_widget->indicesView->scrollTo(m_widget->indicesView->currentIndex(), QAbstractItemView::PositionAtTop);
+}
+
diff --git a/src/plugins/help/indextoolwindow.h b/src/plugins/help/indextoolwindow.h
new file mode 100644
index 0000000000..4d4eb8f6b2
--- /dev/null
+++ b/src/plugins/help/indextoolwindow.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef INDEXTOOLWINDOW_H
+#define INDEXTOOLWINDOW_H
+
+#include <QtCore/QModelIndex>
+#include <QtGui/QWidget>
+
+#include <coreplugin/iview.h>
+
+class QListView;
+class QLineEdit;
+
+namespace Help {
+namespace Internal {
+
+class HelpEngine;
+class IndexListModel;
+class IndexToolWindow;
+
+class IndexToolWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ IndexToolWidget();
+
+signals:
+ void buildRequested();
+ void escapePressed();
+
+private:
+ friend class IndexToolWindow;
+
+ bool eventFilter(QObject * o, QEvent * e);
+ void showEvent(QShowEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ bool wasInitialized;
+ QLineEdit *findLineEdit;
+ QListView *indicesView;
+};
+
+
+class IndexToolWindow : public Core::IView
+{
+ Q_OBJECT
+
+public:
+ IndexToolWindow(const QList<int> &context, HelpEngine *help);
+ ~IndexToolWindow();
+
+ const QList<int> &context() const;
+ QWidget *widget();
+
+ QList<QWidget*> dockToolBarWidgets() const { return QList<QWidget*>(); }
+
+ const char *uniqueViewName() const { return "Help.IndexToolWindow"; }
+ const char *globalMenuGroup() const { return "Help.Group"; }
+ inline QKeySequence defaultShortcut() const { return QKeySequence(); }
+ Qt::DockWidgetArea defaultArea() const { return Qt::RightDockWidgetArea; }
+ IView::ViewPosition defaultPosition() const { return IView::Second; }
+
+signals:
+ void showLinkRequested(const QString &link, bool newWindow);
+ void escapePressed();
+
+private slots:
+ void indexDone();
+ void searchInIndex(const QString &str);
+ void indexRequested();
+
+private:
+ HelpEngine *helpEngine;
+ IndexListModel *model;
+
+ QList<int> m_context;
+ IndexToolWidget *m_widget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // INDEXTOOLWINDOW_H
diff --git a/src/plugins/help/indexwindow.h b/src/plugins/help/indexwindow.h
new file mode 100644
index 0000000000..a0e43a3f2a
--- /dev/null
+++ b/src/plugins/help/indexwindow.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDEXWINDOW
+#define INDEXWINDOW
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+#include <QtGui/QLineEdit>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpIndexWidget;
+class QHelpEngine;
+
+class IndexWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0);
+ ~IndexWindow();
+
+ void setSearchLineEditText(const QString &text);
+ QString searchLineEditText() const
+ {
+ return m_searchLineEdit->text();
+ }
+
+signals:
+ void linkActivated(const QUrl &link);
+ void linksActivated(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void escapePressed();
+
+private slots:
+ void filterIndices(const QString &filter);
+ void enableSearchLineEdit();
+ void disableSearchLineEdit();
+
+private:
+ bool eventFilter(QObject *obj, QEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ QLineEdit *m_searchLineEdit;
+ QHelpIndexWidget *m_indexWidget;
+ QHelpEngine *m_helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/help/searchwidget.cpp b/src/plugins/help/searchwidget.cpp
new file mode 100644
index 0000000000..620ca7ef76
--- /dev/null
+++ b/src/plugins/help/searchwidget.cpp
@@ -0,0 +1,213 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "searchwidget.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+#include <QtGui/QMenu>
+#include <QtGui/QLayout>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+#include <QtGui/QApplication>
+#include <QtGui/QTextBrowser>
+
+#include <QtHelp/QHelpSearchEngine>
+#include <QtHelp/QHelpSearchQueryWidget>
+#include <QtHelp/QHelpSearchResultWidget>
+
+using namespace Help::Internal;
+
+SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent)
+ : QWidget(parent)
+ , zoomCount(0)
+ , searchEngine(engine)
+{
+ QVBoxLayout *vLayout = new QVBoxLayout(this);
+
+ resultWidget = searchEngine->resultWidget();
+ QHelpSearchQueryWidget *queryWidget = searchEngine->queryWidget();
+
+ vLayout->addWidget(queryWidget);
+ vLayout->addWidget(resultWidget);
+
+ setFocusProxy(queryWidget);
+
+ connect(queryWidget, SIGNAL(search()), this, SLOT(search()));
+ connect(resultWidget, SIGNAL(requestShowLink(const QUrl&)),
+ this, SIGNAL(requestShowLink(const QUrl&)));
+
+ connect(searchEngine, SIGNAL(searchingStarted()), this, SLOT(searchingStarted()));
+ connect(searchEngine, SIGNAL(searchingFinished(int)), this, SLOT(searchingFinished(int)));
+}
+
+SearchWidget::~SearchWidget()
+{
+ // nothing todo
+}
+
+void SearchWidget::zoomIn()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser && zoomCount != 10) {
+ zoomCount++;
+ browser->zoomIn();
+ }
+}
+
+void SearchWidget::zoomOut()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser && zoomCount != -5) {
+ zoomCount--;
+ browser->zoomOut();
+ }
+}
+
+void SearchWidget::resetZoom()
+{
+#ifndef QT_CLUCENE_SUPPORT
+ return;
+#endif
+
+ if (zoomCount == 0)
+ return;
+
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (browser) {
+ browser->zoomOut(zoomCount);
+ zoomCount = 0;
+ }
+}
+
+void SearchWidget::search() const
+{
+ QList<QHelpSearchQuery> query = searchEngine->queryWidget()->query();
+ searchEngine->search(query);
+}
+
+void SearchWidget::searchingStarted()
+{
+ qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
+}
+
+void SearchWidget::searchingFinished(int hits)
+{
+ Q_UNUSED(hits)
+ qApp->restoreOverrideCursor();
+}
+
+void SearchWidget::keyPressEvent(QKeyEvent *keyEvent)
+{
+ if (keyEvent->key() == Qt::Key_Escape)
+ emit escapePressed();
+}
+
+void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
+{
+ QMenu menu;
+ QPoint point = contextMenuEvent->globalPos();
+
+#ifdef QT_CLUCENE_SUPPORT
+ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget);
+ if (!browser)
+ return;
+
+ point = browser->mapFromGlobal(point);
+ if (!browser->rect().contains(point, true))
+ return;
+
+ QUrl link = browser->anchorAt(point);
+
+ QAction *copyAction = menu.addAction(tr("&Copy") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_C))));
+ copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection());
+
+ QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location"));
+ copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL))) +
+ QLatin1String("LMB"));
+ newTabAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ menu.addSeparator();
+
+ QAction *selectAllAction = menu.addAction(tr("Select All") +
+ QString(QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_A))));
+
+ QAction *usedAction = menu.exec(mapToGlobal(contextMenuEvent->pos()));
+ if (usedAction == copyAction) {
+ QTextCursor cursor = browser->textCursor();
+ if (!cursor.isNull() && cursor.hasSelection()) {
+ QString selectedText = cursor.selectedText();
+ QMimeData *data = new QMimeData();
+ data->setText(selectedText);
+ QApplication::clipboard()->setMimeData(data);
+ }
+ }
+ else if (usedAction == copyAnchorAction) {
+ QApplication::clipboard()->setText(link.toString());
+ }
+ else if (usedAction == newTabAction) {
+ emit requestShowLinkInNewTab(link);
+ }
+ else if (usedAction == selectAllAction) {
+ browser->selectAll();
+ }
+#else
+ point = resultWidget->mapFromGlobal(point);
+ QUrl link = resultWidget->linkAt(point);
+ if (link.isEmpty() || !link.isValid())
+ return;
+
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+
+ QAction *action = menu.exec(mapToGlobal(contextMenuEvent->pos()));
+ if (curTab == action)
+ emit requestShowLink(link);
+ else if (newTab == action)
+ emit requestShowLinkInNewTab(link);
+#endif
+}
diff --git a/src/plugins/help/searchwidget.h b/src/plugins/help/searchwidget.h
new file mode 100644
index 0000000000..64143fafbf
--- /dev/null
+++ b/src/plugins/help/searchwidget.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef SEARCHWIDGET_H
+#define SEARCHWIDGET_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QPoint>
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QMouseEvent;
+class QHelpSearchEngine;
+class QHelpSearchResultWidget;
+
+QT_END_NAMESPACE
+
+namespace Help {
+namespace Internal {
+
+class SearchWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SearchWidget(QHelpSearchEngine *engine, QWidget *parent = 0);
+ ~SearchWidget();
+
+ void zoomIn();
+ void zoomOut();
+ void resetZoom();
+
+signals:
+ void requestShowLink(const QUrl &url);
+ void requestShowLinkInNewTab(const QUrl &url);
+ void escapePressed();
+
+private slots:
+ void search() const;
+ void searchingStarted();
+ void searchingFinished(int hits);
+
+private:
+ void keyPressEvent(QKeyEvent *keyEvent);
+ void contextMenuEvent(QContextMenuEvent *contextMenuEvent);
+
+private:
+ int zoomCount;
+ QHelpSearchEngine *searchEngine;
+ QHelpSearchResultWidget *resultWidget;
+};
+
+} // namespace Internal
+} // namespace Help
+
+#endif // SEARCHWIDGET_H