/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the Qt Assistant of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 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 the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "tracer.h" | |
#include "centralwidget.h" | |
#include "findwidget.h" | |
#include "helpenginewrapper.h" | |
#include "searchwidget.h" | |
#include "mainwindow.h" | |
#include "../shared/collectionconfiguration.h" | |
#if defined(QT_NO_WEBKIT) | |
#include "helpviewer_qtb.h" | |
#else | |
#include "helpviewer_qwv.h" | |
#endif // QT_NO_WEBKIT | |
#include <QtCore/QTimer> | |
#include <QtGui/QApplication> | |
#include <QtGui/QKeyEvent> | |
#include <QtGui/QLayout> | |
#include <QtGui/QMenu> | |
#include <QtGui/QPrinter> | |
#include <QtGui/QTabBar> | |
#include <QtGui/QTabWidget> | |
#include <QtGui/QTextBrowser> | |
#include <QtGui/QToolButton> | |
#include <QtGui/QPageSetupDialog> | |
#include <QtGui/QPrintDialog> | |
#include <QtGui/QPrintPreviewDialog> | |
#include <QtHelp/QHelpSearchEngine> | |
QT_BEGIN_NAMESPACE | |
namespace { | |
HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget, | |
const QPoint &point) | |
{ | |
TRACE_OBJ | |
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::CentralWidget(MainWindow *parent) | |
: QWidget(parent) | |
, lastTabPage(0) | |
, tabWidget(0) | |
, findWidget(0) | |
, printer(0) | |
, usesDefaultCollection(parent->usesDefaultCollection()) | |
, m_searchWidget(0) | |
{ | |
TRACE_OBJ | |
globalActionList.clear(); | |
staticCentralWidget = this; | |
QVBoxLayout *vboxLayout = new QVBoxLayout(this); | |
QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); | |
vboxLayout->setMargin(0); | |
tabWidget = new QTabWidget(this); | |
#ifndef Q_OS_MAC | |
resourcePath.append(QLatin1String("win")); | |
#else | |
resourcePath.append(QLatin1String("mac")); | |
tabWidget->setDocumentMode(true); | |
#endif | |
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(resourcePath + QLatin1String("/addtab.png"))); | |
tabWidget->setCornerWidget(newTabButton, Qt::TopLeftCorner); | |
connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab())); | |
QToolButton *closeTabButton = new QToolButton(this); | |
closeTabButton->setEnabled(false); | |
closeTabButton->setAutoRaise(true); | |
closeTabButton->setToolTip(tr("Close current page")); | |
closeTabButton->setIcon(QIcon(resourcePath + QLatin1String("/closetab.png"))); | |
tabWidget->setCornerWidget(closeTabButton, Qt::TopRightCorner); | |
connect(closeTabButton, SIGNAL(clicked()), this, SLOT(closeTab())); | |
vboxLayout->addWidget(tabWidget); | |
findWidget = new FindWidget(this); | |
vboxLayout->addWidget(findWidget); | |
findWidget->hide(); | |
connect(findWidget, SIGNAL(findNext()), this, SLOT(findNext())); | |
connect(findWidget, SIGNAL(findPrevious()), this, SLOT(findPrevious())); | |
connect(findWidget, SIGNAL(find(QString, bool)), this, | |
SLOT(find(QString, bool))); | |
connect(findWidget, SIGNAL(escapePressed()), this, SLOT(activateTab())); | |
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); | |
if (tabBar) { | |
tabBar->installEventFilter(this); | |
tabBar->setContextMenuPolicy(Qt::CustomContextMenu); | |
connect(tabBar, SIGNAL(customContextMenuRequested(QPoint)), this, | |
SLOT(showTabBarContextMenu(QPoint))); | |
} | |
#if defined(QT_NO_WEBKIT) | |
QPalette p = palette(); | |
p.setColor(QPalette::Inactive, QPalette::Highlight, | |
p.color(QPalette::Active, QPalette::Highlight)); | |
p.setColor(QPalette::Inactive, QPalette::HighlightedText, | |
p.color(QPalette::Active, QPalette::HighlightedText)); | |
setPalette(p); | |
#endif | |
} | |
CentralWidget::~CentralWidget() | |
{ | |
TRACE_OBJ | |
#ifndef QT_NO_PRINTER | |
delete printer; | |
#endif | |
QStringList zoomFactors; | |
QStringList currentPages; | |
bool searchAttached = m_searchWidget->isAttached(); | |
int i = searchAttached ? 1 : 0; | |
for (; i < tabWidget->count(); ++i) { | |
HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); | |
if (viewer && viewer->source().isValid()) { | |
currentPages << viewer->source().toString(); | |
zoomFactors << QString::number(viewer->scale()); | |
} | |
} | |
HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); | |
helpEngine.setLastTabPage(tabWidget->currentIndex()); | |
helpEngine.setLastShownPages(currentPages); | |
helpEngine.setSearchWasAttached(searchAttached); | |
helpEngine.setLastZoomFactors(zoomFactors); | |
} | |
CentralWidget *CentralWidget::instance() | |
{ | |
TRACE_OBJ | |
return staticCentralWidget; | |
} | |
void CentralWidget::newTab() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
#if !defined(QT_NO_WEBKIT) | |
if (viewer && viewer->hasLoadFinished()) | |
#else | |
if (viewer) | |
#endif | |
setSourceInNewTab(viewer->source()); | |
} | |
void CentralWidget::zoomIn() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->scaleUp(); | |
if (tabWidget->currentWidget() == m_searchWidget) | |
m_searchWidget->zoomIn(); | |
} | |
void CentralWidget::zoomOut() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->scaleDown(); | |
if (tabWidget->currentWidget() == m_searchWidget) | |
m_searchWidget->zoomOut(); | |
} | |
void CentralWidget::nextPage() | |
{ | |
TRACE_OBJ | |
int index = tabWidget->currentIndex() + 1; | |
if (index >= tabWidget->count()) | |
index = 0; | |
tabWidget->setCurrentIndex(index); | |
} | |
void CentralWidget::resetZoom() | |
{ | |
TRACE_OBJ | |
if (HelpViewer *viewer = currentHelpViewer()) | |
viewer->resetScale(); | |
if (tabWidget->currentWidget() == m_searchWidget) | |
m_searchWidget->resetZoom(); | |
} | |
void CentralWidget::previousPage() | |
{ | |
TRACE_OBJ | |
int index = tabWidget->currentIndex() -1; | |
if (index < 0) | |
index = tabWidget->count() -1; | |
tabWidget->setCurrentIndex(index); | |
} | |
void CentralWidget::closeTab() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (!viewer|| tabWidget->count() == 1) | |
return; | |
tabWidget->removeTab(tabWidget->indexOf(viewer)); | |
QTimer::singleShot(0, viewer, SLOT(deleteLater())); | |
} | |
void CentralWidget::setSource(const QUrl &url) | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
HelpViewer *lastViewer = | |
qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage)); | |
if (!viewer && !lastViewer) { | |
viewer = new HelpViewer(this); | |
viewer->installEventFilter(this); | |
lastTabPage = tabWidget->addTab(viewer, QString()); | |
tabWidget->setCurrentIndex(lastTabPage); | |
connectSignals(); | |
} else { | |
viewer = lastViewer; | |
} | |
viewer->setSource(url); | |
currentPageChanged(lastTabPage); | |
viewer->setFocus(Qt::OtherFocusReason); | |
tabWidget->setCurrentIndex(lastTabPage); | |
tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle())); | |
} | |
void CentralWidget::setupWidget() | |
{ | |
TRACE_OBJ | |
HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); | |
int option = helpEngine.startOption(); | |
if (option != ShowLastPages) { | |
QString homePage; | |
if (option == ShowHomePage) | |
homePage = helpEngine.homePage(); | |
else if (option == ShowBlankPage) | |
homePage = QLatin1String("about:blank"); | |
setSource(homePage); | |
} else { | |
setLastShownPages(); | |
} | |
} | |
void CentralWidget::setLastShownPages() | |
{ | |
TRACE_OBJ | |
HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); | |
const QStringList &lastShownPageList = helpEngine.lastShownPages(); | |
const int pageCount = lastShownPageList.count(); | |
if (pageCount == 0) { | |
if (usesDefaultCollection) | |
setSource(QUrl(QLatin1String("help"))); | |
else | |
setSource(QUrl(QLatin1String("about:blank"))); | |
return; | |
} | |
QStringList zoomFactors = helpEngine.lastZoomFactors(); | |
while (zoomFactors.count() < pageCount) | |
zoomFactors.append(CollectionConfiguration::DefaultZoomFactor); | |
const bool searchIsAttached = m_searchWidget->isAttached(); | |
const bool searchWasAttached = helpEngine.searchWasAttached(); | |
int tabToShow = helpEngine.lastTabPage(); | |
if (searchWasAttached && !searchIsAttached && tabToShow != 0) | |
--tabToShow; | |
else if (!searchWasAttached && searchIsAttached) | |
++tabToShow; | |
for (int curTab = 0; curTab < pageCount; ++curTab) { | |
const QString &curFile = lastShownPageList.at(curTab); | |
if (helpEngine.findFile(curFile).isValid() | |
|| curFile == QLatin1String("about:blank")) { | |
setSourceInNewTab(curFile, zoomFactors.at(curTab).toFloat()); | |
} else if (curTab + searchIsAttached <= tabToShow) | |
--tabToShow; | |
} | |
tabWidget->setCurrentIndex(tabToShow); | |
} | |
bool CentralWidget::hasSelection() const | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
return viewer ? viewer->hasSelection() : false; | |
} | |
QUrl CentralWidget::currentSource() const | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
return viewer->source(); | |
return QUrl(); | |
} | |
QString CentralWidget::currentTitle() const | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
return viewer->documentTitle(); | |
return QString(); | |
} | |
void CentralWidget::copySelection() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->copy(); | |
} | |
void CentralWidget::showTextSearch() | |
{ | |
TRACE_OBJ | |
findWidget->show(); | |
} | |
void CentralWidget::initPrinter() | |
{ | |
TRACE_OBJ | |
#ifndef QT_NO_PRINTER | |
if (!printer) | |
printer = new QPrinter(QPrinter::HighResolution); | |
#endif | |
} | |
void CentralWidget::print() | |
{ | |
TRACE_OBJ | |
#ifndef QT_NO_PRINTER | |
HelpViewer *viewer = currentHelpViewer(); | |
if (!viewer) | |
return; | |
initPrinter(); | |
QPrintDialog dlg(printer, this); | |
#if defined(QT_NO_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); | |
} | |
#endif | |
} | |
void CentralWidget::printPreview() | |
{ | |
TRACE_OBJ | |
#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) | |
{ | |
TRACE_OBJ | |
#ifndef QT_NO_PRINTER | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->print(p); | |
#endif | |
} | |
void CentralWidget::pageSetup() | |
{ | |
TRACE_OBJ | |
#ifndef QT_NO_PRINTER | |
initPrinter(); | |
QPageSetupDialog dlg(printer); | |
dlg.exec(); | |
#endif | |
} | |
bool CentralWidget::isHomeAvailable() const | |
{ | |
TRACE_OBJ | |
return currentHelpViewer() ? true : false; | |
} | |
void CentralWidget::home() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->home(); | |
} | |
bool CentralWidget::isForwardAvailable() const | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
return viewer->isForwardAvailable(); | |
return false; | |
} | |
void CentralWidget::forward() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->forward(); | |
} | |
bool CentralWidget::isBackwardAvailable() const | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
return viewer->isBackwardAvailable(); | |
return false; | |
} | |
void CentralWidget::backward() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
viewer->backward(); | |
} | |
QList<QAction*> CentralWidget::globalActions() const | |
{ | |
TRACE_OBJ | |
return globalActionList; | |
} | |
void CentralWidget::setGlobalActions(const QList<QAction*> &actions) | |
{ | |
TRACE_OBJ | |
globalActionList = actions; | |
} | |
void CentralWidget::setSourceInNewTab(const QUrl &url, qreal zoom) | |
{ | |
TRACE_OBJ | |
if (HelpViewer *viewer = currentHelpViewer()) { | |
if (viewer->launchWithExternalApp(url)) | |
return; | |
} | |
HelpViewer *viewer = new HelpViewer(this, zoom); | |
viewer->installEventFilter(this); | |
viewer->setSource(url); | |
viewer->setFocus(Qt::OtherFocusReason); | |
tabWidget->setCurrentIndex(tabWidget->addTab(viewer, | |
quoteTabTitle(viewer->documentTitle()))); | |
connectSignals(); | |
} | |
HelpViewer *CentralWidget::newEmptyTab() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = new HelpViewer(this); | |
viewer->installEventFilter(this); | |
viewer->setFocus(Qt::OtherFocusReason); | |
#if defined(QT_NO_WEBKIT) | |
viewer->setDocumentTitle(tr("unknown")); | |
#endif | |
tabWidget->setCurrentIndex(tabWidget->addTab(viewer, tr("unknown"))); | |
connectSignals(); | |
return viewer; | |
} | |
void CentralWidget::connectSignals() | |
{ | |
TRACE_OBJ | |
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(QUrl)), this, | |
SIGNAL(sourceChanged(QUrl))); | |
connect(viewer, SIGNAL(highlighted(QString)), this, | |
SIGNAL(highlighted(QString))); | |
connect(viewer, SIGNAL(sourceChanged(QUrl)), this, | |
SLOT(setTabTitle(QUrl))); | |
connect(viewer, SIGNAL(printRequested()), this, SLOT(print())); | |
} | |
} | |
HelpViewer* CentralWidget::viewerAt(int index) const | |
{ | |
TRACE_OBJ | |
return qobject_cast<HelpViewer*>(tabWidget->widget(index)); | |
} | |
HelpViewer* CentralWidget::currentHelpViewer() const | |
{ | |
TRACE_OBJ | |
return qobject_cast<HelpViewer*>(tabWidget->currentWidget()); | |
} | |
void CentralWidget::activateTab(bool onlyHelpViewer) | |
{ | |
TRACE_OBJ | |
if (currentHelpViewer()) { | |
currentHelpViewer()->setFocus(); | |
} else { | |
int idx = 0; | |
if (onlyHelpViewer) | |
idx = lastTabPage; | |
tabWidget->setCurrentIndex(idx); | |
tabWidget->currentWidget()->setFocus(); | |
} | |
} | |
void CentralWidget::setTabTitle(const QUrl &url) | |
{ | |
TRACE_OBJ | |
Q_UNUSED(url) | |
#if !defined(QT_NO_WEBKIT) | |
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); | |
for (int tab = 0; tab < tabBar->count(); ++tab) { | |
HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(tab)); | |
if (viewer) { | |
tabWidget->setTabText(tab, | |
quoteTabTitle(viewer->documentTitle().trimmed())); | |
} | |
} | |
#else | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) { | |
tabWidget->setTabText(lastTabPage, | |
quoteTabTitle(viewer->documentTitle().trimmed())); | |
} | |
#endif | |
} | |
void CentralWidget::currentPageChanged(int index) | |
{ | |
TRACE_OBJ | |
const HelpViewer *viewer = currentHelpViewer(); | |
if (viewer) | |
lastTabPage = index; | |
QWidget *widget = tabWidget->cornerWidget(Qt::TopRightCorner); | |
widget->setEnabled(viewer && enableTabCloseAction()); | |
widget = tabWidget->cornerWidget(Qt::TopLeftCorner); | |
widget->setEnabled(viewer ? true : false); | |
emit currentViewerChanged(); | |
} | |
void CentralWidget::showTabBarContextMenu(const QPoint &point) | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, point); | |
if (!viewer) | |
return; | |
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); | |
QMenu menu(QLatin1String(""), tabBar); | |
QAction *newPage = menu.addAction(tr("Add New Page")); | |
bool enableAction = enableTabCloseAction(); | |
QAction *closePage = menu.addAction(tr("Close This Page")); | |
closePage->setEnabled(enableAction); | |
QAction *closePages = menu.addAction(tr("Close Other Pages")); | |
closePages->setEnabled(enableAction); | |
menu.addSeparator(); | |
QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page...")); | |
const QString &url = viewer->source().toString(); | |
if (url.isEmpty() || url == QLatin1String("about:blank")) | |
newBookmark->setEnabled(false); | |
QAction *pickedAction = menu.exec(tabBar->mapToGlobal(point)); | |
if (pickedAction == newPage) | |
setSourceInNewTab(viewer->source()); | |
if (pickedAction == closePage) { | |
tabWidget->removeTab(tabWidget->indexOf(viewer)); | |
QTimer::singleShot(0, viewer, SLOT(deleteLater())); | |
} | |
if (pickedAction == closePages) { | |
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 (pickedAction == newBookmark) | |
emit addBookmark(viewer->documentTitle(), viewer->source().toString()); | |
} | |
bool CentralWidget::eventFilter(QObject *object, QEvent *e) | |
{ | |
TRACE_OBJ | |
if (e->type() == QEvent::KeyPress) { | |
QKeyEvent *ke = static_cast<QKeyEvent*>(e); | |
switch (ke->key()) { | |
default: { | |
return QWidget::eventFilter(object, e); | |
} break; | |
case Qt::Key_Backspace: { | |
HelpViewer *viewer = currentHelpViewer(); | |
if (viewer == object) { | |
#if defined(QT_NO_WEBKIT) | |
if (viewer->isBackwardAvailable()) { | |
#else | |
if (viewer->isBackwardAvailable() && !viewer->hasFocus()) { | |
#endif | |
viewer->backward(); | |
return true; | |
} | |
} | |
} break; | |
} | |
} | |
if (qobject_cast<QTabBar*>(object)) { | |
const bool dblClick = e->type() == QEvent::MouseButtonDblClick; | |
if ((e->type() == QEvent::MouseButtonRelease) || dblClick) { | |
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e); | |
HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, | |
mouseEvent->pos()); | |
if (viewer) { | |
if ((mouseEvent->button() == Qt::MidButton) || dblClick) { | |
if (availableHelpViewer() > 1) { | |
tabWidget->removeTab(tabWidget->indexOf(viewer)); | |
QTimer::singleShot(0, viewer, SLOT(deleteLater())); | |
currentPageChanged(tabWidget->currentIndex()); | |
return true; | |
} | |
} | |
} | |
} | |
} | |
return QWidget::eventFilter(object, e); | |
} | |
void CentralWidget::keyPressEvent(QKeyEvent *e) | |
{ | |
TRACE_OBJ | |
const QString &text = e->text(); | |
if (text.startsWith(QLatin1Char('/'))) { | |
if (!findWidget->isVisible()) { | |
findWidget->showAndClear(); | |
} else { | |
findWidget->show(); | |
} | |
} else { | |
QWidget::keyPressEvent(e); | |
} | |
} | |
void CentralWidget::findNext() | |
{ | |
TRACE_OBJ | |
find(findWidget->text(), true); | |
} | |
void CentralWidget::findPrevious() | |
{ | |
TRACE_OBJ | |
find(findWidget->text(), false); | |
} | |
void CentralWidget::find(const QString &ttf, bool forward) | |
{ | |
TRACE_OBJ | |
bool found = false; | |
#if defined(QT_NO_WEBKIT) | |
found = findInTextBrowser(ttf, forward); | |
#else | |
found = findInWebPage(ttf, forward); | |
#endif | |
if (!found && ttf.isEmpty()) | |
found = true; // the line edit is empty, no need to mark it red... | |
if (!findWidget->isVisible()) | |
findWidget->show(); | |
findWidget->setPalette(found); | |
} | |
bool CentralWidget::findInWebPage(const QString &ttf, bool forward) | |
{ | |
TRACE_OBJ | |
#if !defined(QT_NO_WEBKIT) | |
if (HelpViewer *viewer = currentHelpViewer()) { | |
bool found = false; | |
QWebPage::FindFlags options; | |
if (!ttf.isEmpty()) { | |
if (!forward) | |
options |= QWebPage::FindBackward; | |
if (findWidget->caseSensitive()) | |
options |= QWebPage::FindCaseSensitively; | |
found = viewer->findText(ttf, options); | |
findWidget->setTextWrappedVisible(false); | |
if (!found) { | |
options |= QWebPage::FindWrapsAroundDocument; | |
found = viewer->findText(ttf, options); | |
if (found) | |
findWidget->setTextWrappedVisible(true); | |
} | |
} | |
// force highlighting of all other matches, also when empty (clear) | |
options = QWebPage::HighlightAllOccurrences; | |
if (findWidget->caseSensitive()) | |
options |= QWebPage::FindCaseSensitively; | |
viewer->findText(QLatin1String(""), options); | |
viewer->findText(ttf, options); | |
return found; | |
} | |
// this needs to stay, case for active search results page | |
return findInTextBrowser(ttf, forward); | |
#else | |
Q_UNUSED(ttf); | |
Q_UNUSED(forward); | |
#endif | |
return false; | |
} | |
bool CentralWidget::findInTextBrowser(const QString &ttf, bool forward) | |
{ | |
TRACE_OBJ | |
QTextBrowser *browser = qobject_cast<QTextBrowser*>(currentHelpViewer()); | |
if (tabWidget->currentWidget() == m_searchWidget) | |
browser = qFindChild<QTextBrowser*>(m_searchWidget); | |
if (!browser || ttf.isEmpty()) | |
return false; | |
QTextDocument *doc = browser->document(); | |
QTextCursor cursor = browser->textCursor(); | |
if (!doc || cursor.isNull()) | |
return false; | |
QTextDocument::FindFlags options; | |
if (cursor.hasSelection()) { | |
cursor.setPosition(forward ? cursor.position() : cursor.anchor(), | |
QTextCursor::MoveAnchor); | |
} | |
if (!forward) | |
options |= QTextDocument::FindBackward; | |
if (findWidget->caseSensitive()) | |
options |= QTextDocument::FindCaseSensitively; | |
findWidget->setTextWrappedVisible(false); | |
bool found = true; | |
QTextCursor newCursor = doc->find(ttf, cursor, options); | |
if (newCursor.isNull()) { | |
QTextCursor ac(doc); | |
ac.movePosition(options & QTextDocument::FindBackward | |
? QTextCursor::End : QTextCursor::Start); | |
newCursor = doc->find(ttf, ac, options); | |
if (newCursor.isNull()) { | |
found = false; | |
newCursor = cursor; | |
} else { | |
findWidget->setTextWrappedVisible(true); | |
} | |
} | |
browser->setTextCursor(newCursor); | |
return found; | |
} | |
void CentralWidget::updateBrowserFont() | |
{ | |
TRACE_OBJ | |
const bool searchAttached = searchWidgetAttached(); | |
if (searchAttached) { | |
HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); | |
m_searchWidget->setFont(helpEngine.usesBrowserFont() | |
? helpEngine.browserFont() : qApp->font()); | |
} | |
const int count = tabWidget->count(); | |
if (HelpViewer* viewer = viewerAt(count - 1)) { | |
const QFont &font = viewer->viewerFont(); | |
for (int i = searchAttached ? 1 : 0; i < count; ++i) | |
viewerAt(i)->setViewerFont(font); | |
} | |
} | |
bool CentralWidget::searchWidgetAttached() const | |
{ | |
TRACE_OBJ | |
return m_searchWidget && m_searchWidget->isAttached(); | |
} | |
void CentralWidget::createSearchWidget(QHelpSearchEngine *searchEngine) | |
{ | |
TRACE_OBJ | |
if (m_searchWidget) | |
return; | |
m_searchWidget = new SearchWidget(searchEngine, this); | |
connect(m_searchWidget, SIGNAL(requestShowLink(QUrl)), this, | |
SLOT(setSourceFromSearch(QUrl))); | |
connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(QUrl)), this, | |
SLOT(setSourceFromSearchInNewTab(QUrl))); | |
HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); | |
m_searchWidget->setFont(!helpEngine.usesBrowserFont() ? qApp->font() | |
: helpEngine.browserFont()); | |
} | |
void CentralWidget::activateSearchWidget(bool updateLastTabPage) | |
{ | |
TRACE_OBJ | |
if (!m_searchWidget) | |
createSearchWidget(HelpEngineWrapper::instance().searchEngine()); | |
if (!m_searchWidget->isAttached()) { | |
tabWidget->insertTab(0, m_searchWidget, tr("Search")); | |
m_searchWidget->setAttached(true); | |
if (updateLastTabPage) | |
lastTabPage++; | |
} | |
tabWidget->setCurrentWidget(m_searchWidget); | |
m_searchWidget->setFocus(); | |
} | |
void CentralWidget::removeSearchWidget() | |
{ | |
TRACE_OBJ | |
if (searchWidgetAttached()) { | |
tabWidget->removeTab(0); | |
m_searchWidget->setAttached(false); | |
} | |
} | |
int CentralWidget::availableHelpViewer() const | |
{ | |
TRACE_OBJ | |
int count = tabWidget->count(); | |
if (searchWidgetAttached()) | |
count--; | |
return count; | |
} | |
bool CentralWidget::enableTabCloseAction() const | |
{ | |
TRACE_OBJ | |
int minTabCount = 1; | |
if (searchWidgetAttached()) | |
minTabCount = 2; | |
return (tabWidget->count() > minTabCount); | |
} | |
QString CentralWidget::quoteTabTitle(const QString &title) const | |
{ | |
TRACE_OBJ | |
QString s = title; | |
return s.replace(QLatin1Char('&'), QLatin1String("&&")); | |
} | |
void | |
CentralWidget::setSourceFromSearch(const QUrl &url) | |
{ | |
TRACE_OBJ | |
setSource(url); | |
#if defined(QT_NO_WEBKIT) | |
highlightSearchTerms(); | |
#else | |
connect(currentHelpViewer(), SIGNAL(loadFinished(bool)), this, | |
SLOT(highlightSearchTerms())); | |
#endif | |
} | |
void | |
CentralWidget::setSourceFromSearchInNewTab(const QUrl &url) | |
{ | |
TRACE_OBJ | |
setSourceInNewTab(url); | |
#if defined(QT_NO_WEBKIT) | |
highlightSearchTerms(); | |
#else | |
connect(currentHelpViewer(), SIGNAL(loadFinished(bool)), this, | |
SLOT(highlightSearchTerms())); | |
#endif | |
} | |
void | |
CentralWidget::highlightSearchTerms() | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = currentHelpViewer(); | |
if (!viewer) | |
return; | |
QHelpSearchEngine *searchEngine = | |
HelpEngineWrapper::instance().searchEngine(); | |
QList<QHelpSearchQuery> queryList = searchEngine->query(); | |
QStringList terms; | |
foreach (const QHelpSearchQuery &query, queryList) { | |
switch (query.fieldName) { | |
default: break; | |
case QHelpSearchQuery::ALL: { | |
case QHelpSearchQuery::PHRASE: | |
case QHelpSearchQuery::DEFAULT: | |
case QHelpSearchQuery::ATLEAST: | |
foreach (QString term, query.wordList) | |
terms.append(term.remove(QLatin1Char('"'))); | |
} | |
} | |
} | |
#if defined(QT_NO_WEBKIT) | |
viewer->viewport()->setUpdatesEnabled(false); | |
QTextCharFormat marker; | |
marker.setForeground(Qt::red); | |
QTextCursor firstHit; | |
QTextCursor c = viewer->textCursor(); | |
c.beginEditBlock(); | |
foreach (const QString& term, terms) { | |
c.movePosition(QTextCursor::Start); | |
viewer->setTextCursor(c); | |
while (viewer->find(term, QTextDocument::FindWholeWords)) { | |
QTextCursor hit = viewer->textCursor(); | |
if (firstHit.isNull() || hit.position() < firstHit.position()) | |
firstHit = hit; | |
hit.mergeCharFormat(marker); | |
} | |
} | |
if (firstHit.isNull()) { | |
firstHit = viewer->textCursor(); | |
firstHit.movePosition(QTextCursor::Start); | |
} | |
firstHit.clearSelection(); | |
c.endEditBlock(); | |
viewer->setTextCursor(firstHit); | |
viewer->viewport()->setUpdatesEnabled(true); | |
#else | |
viewer->findText("", QWebPage::HighlightAllOccurrences); | |
// clears existing selections | |
foreach (const QString& term, terms) | |
viewer->findText(term, QWebPage::HighlightAllOccurrences); | |
disconnect(viewer, SIGNAL(loadFinished(bool)), this, | |
SLOT(highlightSearchTerms())); | |
#endif | |
} | |
void CentralWidget::closeOrReloadTabs(const QList<int> &indices, bool tryReload) | |
{ | |
TRACE_OBJ | |
QList<int> sortedIndices = indices; | |
qSort(sortedIndices); | |
for (int i = sortedIndices.count(); --i >= 0;) { | |
const int tab = sortedIndices.at(i); | |
bool close = true; | |
if (tryReload) { | |
HelpViewer *viewer = | |
qobject_cast<HelpViewer*>(tabWidget->widget(tab)); | |
if (HelpEngineWrapper::instance().findFile(viewer->source()).isValid()) { | |
viewer->reload(); | |
close = false; | |
} | |
} | |
if (close) | |
closeTabAt(tab); | |
} | |
if (availableHelpViewer() == 0) | |
setSource(QUrl(QLatin1String("about:blank"))); | |
} | |
void CentralWidget::closeTabAt(int index) | |
{ | |
TRACE_OBJ | |
HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(index)); | |
tabWidget->removeTab(index); | |
QTimer::singleShot(0, viewer, SLOT(deleteLater())); | |
} | |
QMap<int, QString> CentralWidget::currentSourceFileList() const | |
{ | |
TRACE_OBJ | |
QMap<int, QString> sourceList; | |
for (int i = 0; i < tabWidget->count(); ++i) { | |
HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); | |
if (viewer && viewer->source().isValid()) | |
sourceList.insert(i, viewer->source().host()); | |
} | |
return sourceList; | |
} | |
QT_END_NAMESPACE |