Help: Cleanly separate different viewer backends

Removes the conditional compilation of the text browser vs web kit,
cleans up the code, and enables us to provide and test other backends
(WebEngine? Native?)
Adds runtime switch for testing the text browser variant by setting
environment variable QTC_FORCE_TEXTBROWSER (for now)

Change-Id: I8cc9bb373438d37c8194e433224314caa0b617bd
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
This commit is contained in:
Eike Ziller
2014-05-02 16:54:28 +02:00
parent 0ae6905525
commit 96e8f0bb7b
16 changed files with 1083 additions and 828 deletions

View File

@@ -132,7 +132,7 @@ void CentralWidget::addPage(HelpViewer *page, bool fromSearch)
connectSignals(page);
m_stackedWidget->addWidget(page);
if (fromSearch) {
connect(currentHelpViewer(), SIGNAL(loadFinished(bool)), this,
connect(currentHelpViewer(), SIGNAL(loadFinished()), this,
SLOT(highlightSearchTerms()));
}
}
@@ -255,7 +255,7 @@ void CentralWidget::setSource(const QUrl &url)
void CentralWidget::setSourceFromSearch(const QUrl &url)
{
if (HelpViewer* viewer = currentHelpViewer()) {
connect(viewer, SIGNAL(loadFinished(bool)), this,
connect(viewer, SIGNAL(loadFinished()), this,
SLOT(highlightSearchTerms()));
viewer->setSource(url);
viewer->setFocus(Qt::OtherFocusReason);
@@ -309,7 +309,7 @@ void CentralWidget::highlightSearchTerms()
foreach (const QString& term, terms)
viewer->findText(term, 0, false, true);
disconnect(viewer, SIGNAL(loadFinished(bool)), this,
disconnect(viewer, SIGNAL(loadFinished()), this,
SLOT(highlightSearchTerms()));
}
}
@@ -347,7 +347,6 @@ void CentralWidget::connectSignals(HelpViewer *page)
connect(page, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
connect(page, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
connect(page, SIGNAL(printRequested()), this, SLOT(print()));
connect(page, SIGNAL(openFindToolBar()), this, SIGNAL(openFindToolBar()));
}
bool CentralWidget::eventFilter(QObject *object, QEvent *e)
@@ -359,10 +358,8 @@ bool CentralWidget::eventFilter(QObject *object, QEvent *e)
QKeyEvent *keyEvent = static_cast<QKeyEvent*> (e);
if (viewer == object && keyEvent->key() == Qt::Key_Backspace) {
if (viewer->isBackwardAvailable()) {
#if !defined(QT_NO_WEBKIT)
// this helps in case there is an html <input> field
if (!viewer->hasFocus())
#endif
viewer->backward();
}
}

View File

@@ -94,7 +94,6 @@ protected:
void focusInEvent(QFocusEvent *event);
signals:
void openFindToolBar();
void sourceChanged(const QUrl &url);
void forwardAvailable(bool available);
void backwardAvailable(bool available);

View File

@@ -61,6 +61,7 @@ GeneralSettingsPage::GeneralSettingsPage()
: m_ui(0)
{
m_font = qApp->font();
// TODO remove QT_NO_WEBKIT
#if !defined(QT_NO_WEBKIT)
QWebSettings* webSettings = QWebSettings::globalSettings();
m_font.setPointSize(webSettings->fontSize(QWebSettings::DefaultFontSize));

View File

@@ -28,7 +28,6 @@ HEADERS += \
helpmode.h \
helpplugin.h \
helpviewer.h \
helpviewer_p.h \
openpagesmanager.h \
openpagesmodel.h \
openpagesswitcher.h \
@@ -37,7 +36,9 @@ HEADERS += \
searchwidget.h \
xbelsupport.h \
externalhelpwindow.h \
searchtaskhandler.h
searchtaskhandler.h \
qtwebkithelpviewer.h \
textbrowserhelpviewer.h
SOURCES += \
centralwidget.cpp \
@@ -50,8 +51,6 @@ SOURCES += \
helpmode.cpp \
helpplugin.cpp \
helpviewer.cpp \
helpviewer_qtb.cpp \
helpviewer_qwv.cpp \
openpagesmanager.cpp \
openpagesmodel.cpp \
openpagesswitcher.cpp \
@@ -60,7 +59,9 @@ SOURCES += \
searchwidget.cpp \
xbelsupport.cpp \
externalhelpwindow.cpp \
searchtaskhandler.cpp
searchtaskhandler.cpp \
qtwebkithelpviewer.cpp \
textbrowserhelpviewer.cpp
FORMS += docsettingspage.ui \
filtersettingspage.ui \

View File

@@ -51,17 +51,17 @@ QtcPlugin {
"helpindexfilter.cpp", "helpindexfilter.h",
"helpmode.cpp", "helpmode.h",
"helpplugin.cpp", "helpplugin.h",
"helpviewer.cpp", "helpviewer.h", "helpviewer_p.h",
"helpviewer_qtb.cpp",
"helpviewer_qwv.cpp",
"helpviewer.cpp", "helpviewer.h",
"localhelpmanager.cpp", "localhelpmanager.h",
"openpagesmanager.cpp", "openpagesmanager.h",
"openpagesmodel.cpp", "openpagesmodel.h",
"openpagesswitcher.cpp", "openpagesswitcher.h",
"openpageswidget.cpp", "openpageswidget.h",
"qtwebkithelpviewer.cpp", "qtwebkithelpviewer.h",
"remotehelpfilter.cpp", "remotehelpfilter.h", "remotehelpfilter.ui",
"searchtaskhandler.cpp", "searchtaskhandler.h",
"searchwidget.cpp", "searchwidget.h",
"textbrowserhelpviewer.cpp", "textbrowserhelpviewer.h",
"xbelsupport.cpp", "xbelsupport.h",
]
}

View File

@@ -42,9 +42,11 @@
#include "localhelpmanager.h"
#include "openpagesmanager.h"
#include "openpagesmodel.h"
#include "qtwebkithelpviewer.h"
#include "remotehelpfilter.h"
#include "searchwidget.h"
#include "searchtaskhandler.h"
#include "textbrowserhelpviewer.h"
#include <bookmarkmanager.h>
#include <contentwindow.h>
@@ -88,13 +90,6 @@
#include <QHelpEngine>
#if !defined(QT_NO_WEBKIT)
#include <QWebElement>
#include <QWebElementCollection>
#include <QWebFrame>
#include <QWebHistory>
#endif
using namespace Help::Internal;
const char SB_INDEX[] = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index");
@@ -200,9 +195,6 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
m_centralWidget = new Help::Internal::CentralWidget();
connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this,
SLOT(updateSideBarSource(QUrl)));
connect(m_centralWidget, SIGNAL(openFindToolBar()), this,
SLOT(openFindToolBar()));
// Add Home, Previous and Next actions (used in the toolbar)
QAction *action = new QAction(QIcon(QLatin1String(IMAGEPATH "home.png")),
tr("Home"), this);
@@ -564,12 +556,8 @@ void HelpPlugin::createRightPaneContextViewer()
layout->addWidget(toolButton(close));
m_rightPaneSideBarWidget = new QWidget;
m_helpViewerForSideBar = new HelpViewer(qreal(0.0));
connect(m_helpViewerForSideBar, SIGNAL(openFindToolBar()), this,
SLOT(openFindToolBar()));
#if !defined(QT_NO_WEBKIT)
m_helpViewerForSideBar->pageAction(QWebPage::OpenLinkInNewWindow)->setVisible(false);
#endif
m_helpViewerForSideBar = createHelpViewer(qreal(0.0));
m_helpViewerForSideBar->setOpenInNewWindowActionVisible(false);
QVBoxLayout *rightPaneLayout = new QVBoxLayout(m_rightPaneSideBarWidget);
rightPaneLayout->setMargin(0);
@@ -648,6 +636,18 @@ void HelpPlugin::resetRightPaneScale()
m_helpViewerForSideBar->resetScale();
}
HelpViewer *HelpPlugin::createHelpViewer(qreal zoom)
{
#ifndef QT_NO_WEBKIT
if (qgetenv("QTC_FORCE_TEXTBROWSER").isEmpty())
return new QtWebKitHelpViewer(zoom);
else
return new TextBrowserHelpViewer(zoom);
#else
return new TextBrowserHelpViewer(zoom);
#endif
}
void HelpPlugin::activateHelpMode()
{
if (contextHelpOption() != Help::Constants::ExternalHelpAlways)
@@ -910,9 +910,7 @@ void HelpPlugin::activateContext()
const QUrl &oldSource = viewer->source();
if (source != oldSource) {
#if !defined(QT_NO_WEBKIT)
viewer->stop();
#endif
const QString &fragment = source.fragment();
const bool isQtRefDoc = source.authority().startsWith(qtRefDoc);
if (isQtRefDoc) {
@@ -920,7 +918,7 @@ void HelpPlugin::activateContext()
m_idFromContext = fragment;
if (!m_idFromContext.isEmpty()) {
connect(viewer, SIGNAL(loadFinished(bool)), this,
connect(viewer, SIGNAL(loadFinished()), this,
SLOT(highlightSearchTerms()));
}
}
@@ -934,9 +932,7 @@ void HelpPlugin::activateContext()
}
}
} else {
#if !defined(QT_NO_WEBKIT)
viewer->page()->mainFrame()->scrollToAnchor(source.fragment());
#endif
viewer->scrollToAnchor(source.fragment());
}
viewer->setFocus();
}
@@ -1089,35 +1085,9 @@ void HelpPlugin::addBookmark()
void HelpPlugin::highlightSearchTerms()
{
if (HelpViewer* viewer = viewerForContextMode()) {
disconnect(viewer, SIGNAL(loadFinished(bool)), this,
disconnect(viewer, SIGNAL(loadFinished()), this,
SLOT(highlightSearchTerms()));
#if !defined(QT_NO_WEBKIT)
const QWebElement &document = viewer->page()->mainFrame()->documentElement();
const QWebElementCollection &collection = document.findAll(QLatin1String("h3.fn a"));
const QLatin1String property("background-color");
foreach (const QWebElement &element, collection) {
const QString &name = element.attribute(QLatin1String("name"));
if (name.isEmpty())
continue;
if (m_oldAttrValue == name
|| name.startsWith(m_oldAttrValue + QLatin1Char('-'))) {
QWebElement parent = element.parent();
parent.setStyleProperty(property, m_styleProperty);
}
if (m_idFromContext == name
|| name.startsWith(m_idFromContext + QLatin1Char('-'))) {
QWebElement parent = element.parent();
m_styleProperty = parent.styleProperty(property,
QWebElement::ComputedStyle);
parent.setStyleProperty(property, QLatin1String("yellow"));
}
}
m_oldAttrValue = m_idFromContext;
#endif
viewer->highlightId(m_idFromContext);
}
}
@@ -1152,54 +1122,16 @@ void HelpPlugin::handleHelpRequest(const QUrl &url)
void HelpPlugin::slotAboutToShowBackMenu()
{
#if !defined(QT_NO_WEBKIT)
m_backMenu->clear();
if (QWebHistory *history = viewerForContextMode()->history()) {
const int currentItemIndex = history->currentItemIndex();
QList<QWebHistoryItem> items = history->backItems(history->count());
for (int i = items.count() - 1; i >= 0; --i) {
QAction *action = new QAction(this);
action->setText(items.at(i).title());
action->setData(-1 * (currentItemIndex - i));
m_backMenu->addAction(action);
}
}
#endif
if (HelpViewer *viewer = m_centralWidget->currentHelpViewer())
viewer->addBackHistoryItems(m_backMenu);
}
void HelpPlugin::slotAboutToShowNextMenu()
{
#if !defined(QT_NO_WEBKIT)
m_nextMenu->clear();
if (QWebHistory *history = viewerForContextMode()->history()) {
const int count = history->count();
QList<QWebHistoryItem> items = history->forwardItems(count);
for (int i = 0; i < items.count(); ++i) {
QAction *action = new QAction(this);
action->setData(count - i);
action->setText(items.at(i).title());
m_nextMenu->addAction(action);
}
}
#endif
}
void HelpPlugin::slotOpenActionUrl(QAction *action)
{
#if !defined(QT_NO_WEBKIT)
if (HelpViewer* viewer = viewerForContextMode()) {
const int offset = action->data().toInt();
QWebHistory *history = viewer->history();
if (offset > 0) {
history->goToItem(history->forwardItems(history->count()
- offset + 1).back()); // forward
} else if (offset < 0) {
history->goToItem(history->backItems(-1 * offset).first()); // back
}
}
#else
Q_UNUSED(action)
#endif
if (HelpViewer *viewer = m_centralWidget->currentHelpViewer())
viewer->addForwardHistoryItems(m_nextMenu);
}
void HelpPlugin::slotOpenSupportPage()
@@ -1212,12 +1144,6 @@ void HelpPlugin::slotReportBug()
QDesktopServices::openUrl(QUrl(QLatin1String("https://bugreports.qt-project.org")));
}
void HelpPlugin::openFindToolBar()
{
if (FindPlugin::instance())
FindPlugin::instance()->openFindToolBar(FindPlugin::FindForwardDirection);
}
void HelpPlugin::onSideBarVisibilityChanged()
{
m_isSidebarVisible = m_sideBar->isVisible();
@@ -1273,30 +1199,20 @@ void HelpPlugin::connectExternalHelpWindow()
void HelpPlugin::setupNavigationMenus(QAction *back, QAction *next, QWidget *parent)
{
#if !defined(QT_NO_WEBKIT)
if (!m_backMenu) {
m_backMenu = new QMenu(parent);
connect(m_backMenu, SIGNAL(aboutToShow()), this,
SLOT(slotAboutToShowBackMenu()));
connect(m_backMenu, SIGNAL(triggered(QAction*)), this,
SLOT(slotOpenActionUrl(QAction*)));
}
if (!m_nextMenu) {
m_nextMenu = new QMenu(parent);
connect(m_nextMenu, SIGNAL(aboutToShow()), this,
SLOT(slotAboutToShowNextMenu()));
connect(m_nextMenu, SIGNAL(triggered(QAction*)), this,
SLOT(slotOpenActionUrl(QAction*)));
}
back->setMenu(m_backMenu);
next->setMenu(m_nextMenu);
#else
Q_UNUSED(back)
Q_UNUSED(next)
Q_UNUSED(parent)
#endif
}
Q_EXPORT_PLUGIN(HelpPlugin)

View File

@@ -78,6 +78,8 @@ public:
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
static HelpViewer *createHelpViewer(qreal zoom);
private slots:
void unregisterOldQtCreatorDocumentation();
@@ -114,11 +116,9 @@ private slots:
void slotAboutToShowBackMenu();
void slotAboutToShowNextMenu();
void slotOpenActionUrl(QAction *action);
void slotOpenSupportPage();
void slotReportBug();
void openFindToolBar();
void onSideBarVisibilityChanged();
void scaleRightPaneUp();
@@ -166,8 +166,6 @@ private:
QToolButton *m_closeButton;
QString m_oldAttrValue;
QString m_styleProperty;
QString m_idFromContext;
Core::IMode* m_oldMode;

View File

@@ -85,6 +85,11 @@ struct ExtensionMap {
{ 0, 0 }
};
HelpViewer::HelpViewer(QWidget *parent)
: QWidget(parent)
{
}
bool HelpViewer::isLocalUrl(const QUrl &url)
{
return url.scheme() == QLatin1String("about") // "No documenation available"
@@ -155,11 +160,11 @@ void HelpViewer::slotLoadStarted()
qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
}
void HelpViewer::slotLoadFinished(bool ok)
void HelpViewer::slotLoadFinished()
{
Q_UNUSED(ok)
emit sourceChanged(source());
qApp->restoreOverrideCursor();
emit sourceChanged(source());
emit loadFinished();
}
bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event)

View File

@@ -30,60 +30,56 @@
#ifndef HELPVIEWER_H
#define HELPVIEWER_H
#include <coreplugin/find/ifindsupport.h>
#include <coreplugin/find/textfindconstants.h>
#include <qglobal.h>
#include <QFont>
#include <QMenu>
#include <QPrinter>
#include <QString>
#include <QUrl>
#include <QVariant>
#include <QAction>
#include <QFont>
#if defined(QT_NO_WEBKIT)
#include <QTextBrowser>
#else
#include <QWebPage>
#include <QWebView>
#endif
#include <QWidget>
namespace Help {
namespace Internal {
#if !defined(QT_NO_WEBKIT)
class HelpViewer : public QWebView
#else
class HelpViewer : public QTextBrowser
#endif
class HelpViewer : public QWidget
{
Q_OBJECT
class HelpViewerPrivate;
public:
explicit HelpViewer(qreal zoom, QWidget *parent = 0);
~HelpViewer();
explicit HelpViewer(QWidget *parent = 0);
~HelpViewer() { }
QFont viewerFont() const;
void setViewerFont(const QFont &font);
virtual QFont viewerFont() const = 0;
virtual void setViewerFont(const QFont &font) = 0;
void scaleUp();
void scaleDown();
virtual void scaleUp() = 0;
virtual void scaleDown() = 0;
virtual void resetScale() = 0;
void resetScale();
qreal scale() const;
virtual qreal scale() const = 0;
QString title() const;
void setTitle(const QString &title);
virtual QString title() const = 0;
virtual void setTitle(const QString &title) = 0;
QUrl source() const;
void setSource(const QUrl &url);
virtual QUrl source() const = 0;
virtual void setSource(const QUrl &url) = 0;
virtual void scrollToAnchor(const QString &anchor) = 0;
virtual void highlightId(const QString &id) { Q_UNUSED(id) }
QString selectedText() const;
bool isForwardAvailable() const;
bool isBackwardAvailable() const;
virtual void setHtml(const QString &html) = 0;
bool findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped = 0);
virtual QString selectedText() const = 0;
virtual bool isForwardAvailable() const = 0;
virtual bool isBackwardAvailable() const = 0;
virtual void addBackHistoryItems(QMenu *backMenu) = 0;
virtual void addForwardHistoryItems(QMenu *forwardMenu) = 0;
virtual void setOpenInNewWindowActionVisible(bool visible) = 0;
virtual bool findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped = 0) = 0;
bool handleForwardBackwardMouseButtons(QMouseEvent *e);
static bool isLocalUrl(const QUrl &url);
static bool canOpenPage(const QString &url);
@@ -91,77 +87,27 @@ public:
static bool launchWithExternalApp(const QUrl &url);
public slots:
void copy();
void home();
void stop();
void forward();
void backward();
virtual void copy() = 0;
virtual void stop() = 0;
virtual void forward() = 0;
virtual void backward() = 0;
virtual void print(QPrinter *printer) = 0;
signals:
void sourceChanged(const QUrl &);
void titleChanged();
void printRequested();
void openFindToolBar();
void forwardAvailable(bool);
void backwardAvailable(bool);
void loadFinished();
#if !defined(QT_NO_WEBKIT)
void sourceChanged(const QUrl &);
void forwardAvailable(bool enabled);
void backwardAvailable(bool enabled);
#else
void loadFinished(bool finished);
#endif
protected:
void keyPressEvent(QKeyEvent *e);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private slots:
void actionChanged();
protected slots:
void slotLoadStarted();
void slotLoadFinished(bool ok);
#if !defined(QT_NO_WEBKIT)
void slotNetworkReplyFinished(QNetworkReply *reply);
#endif
private:
bool eventFilter(QObject *obj, QEvent *event);
void contextMenuEvent(QContextMenuEvent *event);
QVariant loadResource(int type, const QUrl &name);
bool handleForwardBackwardMouseButtons(QMouseEvent *e);
private:
HelpViewerPrivate *d;
void slotLoadFinished();
};
#ifndef QT_NO_WEBKIT
class HelpPage : public QWebPage
{
Q_OBJECT
public:
HelpPage(QObject *parent);
protected:
virtual QWebPage *createWindow(QWebPage::WebWindowType);
virtual void triggerAction(WebAction action, bool checked = false);
virtual bool acceptNavigationRequest(QWebFrame *frame,
const QNetworkRequest &request, NavigationType type);
private slots:
void onHandleUnsupportedContent(QNetworkReply *reply);
private:
QUrl m_loadingUrl;
bool closeNewTabIfNeeded;
friend class Help::Internal::HelpViewer;
Qt::MouseButtons m_pressedButtons;
Qt::KeyboardModifiers m_keyboardModifiers;
};
#endif // QT_NO_WEBKIT
} // namespace Internal
} // namespace Help

View File

@@ -1,101 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef HELPVIEWERPRIVATE_H
#define HELPVIEWERPRIVATE_H
#include "centralwidget.h"
#include "helpviewer.h"
#include "openpagesmanager.h"
#include <QObject>
#include <QTextBrowser>
namespace Help {
namespace Internal {
class HelpViewer::HelpViewerPrivate : public QObject
{
Q_OBJECT
public:
HelpViewerPrivate(int zoom)
: zoomCount(zoom)
, forceFont(false)
, lastAnchor(QString())
{}
bool hasAnchorAt(QTextBrowser *browser, const QPoint& pos)
{
lastAnchor = browser->anchorAt(pos);
if (lastAnchor.isEmpty())
return false;
lastAnchor = browser->source().resolved(lastAnchor).toString();
if (lastAnchor.at(0) == QLatin1Char('#')) {
QString src = browser->source().toString();
int hsh = src.indexOf(QLatin1Char('#'));
lastAnchor = (hsh >= 0 ? src.left(hsh) : src) + lastAnchor;
}
return true;
}
void openLink(bool newPage)
{
if (lastAnchor.isEmpty())
return;
if (newPage)
OpenPagesManager::instance().createPage(lastAnchor);
else
CentralWidget::instance()->setSource(lastAnchor);
lastAnchor.clear();
}
public slots:
void openLink()
{
openLink(false);
}
void openLinkInNewPage()
{
openLink(true);
}
public:
int zoomCount;
bool forceFont;
QString lastAnchor;
};
} // namespace Help
} // namespace Internal
#endif // HELPVIEWERPRIVATE_H

View File

@@ -1,379 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "helpviewer.h"
#if defined(QT_NO_WEBKIT)
#include "helpconstants.h"
#include "helpviewer_p.h"
#include "localhelpmanager.h"
#include <utils/hostosinfo.h>
#include <QApplication>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QKeyEvent>
#include <QMenu>
#include <QHelpEngine>
using namespace Help;
using namespace Help::Internal;
// -- HelpViewer
HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
: QTextBrowser(parent)
, d(new HelpViewerPrivate(zoom))
{
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);
installEventFilter(this);
document()->setDocumentMargin(8);
QFont font = viewerFont();
font.setPointSize(int(font.pointSize() + zoom));
setViewerFont(font);
connect(this, SIGNAL(sourceChanged(QUrl)), this, SIGNAL(titleChanged()));
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
}
HelpViewer::~HelpViewer()
{
delete d;
}
QFont HelpViewer::viewerFont() const
{
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
return qvariant_cast<QFont>(engine.customValue(QLatin1String("font"),
qApp->font()));
}
void HelpViewer::setViewerFont(const QFont &newFont)
{
if (font() != newFont) {
d->forceFont = true;
setFont(newFont);
d->forceFont = false;
}
}
void HelpViewer::scaleUp()
{
if (d->zoomCount < 10) {
d->zoomCount++;
d->forceFont = true;
zoomIn();
d->forceFont = false;
}
}
void HelpViewer::scaleDown()
{
if (d->zoomCount > -5) {
d->zoomCount--;
d->forceFont = true;
zoomOut();
d->forceFont = false;
}
}
void HelpViewer::resetScale()
{
if (d->zoomCount != 0) {
d->forceFont = true;
zoomOut(d->zoomCount);
d->forceFont = false;
}
d->zoomCount = 0;
}
qreal HelpViewer::scale() const
{
return d->zoomCount;
}
QString HelpViewer::title() const
{
return documentTitle();
}
void HelpViewer::setTitle(const QString &title)
{
setDocumentTitle(title);
}
QUrl HelpViewer::source() const
{
return QTextBrowser::source();
}
void HelpViewer::setSource(const QUrl &url)
{
const QString &string = url.toString();
if (url.isValid() && string != QLatin1String("help")) {
if (launchWithExternalApp(url))
return;
QUrl resolvedUrl;
if (url.scheme() == QLatin1String("http"))
resolvedUrl = url;
if (!resolvedUrl.isValid()) {
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
resolvedUrl = engine.findFile(url);
}
if (resolvedUrl.isValid()) {
QTextBrowser::setSource(resolvedUrl);
emit loadFinished(true);
return;
}
}
QTextBrowser::setSource(url);
setHtml(string == Help::Constants::AboutBlank
? HelpViewer::tr("<title>about:blank</title>")
: HelpViewer::tr("<html><head><meta http-equiv=\""
"content-type\" content=\"text/html; charset=UTF-8\"><title>Error 404...</title>"
"</head><body><div align=\"center\"><br/><br/><h1>The page could not be found</h1>"
"<br/><h3>\"%1\"</h3></div></body></html>")
.arg(url.toString()));
emit loadFinished(true);
}
QString HelpViewer::selectedText() const
{
return textCursor().selectedText();
}
bool HelpViewer::isForwardAvailable() const
{
return QTextBrowser::isForwardAvailable();
}
bool HelpViewer::isBackwardAvailable() const
{
return QTextBrowser::isBackwardAvailable();
}
bool HelpViewer::findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped)
{
if (wrapped)
*wrapped = false;
QTextDocument *doc = document();
QTextCursor cursor = textCursor();
if (!doc || cursor.isNull())
return false;
const int position = cursor.selectionStart();
if (incremental)
cursor.setPosition(position);
QTextDocument::FindFlags f = Core::textDocumentFlagsForFindFlags(flags);
QTextCursor found = doc->find(text, cursor, f);
if (found.isNull()) {
if ((flags & Core::FindBackward) == 0)
cursor.movePosition(QTextCursor::Start);
else
cursor.movePosition(QTextCursor::End);
found = doc->find(text, cursor, f);
if (!found.isNull() && wrapped)
*wrapped = true;
}
if (fromSearch) {
cursor.beginEditBlock();
viewport()->setUpdatesEnabled(false);
QTextCharFormat marker;
marker.setForeground(Qt::red);
cursor.movePosition(QTextCursor::Start);
setTextCursor(cursor);
while (find(text)) {
QTextCursor hit = textCursor();
hit.mergeCharFormat(marker);
}
viewport()->setUpdatesEnabled(true);
cursor.endEditBlock();
}
bool cursorIsNull = found.isNull();
if (cursorIsNull) {
found = textCursor();
found.setPosition(position);
}
setTextCursor(found);
return !cursorIsNull;
}
// -- public slots
void HelpViewer::copy()
{
QTextBrowser::copy();
}
void HelpViewer::stop()
{
}
void HelpViewer::forward()
{
QTextBrowser::forward();
}
void HelpViewer::backward()
{
QTextBrowser::backward();
}
// -- protected
void HelpViewer::keyPressEvent(QKeyEvent *e)
{
if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
|| (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
e->text(), e->isAutoRepeat(), e->count());
e = event;
}
QTextBrowser::keyPressEvent(e);
}
void HelpViewer::wheelEvent(QWheelEvent *e)
{
if (e->modifiers() == Qt::ControlModifier) {
e->accept();
e->delta() > 0 ? scaleUp() : scaleDown();
} else {
QTextBrowser::wheelEvent(e);
}
}
void HelpViewer::mousePressEvent(QMouseEvent *e)
{
if (Utils::HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
return;
QTextBrowser::mousePressEvent(e);
}
void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
{
if (!Utils::HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
return;
bool controlPressed = e->modifiers() & Qt::ControlModifier;
if ((controlPressed && d->hasAnchorAt(this, e->pos())) ||
(e->button() == Qt::MidButton && d->hasAnchorAt(this, e->pos()))) {
d->openLinkInNewPage();
return;
}
QTextBrowser::mouseReleaseEvent(e);
}
// -- private slots
void HelpViewer::actionChanged()
{
// stub
}
// -- private
bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FontChange && !d->forceFont)
return true;
if (event->type() == QEvent::KeyPress) {
if (QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event)) {
if (keyEvent->key() == Qt::Key_Slash)
emit openFindToolBar();
}
}
return QTextBrowser::eventFilter(obj, event);
}
void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(QLatin1String(""), 0);
QUrl link;
QAction *copyAnchorAction = 0;
if (d->hasAnchorAt(this, event->pos())) {
link = anchorAt(event->pos());
if (link.isRelative())
link = source().resolved(link);
menu.addAction(tr("Open Link"), d, SLOT(openLink()));
menu.addAction(tr("Open Link as New Page"), d, SLOT(openLinkInNewPage()));
if (!link.isEmpty() && link.isValid())
copyAnchorAction = menu.addAction(tr("Copy Link"));
} else if (!selectedText().isEmpty()) {
menu.addAction(tr("Copy"), this, SLOT(copy()));
} else {
menu.addAction(tr("Reload"), this, SLOT(reload()));
}
if (copyAnchorAction == menu.exec(event->globalPos()))
QApplication::clipboard()->setText(link.toString());
}
QVariant HelpViewer::loadResource(int type, const QUrl &name)
{
QByteArray ba;
if (type < 4) {
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
ba = engine.fileData(name);
if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
QImage image;
image.loadFromData(ba, "svg");
if (!image.isNull())
return image;
}
}
return ba;
}
#endif // QT_NO_WEBKIT

View File

@@ -28,6 +28,7 @@
****************************************************************************/
#include "openpagesmodel.h"
#include "helpplugin.h"
#include "helpviewer.h"
#include <QUrl>
@@ -72,7 +73,7 @@ QVariant OpenPagesModel::data(const QModelIndex &index, int role) const
void OpenPagesModel::addPage(const QUrl &url, qreal zoom)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
HelpViewer *page = new HelpViewer(zoom);
HelpViewer *page = HelpPlugin::createHelpViewer(zoom);
connect(page, SIGNAL(titleChanged()), this, SLOT(handleTitleChanged()));
m_pages << page;
endInsertRows();

View File

@@ -27,23 +27,27 @@
**
****************************************************************************/
#include "helpviewer.h"
#include "qtwebkithelpviewer.h"
#if !defined(QT_NO_WEBKIT)
#include "centralwidget.h"
#include "helpconstants.h"
#include "localhelpmanager.h"
#include "openpagesmanager.h"
#include <coreplugin/find/findplugin.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QAction>
#include <QDebug>
#include <QFileInfo>
#include <QString>
#include <QStringBuilder>
#include <QTimer>
#include <QVBoxLayout>
#include <QWebElement>
#include <QWebFrame>
#include <QWebHistory>
#include <QApplication>
#include <QDesktopServices>
@@ -205,8 +209,10 @@ HelpPage::HelpPage(QObject *parent)
QWebPage *HelpPage::createWindow(QWebPage::WebWindowType)
{
HelpPage* newPage = static_cast<HelpPage*>(OpenPagesManager::instance()
.createPage()->page());
// TODO: ensure that we'll get a QtWebKitHelpViewer here
QtWebKitHelpViewer* viewer = static_cast<QtWebKitHelpViewer *>(OpenPagesManager::instance()
.createPage());
HelpPage *newPage = viewer->page();
newPage->closeNewTabIfNeeded = closeNewTabIfNeeded;
closeNewTabIfNeeded = false;
return newPage;
@@ -299,8 +305,9 @@ void HelpPage::onHandleUnsupportedContent(QNetworkReply *reply)
// -- HelpViewer
HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
: QWebView(parent)
QtWebKitHelpWidget::QtWebKitHelpWidget(qreal zoom, QtWebKitHelpViewer *parent)
: QWebView(parent),
m_parent(parent)
{
setAcceptDrops(false);
installEventFilter(this);
@@ -326,21 +333,129 @@ HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
SLOT(actionChanged()));
connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this,
SLOT(actionChanged()));
connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
connect(this, SIGNAL(loadStarted()), this, SLOT(slotLoadStarted()));
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged()));
connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested()));
setViewerFont(viewerFont());
setZoomFactor(zoom == 0.0 ? 1.0 : zoom);
}
HelpViewer::~HelpViewer()
QtWebKitHelpWidget::~QtWebKitHelpWidget()
{
}
QFont HelpViewer::viewerFont() const
void QtWebKitHelpWidget::scaleUp()
{
setZoomFactor(zoomFactor() + 0.1);
}
void QtWebKitHelpWidget::scaleDown()
{
setZoomFactor(qMax(qreal(0.0), zoomFactor() - qreal(0.1)));
}
// -- public slots
void QtWebKitHelpWidget::copy()
{
triggerPageAction(QWebPage::Copy);
}
// -- protected
void QtWebKitHelpWidget::keyPressEvent(QKeyEvent *e)
{
// TODO: remove this once we support multiple keysequences per command
if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) {
if (!selectedText().isEmpty())
copy();
}
QWebView::keyPressEvent(e);
}
void QtWebKitHelpWidget::wheelEvent(QWheelEvent *event)
{
if (event->modifiers()& Qt::ControlModifier) {
event->accept();
event->delta() > 0 ? scaleUp() : scaleDown();
} else {
QWebView::wheelEvent(event);
}
}
void QtWebKitHelpWidget::mousePressEvent(QMouseEvent *event)
{
if (Utils::HostOsInfo::isLinuxHost() && m_parent->handleForwardBackwardMouseButtons(event))
return;
if (HelpPage *currentPage = static_cast<HelpPage*>(page())) {
currentPage->m_pressedButtons = event->buttons();
currentPage->m_keyboardModifiers = event->modifiers();
}
QWebView::mousePressEvent(event);
}
void QtWebKitHelpWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (!Utils::HostOsInfo::isLinuxHost() && m_parent->handleForwardBackwardMouseButtons(event))
return;
QWebView::mouseReleaseEvent(event);
}
// -- private slots
void QtWebKitHelpWidget::actionChanged()
{
QAction *a = qobject_cast<QAction *>(sender());
if (a == pageAction(QWebPage::Back))
emit backwardAvailable(a->isEnabled());
else if (a == pageAction(QWebPage::Forward))
emit forwardAvailable(a->isEnabled());
}
void QtWebKitHelpWidget::slotNetworkReplyFinished(QNetworkReply *reply)
{
if (reply && reply->error() != QNetworkReply::NoError) {
load(QUrl(Help::Constants::AboutBlank));
setHtml(QString::fromLatin1(g_htmlPage).arg(g_percent1, reply->errorString(),
HelpViewer::tr("Error loading: %1").arg(reply->url().toString()), g_percent4, g_percent6, g_percent7,
QString()));
}
}
// -- private
bool QtWebKitHelpWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
if (QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event)) {
if (keyEvent->key() == Qt::Key_Slash)
Core::FindPlugin::instance()->openFindToolBar(Core::FindPlugin::FindForwardDirection);
}
}
return QWebView::eventFilter(obj, event);
}
QtWebKitHelpViewer::QtWebKitHelpViewer(qreal zoom, QWidget *parent)
: HelpViewer(parent),
m_webView(new QtWebKitHelpWidget(zoom, this))
{
QVBoxLayout *layout = new QVBoxLayout;
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_webView, 10);
connect(m_webView, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
connect(m_webView, SIGNAL(loadStarted()), this, SLOT(slotLoadStarted()));
connect(m_webView, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished()));
connect(m_webView, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged()));
connect(m_webView->page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested()));
connect(m_webView, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
connect(m_webView, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
setViewerFont(viewerFont());
}
QFont QtWebKitHelpViewer::viewerFont() const
{
QWebSettings* webSettings = QWebSettings::globalSettings();
QFont font(QApplication::font().family(),
@@ -350,69 +465,140 @@ QFont HelpViewer::viewerFont() const
font));
}
void HelpViewer::setViewerFont(const QFont &font)
void QtWebKitHelpViewer::setViewerFont(const QFont &font)
{
QWebSettings *webSettings = settings();
QWebSettings *webSettings = m_webView->settings();
webSettings->setFontFamily(QWebSettings::StandardFont, font.family());
webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize());
}
void HelpViewer::scaleUp()
void QtWebKitHelpViewer::scaleUp()
{
setZoomFactor(zoomFactor() + 0.1);
m_webView->scaleUp();
}
void HelpViewer::scaleDown()
void QtWebKitHelpViewer::scaleDown()
{
setZoomFactor(qMax(qreal(0.0), zoomFactor() - qreal(0.1)));
m_webView->scaleDown();
}
void HelpViewer::resetScale()
void QtWebKitHelpViewer::resetScale()
{
setZoomFactor(1.0);
m_webView->setZoomFactor(1.0);
}
qreal HelpViewer::scale() const
qreal QtWebKitHelpViewer::scale() const
{
return zoomFactor();
return m_webView->zoomFactor();
}
QString HelpViewer::title() const
QString QtWebKitHelpViewer::title() const
{
return QWebView::title();
return m_webView->title();
}
void HelpViewer::setTitle(const QString &title)
void QtWebKitHelpViewer::setTitle(const QString &title)
{
Q_UNUSED(title)
}
QUrl HelpViewer::source() const
QUrl QtWebKitHelpViewer::source() const
{
return url();
return m_webView->url();
}
void HelpViewer::setSource(const QUrl &url)
void QtWebKitHelpViewer::setSource(const QUrl &url)
{
load(url);
m_webView->load(url);
}
QString HelpViewer::selectedText() const
void QtWebKitHelpViewer::scrollToAnchor(const QString &anchor)
{
return QWebView::selectedText();
m_webView->page()->mainFrame()->scrollToAnchor(anchor);
}
bool HelpViewer::isForwardAvailable() const
void QtWebKitHelpViewer::highlightId(const QString &id)
{
return pageAction(QWebPage::Forward)->isEnabled();
const QWebElement &document = m_webView->page()->mainFrame()->documentElement();
const QWebElementCollection &collection = document.findAll(QLatin1String("h3.fn a"));
const QLatin1String property("background-color");
foreach (const QWebElement &element, collection) {
const QString &name = element.attribute(QLatin1String("name"));
if (name.isEmpty())
continue;
if (m_oldHighlightId == name
|| name.startsWith(m_oldHighlightId + QLatin1Char('-'))) {
QWebElement parent = element.parent();
parent.setStyleProperty(property, m_oldHighlightStyle);
}
bool HelpViewer::isBackwardAvailable() const
{
return pageAction(QWebPage::Back)->isEnabled();
if (id == name
|| name.startsWith(id + QLatin1Char('-'))) {
QWebElement parent = element.parent();
m_oldHighlightStyle = parent.styleProperty(property,
QWebElement::ComputedStyle);
parent.setStyleProperty(property, QLatin1String("yellow"));
}
}
m_oldHighlightId = id;
}
bool HelpViewer::findText(const QString &text, Core::FindFlags flags,
void QtWebKitHelpViewer::setHtml(const QString &html)
{
m_webView->setHtml(html);
}
QString QtWebKitHelpViewer::selectedText() const
{
return m_webView->selectedText();
}
bool QtWebKitHelpViewer::isForwardAvailable() const
{
return m_webView->pageAction(QWebPage::Forward)->isEnabled();
}
bool QtWebKitHelpViewer::isBackwardAvailable() const
{
return m_webView->pageAction(QWebPage::Back)->isEnabled();
}
void QtWebKitHelpViewer::addBackHistoryItems(QMenu *backMenu)
{
if (QWebHistory *history = m_webView->history()) {
QList<QWebHistoryItem> items = history->backItems(history->count());
for (int i = items.count() - 1; i >= 0; --i) {
QAction *action = new QAction(backMenu);
action->setText(items.at(i).title());
action->setData(i);
connect(action, SIGNAL(triggered()), this, SLOT(goToBackHistoryItem()));
backMenu->addAction(action);
}
}
}
void QtWebKitHelpViewer::addForwardHistoryItems(QMenu *forwardMenu)
{
if (QWebHistory *history = m_webView->history()) {
QList<QWebHistoryItem> items = history->forwardItems(history->count());
for (int i = 0; i < items.count(); ++i) {
QAction *action = new QAction(forwardMenu);
action->setText(items.at(i).title());
action->setData(i);
connect(action, SIGNAL(triggered()), this, SLOT(goToForwardHistoryItem()));
forwardMenu->addAction(action);
}
}
}
void QtWebKitHelpViewer::setOpenInNewWindowActionVisible(bool visible)
{
m_webView->pageAction(QWebPage::OpenLinkInNewWindow)->setVisible(visible);
}
bool QtWebKitHelpViewer::findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped)
{
Q_UNUSED(incremental);
@@ -425,121 +611,72 @@ bool HelpViewer::findText(const QString &text, Core::FindFlags flags,
if (flags & Core::FindCaseSensitively)
options |= QWebPage::FindCaseSensitively;
bool found = QWebView::findText(text, options);
bool found = m_webView->findText(text, options);
if (!found) {
options |= QWebPage::FindWrapsAroundDocument;
found = QWebView::findText(text, options);
found = m_webView->findText(text, options);
if (found && wrapped)
*wrapped = true;
}
options = QWebPage::HighlightAllOccurrences;
QWebView::findText(QLatin1String(""), options); // clear first
QWebView::findText(text, options); // force highlighting of all other matches
m_webView->findText(QLatin1String(""), options); // clear first
m_webView->findText(text, options); // force highlighting of all other matches
return found;
}
// -- public slots
void HelpViewer::copy()
HelpPage *QtWebKitHelpViewer::page() const
{
triggerPageAction(QWebPage::Copy);
return static_cast<HelpPage *>(m_webView->page());
}
void HelpViewer::stop()
void QtWebKitHelpViewer::copy()
{
triggerPageAction(QWebPage::Stop);
m_webView->copy();
}
void HelpViewer::forward()
void QtWebKitHelpViewer::stop()
{
QWebView::forward();
m_webView->triggerPageAction(QWebPage::Stop);
}
void HelpViewer::backward()
void QtWebKitHelpViewer::forward()
{
back();
m_webView->forward();
}
// -- protected
void HelpViewer::keyPressEvent(QKeyEvent *e)
void QtWebKitHelpViewer::backward()
{
// TODO: remove this once we support multiple keysequences per command
if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) {
if (!selectedText().isEmpty())
copy();
}
QWebView::keyPressEvent(e);
m_webView->back();
}
void HelpViewer::wheelEvent(QWheelEvent *event)
void QtWebKitHelpViewer::print(QPrinter *printer)
{
if (event->modifiers()& Qt::ControlModifier) {
event->accept();
event->delta() > 0 ? scaleUp() : scaleDown();
} else {
QWebView::wheelEvent(event);
}
m_webView->print(printer);
}
void HelpViewer::mousePressEvent(QMouseEvent *event)
void QtWebKitHelpViewer::goToBackHistoryItem()
{
if (Utils::HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(event))
return;
if (HelpPage *currentPage = static_cast<HelpPage*> (page())) {
currentPage->m_pressedButtons = event->buttons();
currentPage->m_keyboardModifiers = event->modifiers();
goToHistoryItem(/*forward=*/false);
}
QWebView::mousePressEvent(event);
}
void HelpViewer::mouseReleaseEvent(QMouseEvent *event)
void QtWebKitHelpViewer::goToForwardHistoryItem()
{
if (!Utils::HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(event))
return;
QWebView::mouseReleaseEvent(event);
goToHistoryItem(/*forward=*/true);
}
// -- private slots
void HelpViewer::actionChanged()
void QtWebKitHelpViewer::goToHistoryItem(bool forward)
{
QAction *a = qobject_cast<QAction *>(sender());
if (a == pageAction(QWebPage::Back))
emit backwardAvailable(a->isEnabled());
else if (a == pageAction(QWebPage::Forward))
emit forwardAvailable(a->isEnabled());
}
void HelpViewer::slotNetworkReplyFinished(QNetworkReply *reply)
{
if (reply && reply->error() != QNetworkReply::NoError) {
setSource(QUrl(Help::Constants::AboutBlank));
setHtml(QString::fromLatin1(g_htmlPage).arg(g_percent1, reply->errorString(),
HelpViewer::tr("Error loading: %1").arg(reply->url().toString()), g_percent4, g_percent6, g_percent7,
QString()));
}
}
// -- private
bool HelpViewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
if (QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event)) {
if (keyEvent->key() == Qt::Key_Slash)
emit openFindToolBar();
}
}
return QWebView::eventFilter(obj, event);
}
void HelpViewer::contextMenuEvent(QContextMenuEvent *event)
{
QWebView::contextMenuEvent(event);
QAction *action = qobject_cast<QAction *>(sender());
QTC_ASSERT(action, return);
QWebHistory *history = m_webView->history();
QTC_ASSERT(history, return);
bool ok = false;
int index = action->data().toInt(&ok);
QTC_ASSERT(ok, return);
if (forward)
history->goToItem(history->forwardItems(history->count()).at(index));
else
history->goToItem(history->backItems(history->count()).at(index));
}
#endif // !QT_NO_WEBKIT

View File

@@ -0,0 +1,165 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QTWEBKITHELPVIEWER_H
#define QTWEBKITHELPVIEWER_H
#include "helpviewer.h"
#ifndef QT_NO_WEBKIT
#include <QWebPage>
#include <QWebView>
namespace Help {
namespace Internal {
class HelpPage;
class QtWebKitHelpWidget;
class QtWebKitHelpViewer : public HelpViewer
{
Q_OBJECT
public:
explicit QtWebKitHelpViewer(qreal zoom, QWidget *parent = 0);
~QtWebKitHelpViewer() { }
QFont viewerFont() const;
void setViewerFont(const QFont &font);
void scaleUp();
void scaleDown();
void resetScale();
qreal scale() const;
QString title() const;
void setTitle(const QString &title);
QUrl source() const;
void setSource(const QUrl &url);
void scrollToAnchor(const QString &anchor);
void highlightId(const QString &id);
void setHtml(const QString &html);
QString selectedText() const;
bool isForwardAvailable() const;
bool isBackwardAvailable() const;
void addBackHistoryItems(QMenu *backMenu);
void addForwardHistoryItems(QMenu *forwardMenu);
void setOpenInNewWindowActionVisible(bool visible);
bool findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped = 0);
HelpPage *page() const;
public slots:
void copy();
void stop();
void forward();
void backward();
void print(QPrinter *printer);
private slots:
void goToBackHistoryItem();
void goToForwardHistoryItem();
void goToHistoryItem(bool forward);
private:
QString m_oldHighlightId;
QString m_oldHighlightStyle;
QtWebKitHelpWidget *m_webView;
};
class QtWebKitHelpWidget : public QWebView
{
Q_OBJECT
public:
explicit QtWebKitHelpWidget(qreal zoom, QtWebKitHelpViewer *parent = 0);
~QtWebKitHelpWidget();
void scaleUp();
void scaleDown();
public slots:
void copy();
signals:
void forwardAvailable(bool enabled);
void backwardAvailable(bool enabled);
protected:
void keyPressEvent(QKeyEvent *e);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private slots:
void actionChanged();
void slotNetworkReplyFinished(QNetworkReply *reply);
private:
bool eventFilter(QObject *obj, QEvent *event);
QtWebKitHelpViewer *m_parent;
};
class HelpPage : public QWebPage
{
Q_OBJECT
public:
HelpPage(QObject *parent);
protected:
virtual QWebPage *createWindow(QWebPage::WebWindowType);
virtual void triggerAction(WebAction action, bool checked = false);
virtual bool acceptNavigationRequest(QWebFrame *frame,
const QNetworkRequest &request, NavigationType type);
private slots:
void onHandleUnsupportedContent(QNetworkReply *reply);
private:
QUrl m_loadingUrl;
bool closeNewTabIfNeeded;
friend class Help::Internal::QtWebKitHelpWidget;
Qt::MouseButtons m_pressedButtons;
Qt::KeyboardModifiers m_keyboardModifiers;
};
} // namespace Internal
} // namespace Help
#endif // !QT_NO_WEBKIT
#endif // QTWEBKITHELPVIEWER_H

View File

@@ -0,0 +1,440 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "textbrowserhelpviewer.h"
#include "helpconstants.h"
#include "localhelpmanager.h"
#include <coreplugin/find/findplugin.h>
#include <utils/hostosinfo.h>
#include <QApplication>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QHelpEngine>
#include <QKeyEvent>
#include <QMenu>
#include <QVBoxLayout>
using namespace Help;
using namespace Help::Internal;
// -- HelpViewer
TextBrowserHelpViewer::TextBrowserHelpViewer(qreal zoom, QWidget *parent)
: HelpViewer(parent)
, m_textBrowser(new TextBrowserHelpWidget(zoom, this))
{
QVBoxLayout *layout = new QVBoxLayout;
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_textBrowser, 10);
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);
// ???
QFont font = viewerFont();
font.setPointSize(int(font.pointSize() + zoom));
setViewerFont(font);
connect(m_textBrowser, SIGNAL(sourceChanged(QUrl)), this, SIGNAL(titleChanged()));
connect(m_textBrowser, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
connect(m_textBrowser, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
}
TextBrowserHelpViewer::~TextBrowserHelpViewer()
{
}
QFont TextBrowserHelpViewer::viewerFont() const
{
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
return qvariant_cast<QFont>(engine.customValue(QLatin1String("font"),
qApp->font()));
}
void TextBrowserHelpViewer::setViewerFont(const QFont &newFont)
{
if (font() != newFont) {
m_textBrowser->forceFont = true;
m_textBrowser->setFont(newFont);
m_textBrowser->forceFont = false;
}
}
void TextBrowserHelpViewer::scaleUp()
{
m_textBrowser->scaleUp();
}
void TextBrowserHelpViewer::scaleDown()
{
m_textBrowser->scaleDown();
}
void TextBrowserHelpViewer::resetScale()
{
if (m_textBrowser->zoomCount != 0) {
m_textBrowser->forceFont = true;
m_textBrowser->zoomOut(m_textBrowser->zoomCount);
m_textBrowser->forceFont = false;
}
m_textBrowser->zoomCount = 0;
}
qreal TextBrowserHelpViewer::scale() const
{
return m_textBrowser->zoomCount;
}
QString TextBrowserHelpViewer::title() const
{
return m_textBrowser->documentTitle();
}
void TextBrowserHelpViewer::setTitle(const QString &title)
{
m_textBrowser->setDocumentTitle(title);
}
QUrl TextBrowserHelpViewer::source() const
{
return m_textBrowser->source();
}
void TextBrowserHelpViewer::setSource(const QUrl &url)
{
const QString &string = url.toString();
if (url.isValid() && string != QLatin1String("help")) {
if (launchWithExternalApp(url))
return;
QUrl resolvedUrl;
if (url.scheme() == QLatin1String("http"))
resolvedUrl = url;
if (!resolvedUrl.isValid()) {
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
resolvedUrl = engine.findFile(url);
}
if (resolvedUrl.isValid()) {
m_textBrowser->setSource(resolvedUrl);
slotLoadFinished();
return;
}
}
m_textBrowser->setSource(url);
m_textBrowser->setHtml(string == Help::Constants::AboutBlank
? HelpViewer::tr("<title>about:blank</title>")
: HelpViewer::tr("<html><head><meta http-equiv=\""
"content-type\" content=\"text/html; charset=UTF-8\"><title>Error 404...</title>"
"</head><body><div align=\"center\"><br/><br/><h1>The page could not be found</h1>"
"<br/><h3>\"%1\"</h3></div></body></html>")
.arg(url.toString()));
slotLoadFinished();
}
void TextBrowserHelpViewer::scrollToAnchor(const QString &anchor)
{
m_textBrowser->scrollToAnchor(anchor);
}
void TextBrowserHelpViewer::setHtml(const QString &html)
{
m_textBrowser->setHtml(html);
}
QString TextBrowserHelpViewer::selectedText() const
{
return m_textBrowser->textCursor().selectedText();
}
bool TextBrowserHelpViewer::isForwardAvailable() const
{
return m_textBrowser->isForwardAvailable();
}
bool TextBrowserHelpViewer::isBackwardAvailable() const
{
return m_textBrowser->isBackwardAvailable();
}
void TextBrowserHelpViewer::setOpenInNewWindowActionVisible(bool visible)
{
m_textBrowser->showOpenInNewWindowAction = visible;
}
bool TextBrowserHelpViewer::findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped)
{
if (wrapped)
*wrapped = false;
QTextDocument *doc = m_textBrowser->document();
QTextCursor cursor = m_textBrowser->textCursor();
if (!doc || cursor.isNull())
return false;
const int position = cursor.selectionStart();
if (incremental)
cursor.setPosition(position);
QTextDocument::FindFlags f = Core::textDocumentFlagsForFindFlags(flags);
QTextCursor found = doc->find(text, cursor, f);
if (found.isNull()) {
if ((flags & Core::FindBackward) == 0)
cursor.movePosition(QTextCursor::Start);
else
cursor.movePosition(QTextCursor::End);
found = doc->find(text, cursor, f);
if (!found.isNull() && wrapped)
*wrapped = true;
}
if (fromSearch) {
cursor.beginEditBlock();
m_textBrowser->viewport()->setUpdatesEnabled(false);
QTextCharFormat marker;
marker.setForeground(Qt::red);
cursor.movePosition(QTextCursor::Start);
m_textBrowser->setTextCursor(cursor);
while (m_textBrowser->find(text)) {
QTextCursor hit = m_textBrowser->textCursor();
hit.mergeCharFormat(marker);
}
m_textBrowser->viewport()->setUpdatesEnabled(true);
cursor.endEditBlock();
}
bool cursorIsNull = found.isNull();
if (cursorIsNull) {
found = m_textBrowser->textCursor();
found.setPosition(position);
}
m_textBrowser->setTextCursor(found);
return !cursorIsNull;
}
// -- public slots
void TextBrowserHelpViewer::copy()
{
m_textBrowser->copy();
}
void TextBrowserHelpViewer::stop()
{
}
void TextBrowserHelpViewer::forward()
{
m_textBrowser->forward();
}
void TextBrowserHelpViewer::backward()
{
m_textBrowser->backward();
}
void TextBrowserHelpViewer::print(QPrinter *printer)
{
m_textBrowser->print(printer);
}
// -- private
TextBrowserHelpWidget::TextBrowserHelpWidget(int zoom, TextBrowserHelpViewer *parent)
: QTextBrowser(parent)
, zoomCount(zoom)
, forceFont(false)
, lastAnchor(QString())
, showOpenInNewWindowAction(true)
, m_parent(parent)
{
installEventFilter(this);
document()->setDocumentMargin(8);
}
QVariant TextBrowserHelpWidget::loadResource(int type, const QUrl &name)
{
QByteArray ba;
if (type < 4) {
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
ba = engine.fileData(name);
if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
QImage image;
image.loadFromData(ba, "svg");
if (!image.isNull())
return image;
}
}
return ba;
}
bool TextBrowserHelpWidget::hasAnchorAt(const QPoint &pos)
{
lastAnchor = anchorAt(pos);
if (lastAnchor.isEmpty())
return false;
lastAnchor = source().resolved(lastAnchor).toString();
if (lastAnchor.at(0) == QLatin1Char('#')) {
QString src = source().toString();
int hsh = src.indexOf(QLatin1Char('#'));
lastAnchor = (hsh >= 0 ? src.left(hsh) : src) + lastAnchor;
}
return true;
}
void TextBrowserHelpWidget::openLink(bool newPage)
{
if (lastAnchor.isEmpty())
return;
if (newPage)
OpenPagesManager::instance().createPage(lastAnchor);
else
CentralWidget::instance()->setSource(lastAnchor);
lastAnchor.clear();
}
void TextBrowserHelpWidget::scaleUp()
{
if (zoomCount < 10) {
zoomCount++;
forceFont = true;
zoomIn();
forceFont = false;
}
}
void TextBrowserHelpWidget::scaleDown()
{
if (zoomCount > -5) {
zoomCount--;
forceFont = true;
zoomOut();
forceFont = false;
}
}
void TextBrowserHelpWidget::openLink()
{
openLink(false);
}
void TextBrowserHelpWidget::openLinkInNewPage()
{
openLink(true);
}
void TextBrowserHelpWidget::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(QLatin1String(""), 0);
QUrl link;
QAction *copyAnchorAction = 0;
if (hasAnchorAt(event->pos())) {
link = anchorAt(event->pos());
if (link.isRelative())
link = source().resolved(link);
menu.addAction(tr("Open Link"), this, SLOT(openLink()));
if (showOpenInNewWindowAction)
menu.addAction(tr("Open Link as New Page"), this, SLOT(openLinkInNewPage()));
if (!link.isEmpty() && link.isValid())
copyAnchorAction = menu.addAction(tr("Copy Link"));
} else if (!textCursor().selectedText().isEmpty()) {
menu.addAction(tr("Copy"), this, SLOT(copy()));
} else {
menu.addAction(tr("Reload"), this, SLOT(reload()));
}
if (copyAnchorAction == menu.exec(event->globalPos()))
QApplication::clipboard()->setText(link.toString());
}
bool TextBrowserHelpWidget::eventFilter(QObject *obj, QEvent *event)
{
if (obj == this) {
if (event->type() == QEvent::FontChange) {
if (!forceFont)
return true;
} else if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Slash) {
keyEvent->accept();
Core::FindPlugin::instance()->openFindToolBar(Core::FindPlugin::FindForwardDirection);
return true;
}
}
}
return QTextBrowser::eventFilter(obj, event);
}
void TextBrowserHelpWidget::wheelEvent(QWheelEvent *e)
{
if (e->modifiers() == Qt::ControlModifier) {
e->accept();
e->delta() > 0 ? scaleUp() : scaleDown();
} else {
QTextBrowser::wheelEvent(e);
}
}
void TextBrowserHelpWidget::mousePressEvent(QMouseEvent *e)
{
if (Utils::HostOsInfo::isLinuxHost() && m_parent->handleForwardBackwardMouseButtons(e))
return;
QTextBrowser::mousePressEvent(e);
}
void TextBrowserHelpWidget::mouseReleaseEvent(QMouseEvent *e)
{
if (!Utils::HostOsInfo::isLinuxHost() && m_parent->handleForwardBackwardMouseButtons(e))
return;
bool controlPressed = e->modifiers() & Qt::ControlModifier;
if ((controlPressed && hasAnchorAt(e->pos())) ||
(e->button() == Qt::MidButton && hasAnchorAt(e->pos()))) {
openLinkInNewPage();
return;
}
QTextBrowser::mouseReleaseEvent(e);
}

View File

@@ -0,0 +1,129 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef TEXTBROWSERHELPVIEWER_H
#define TEXTBROWSERHELPVIEWER_H
#include "centralwidget.h"
#include "helpviewer.h"
#include "openpagesmanager.h"
#include <QTextBrowser>
namespace Help {
namespace Internal {
class TextBrowserHelpWidget;
class TextBrowserHelpViewer : public HelpViewer
{
Q_OBJECT
public:
explicit TextBrowserHelpViewer(qreal zoom, QWidget *parent = 0);
~TextBrowserHelpViewer();
QFont viewerFont() const;
void setViewerFont(const QFont &font);
void scaleUp();
void scaleDown();
void resetScale();
qreal scale() const;
QString title() const;
void setTitle(const QString &title);
QUrl source() const;
void setSource(const QUrl &url);
void scrollToAnchor(const QString &anchor);
void setHtml(const QString &html);
QString selectedText() const;
bool isForwardAvailable() const;
bool isBackwardAvailable() const;
void addBackHistoryItems(QMenu *backMenu) { Q_UNUSED(backMenu) }
void addForwardHistoryItems(QMenu *forwardMenu) { Q_UNUSED(forwardMenu) }
void setOpenInNewWindowActionVisible(bool visible);
bool findText(const QString &text, Core::FindFlags flags,
bool incremental, bool fromSearch, bool *wrapped = 0);
public slots:
void copy();
void stop();
void forward();
void backward();
void print(QPrinter *printer);
private:
QVariant loadResource(int type, const QUrl &name);
TextBrowserHelpWidget *m_textBrowser;
};
class TextBrowserHelpWidget : public QTextBrowser
{
Q_OBJECT
public:
TextBrowserHelpWidget(int zoom, TextBrowserHelpViewer *parent);
QVariant loadResource(int type, const QUrl &name);
bool hasAnchorAt(const QPoint& pos);
void openLink(bool newPage);
void scaleUp();
void scaleDown();
public slots:
void openLink();
void openLinkInNewPage();
protected:
void contextMenuEvent(QContextMenuEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
void wheelEvent(QWheelEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
public:
int zoomCount;
bool forceFont;
QString lastAnchor;
bool showOpenInNewWindowAction;
TextBrowserHelpViewer *m_parent;
};
} // namespace Internal
} // namespace Help
#endif // TEXTBROWSERHELPVIEWER_H