summaryrefslogtreecommitdiff
path: root/src/plugins/help/centralwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/help/centralwidget.cpp')
-rw-r--r--src/plugins/help/centralwidget.cpp687
1 files changed, 687 insertions, 0 deletions
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("&&"));
+}