diff --git a/src/plugins/help/helpviewer.cpp b/src/plugins/help/helpviewer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3a7bd2ecf62e87991225f7c83ede66a2fac25e6 --- /dev/null +++ b/src/plugins/help/helpviewer.cpp @@ -0,0 +1,129 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "helpviewer.h" +#include "helpconstants.h" +#include "helpmanager.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QFileInfo> +#include <QtCore/QStringBuilder> +#include <QtCore/QTemporaryFile> +#include <QtCore/QUrl> + +#include <QtGui/QDesktopServices> +#include <QtGui/QMouseEvent> + +#include <QtHelp/QHelpEngineCore> + +using namespace Help::Internal; + +QString HelpViewer::AboutBlankPage = + QCoreApplication::translate("HelpViewer", "<title>about:blank</title>"); + +QString HelpViewer::PageNotFoundMessage = + QCoreApplication::translate("HelpViewer", "<title>Error 404...</title><div " + "align=\"center\"><br><br><h1>The page could not be found</h1><br><h3>'%1'" + "</h3></div>"); + +bool HelpViewer::isLocalUrl(const QUrl &url) +{ + const QString &scheme = url.scheme(); + return scheme.isEmpty() + || scheme == QLatin1String("file") + || scheme == QLatin1String("qrc") + || scheme == QLatin1String("data") + || scheme == QLatin1String("qthelp") + || scheme == QLatin1String("about"); +} + +bool HelpViewer::canOpenPage(const QString &url) +{ + return url.endsWith(QLatin1String(".html"), Qt::CaseInsensitive) + || url.endsWith(QLatin1String(".htm"), Qt::CaseInsensitive) + || url == Help::Constants::AboutBlank; +} + +bool HelpViewer::launchWithExternalApp(const QUrl &url) +{ + if (isLocalUrl(url)) { + const QHelpEngineCore &helpEngine = Help::HelpManager::helpEngineCore(); + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (!resolvedUrl.isValid()) + return false; + + const QString& path = resolvedUrl.path(); + if (!canOpenPage(path)) { + QTemporaryFile tmpTmpFile; + if (!tmpTmpFile.open()) + return false; + + const QString &extension = QFileInfo(path).completeSuffix(); + QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String(".") + % extension); + if (!actualTmpFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) + return false; + + actualTmpFile.write(helpEngine.fileData(resolvedUrl)); + actualTmpFile.close(); + return QDesktopServices::openUrl(QUrl(actualTmpFile.fileName())); + } + } else if (url.scheme() == QLatin1String("http")) { + return QDesktopServices::openUrl(url); + } + return false; +} + +void HelpViewer::home() +{ + const QHelpEngineCore &engine = Help::HelpManager::helpEngineCore(); + QString homepage = engine.customValue(QLatin1String("HomePage"), + QLatin1String("")).toString(); + + if (homepage.isEmpty()) { + homepage = engine.customValue(QLatin1String("DefaultHomePage"), + Help::Constants::AboutBlank).toString(); + } + + setSource(homepage); +} + +bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event) +{ + if (event->button() == Qt::XButton1) { + backward(); + return true; + } + if (event->button() == Qt::XButton2) { + forward(); + return true; + } + + return false; +} diff --git a/src/plugins/help/helpviewer.h b/src/plugins/help/helpviewer.h new file mode 100644 index 0000000000000000000000000000000000000000..489185d8efa8892e123589dcc5f11643e1c2ccf0 --- /dev/null +++ b/src/plugins/help/helpviewer.h @@ -0,0 +1,135 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef HELPVIEWER_H +#define HELPVIEWER_H + +#include <find/ifindsupport.h> + +#include <QtCore/qglobal.h> +#include <QtCore/QString> +#include <QtCore/QUrl> +#include <QtCore/QVariant> + +#include <QtGui/QAction> +#include <QtGui/QFont> + +#if defined(QT_NO_WEBKIT) +#include <QtGui/QTextBrowser> +#else +#include <QtWebKit/QWebView> +#endif + +namespace Help { + namespace Internal { + +#if !defined(QT_NO_WEBKIT) +class HelpViewer : public QWebView +#else +class HelpViewer : public QTextBrowser +#endif +{ + Q_OBJECT + class HelpViewerPrivate; + Q_DISABLE_COPY(HelpViewer) + +public: + HelpViewer(qreal zoom, QWidget *parent = 0); + ~HelpViewer(); + + 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); + + QString selectedText() const; + bool isForwardAvailable() const; + bool isBackwardAvailable() const; + + bool findText(const QString &text, Find::IFindSupport::FindFlags flags, + bool incremental); + + static QString AboutBlankPage; + static QString PageNotFoundMessage; + + static bool isLocalUrl(const QUrl &url); + static bool canOpenPage(const QString &url); + static bool launchWithExternalApp(const QUrl &url); + +public slots: + void copy(); + void home(); + + void forward(); + void backward(); + +signals: + void titleChanged(); +#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(); + void setLoadFinished(bool ok); + +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; +}; + + } // namespace Help +} // namespace Internal + +#endif // HELPVIEWER_H diff --git a/src/plugins/help/helpviewer_p.h b/src/plugins/help/helpviewer_p.h new file mode 100644 index 0000000000000000000000000000000000000000..7ba7e95fd7cb88797fa49230d15ce32724b0d6e9 --- /dev/null +++ b/src/plugins/help/helpviewer_p.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef HELPVIEWERPRIVATE_H +#define HELPVIEWERPRIVATE_H + +#include "centralwidget.h" +#include "helpviewer.h" +#include "openpagesmanager.h" + +#include <QtCore/QObject> +#include <QtGui/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 diff --git a/src/plugins/help/helpviewer_qtb.cpp b/src/plugins/help/helpviewer_qtb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b56a2bed5d23969cbf457d7a41402c59c3b493fe --- /dev/null +++ b/src/plugins/help/helpviewer_qtb.cpp @@ -0,0 +1,334 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "helpviewer.h" + +#if defined(QT_NO_WEBKIT) + +#include "helpconstants.h" +#include "helpviewer_p.h" +#include "helpmanager.h" + +#include <QtGui/QApplication> +#include <QtGui/QClipboard> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QKeyEvent> +#include <QtGui/QMenu> + +#include <QtHelp/QHelpEngineCore> + +using namespace Find; +using namespace Help; +using namespace Help::Internal; + +// -- HelpViewer + +HelpViewer::HelpViewer(qreal zoom, QWidget *parent) + : QTextBrowser(parent) + , d(new HelpViewerPrivate(zoom)) +{ + 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(setLoadFinished(bool))); +} + +HelpViewer::~HelpViewer() +{ + delete d; +} + +QFont HelpViewer::viewerFont() const +{ + const QHelpEngineCore &engine = HelpManager::helpEngineCore(); + return qVariantValue<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; + + const QHelpEngineCore &engine = HelpManager::instance().helpEngineCore(); + const QUrl &resolvedUrl = engine.findFile(url); + if (resolvedUrl.isValid()) { + QTextBrowser::setSource(resolvedUrl); + emit loadFinished(true); + return; + } + } + + QTextBrowser::setSource(url); + setHtml(string == Help::Constants::AboutBlank ? AboutBlankPage + : PageNotFoundMessage.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, IFindSupport::FindFlags flags, + bool incremental) +{ + QTextDocument *doc = document(); + QTextCursor cursor = textCursor(); + + if (!doc || cursor.isNull()) + return false; + + if (incremental) + cursor.setPosition(cursor.selectionStart()); + + QTextDocument::FindFlags f = IFindSupport::textDocumentFlagsForFindFlags(flags); + QTextCursor found = doc->find(text, cursor, f); + if (found.isNull()) { + if ((flags & Find::IFindSupport::FindBackward) == 0) + cursor.movePosition(QTextCursor::Start); + else + cursor.movePosition(QTextCursor::End); + found = doc->find(text, cursor, f); + if (found.isNull()) { + return false; + } + } + if (!found.isNull()) { + setTextCursor(found); + } + return true; +} + +// -- public slots + +void HelpViewer::copy() +{ + QTextBrowser::copy(); +} + +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) +{ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + QTextBrowser::mousePressEvent(e); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *e) +{ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + 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 +} + +void HelpViewer::setLoadFinished(bool ok) +{ + Q_UNUSED(ok) + emit sourceChanged(source()); +} + +// -- private + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::FontChange && !d->forceFont) + return true; + 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 = HelpManager::instance().helpEngineCore(); + 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 diff --git a/src/plugins/help/helpviewer_qwv.cpp b/src/plugins/help/helpviewer_qwv.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e463719a4122c864cc9f7c286905c29bde8c078 --- /dev/null +++ b/src/plugins/help/helpviewer_qwv.cpp @@ -0,0 +1,441 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "helpviewer.h" + +#if !defined(QT_NO_WEBKIT) + +#include "centralwidget.h" +#include "helpconstants.h" +#include "helpmanager.h" +#include "openpagesmanager.h" + +#include <QtCore/QFileInfo> +#include <QtCore/QString> +#include <QtCore/QStringBuilder> +#include <QtCore/QTimer> + +#include <QtGui/QApplication> +#include <QtGui/QWheelEvent> + +#include <QtHelp/QHelpEngineCore> + +#include <QtNetwork/QNetworkAccessManager> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +using namespace Find; +using namespace Help; +using namespace Help::Internal; + +// -- HelpNetworkReply + +class HelpNetworkReply : public QNetworkReply +{ +public: + HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, + const QString &mimeType); + + virtual void abort(); + + virtual qint64 bytesAvailable() const + { return data.length() + QNetworkReply::bytesAvailable(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen); + +private: + QByteArray data; + qint64 origLen; +}; + +HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, + const QByteArray &fileData, const QString& mimeType) + : data(fileData), origLen(fileData.length()) +{ + setRequest(request); + setOpenMode(QIODevice::ReadOnly); + + setHeader(QNetworkRequest::ContentTypeHeader, mimeType); + setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); + QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); + QTimer::singleShot(0, this, SIGNAL(readyRead())); +} + +void HelpNetworkReply::abort() +{ +} + +qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +{ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + qMemCopy(buffer, data.constData(), len); + data.remove(0, len); + } + if (!data.length()) + QTimer::singleShot(0, this, SIGNAL(finished())); + return len; +} + +// -- HelpNetworkAccessManager + +class HelpNetworkAccessManager : public QNetworkAccessManager +{ +public: + HelpNetworkAccessManager(QObject *parent); + +protected: + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest &request, QIODevice *outgoingData = 0); +}; + +HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ +} + +QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, + const QNetworkRequest &request, QIODevice* /*outgoingData*/) +{ + const QUrl& url = request.url(); + QString mimeType = url.toString(); + if (mimeType.endsWith(QLatin1String(".svg")) + || mimeType.endsWith(QLatin1String(".svgz"))) { + mimeType = QLatin1String("image/svg+xml"); + } else if (mimeType.endsWith(QLatin1String(".css"))) { + mimeType = QLatin1String("text/css"); + } else if (mimeType.endsWith(QLatin1String(".js"))) { + mimeType = QLatin1String("text/javascript"); + } else if (mimeType.endsWith(QLatin1String(".txt"))) { + mimeType = QLatin1String("text/plain"); + } else { + mimeType = QLatin1String("text/html"); + } + + const QHelpEngineCore &engine = HelpManager::helpEngineCore(); + const QByteArray &data = engine.findFile(url).isValid() + ? engine.fileData(url) : HelpViewer::PageNotFoundMessage.arg(url.toString()).toUtf8(); + return new HelpNetworkReply(request, data, mimeType); +} + +// -- HelpPage + +class HelpPage : public QWebPage +{ +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: + bool closeNewTabIfNeeded; + + friend class HelpViewer; + Qt::MouseButtons m_pressedButtons; + Qt::KeyboardModifiers m_keyboardModifiers; +}; + +HelpPage::HelpPage(QObject *parent) + : QWebPage(parent) + , closeNewTabIfNeeded(false) + , m_pressedButtons(Qt::NoButton) + , m_keyboardModifiers(Qt::NoModifier) +{ +} + +QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) +{ + HelpPage* newPage = static_cast<HelpPage*>(OpenPagesManager::instance() + .createPage()->page()); + newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + return newPage; +} + +void HelpPage::triggerAction(WebAction action, bool checked) +{ + switch (action) { + case OpenLinkInNewWindow: + closeNewTabIfNeeded = true; + default: // fall through + QWebPage::triggerAction(action, checked); + break; + } +} + +bool HelpPage::acceptNavigationRequest(QWebFrame *, + const QNetworkRequest &request, QWebPage::NavigationType type) +{ + const bool closeNewTab = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + + const QUrl &url = request.url(); + if (HelpViewer::launchWithExternalApp(url)) { + if (closeNewTab) + QMetaObject::invokeMethod(&OpenPagesManager::instance(), "closeCurrentPage"); + return false; + } + + if (type == QWebPage::NavigationTypeLinkClicked + && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) { + m_pressedButtons = Qt::NoButton; + m_keyboardModifiers = Qt::NoModifier; + OpenPagesManager::instance().createPage(url); + return false; + } + + return true; +} + +// -- HelpViewer + +HelpViewer::HelpViewer(qreal zoom, QWidget *parent) + : QWebView(parent) +{ + setAcceptDrops(false); + settings()->setAttribute(QWebSettings::JavaEnabled, false); + settings()->setAttribute(QWebSettings::PluginsEnabled, false); + + setPage(new HelpPage(this)); + page()->setNetworkAccessManager(new HelpNetworkAccessManager(this)); + + QAction* action = pageAction(QWebPage::OpenLinkInNewWindow); + action->setText(tr("Open Link as New Page")); + + pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false); + pageAction(QWebPage::DownloadImageToDisk)->setVisible(false); + pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false); + + connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); + connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged())); + + setFont(viewerFont()); + setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); +} + +HelpViewer::~HelpViewer() +{ +} + +QFont HelpViewer::viewerFont() const +{ + QWebSettings* webSettings = QWebSettings::globalSettings(); + QFont font(QApplication::font().family(), + webSettings->fontSize(QWebSettings::DefaultFontSize)); + const QHelpEngineCore &engine = HelpManager::helpEngineCore(); + return qVariantValue<QFont>(engine.customValue(QLatin1String("font"), + font)); +} + +void HelpViewer::setViewerFont(const QFont &font) +{ + QWebSettings *webSettings = settings(); + webSettings->setFontFamily(QWebSettings::StandardFont, font.family()); + webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); +} + +void HelpViewer::scaleUp() +{ + setTextSizeMultiplier(textSizeMultiplier() + 0.1); +} + +void HelpViewer::scaleDown() +{ + setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - 0.1)); +} + +void HelpViewer::resetScale() +{ + setTextSizeMultiplier(1.0); +} + +qreal HelpViewer::scale() const +{ + return textSizeMultiplier(); +} + +QString HelpViewer::title() const +{ + return QWebView::title(); +} + +void HelpViewer::setTitle(const QString &title) +{ + Q_UNUSED(title) +} + +QUrl HelpViewer::source() const +{ + return url(); +} + +void HelpViewer::setSource(const QUrl &url) +{ + load(url); +} + +QString HelpViewer::selectedText() const +{ + return QWebView::selectedText(); +} + +bool HelpViewer::isForwardAvailable() const +{ + return pageAction(QWebPage::Forward)->isEnabled(); +} + +bool HelpViewer::isBackwardAvailable() const +{ + return pageAction(QWebPage::Back)->isEnabled(); +} + +bool HelpViewer::findText(const QString &text, IFindSupport::FindFlags flags, + bool incremental) +{ + Q_UNUSED(incremental) + QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument; + if (flags & Find::IFindSupport::FindBackward) + options |= QWebPage::FindBackward; + if (flags & Find::IFindSupport::FindCaseSensitively) + options |= QWebPage::FindCaseSensitively; + + bool found = QWebView::findText(text, options); + options = QWebPage::HighlightAllOccurrences; + QWebView::findText(QLatin1String(""), options); // clear first + QWebView::findText(text, options); // force highlighting of all other matches + return found; +} + +// -- public slots + +void HelpViewer::copy() +{ + triggerPageAction(QWebPage::Copy); +} + +void HelpViewer::forward() +{ + QWebView::forward(); +} + +void HelpViewer::backward() +{ + back(); +} + +// -- protected + +void HelpViewer::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 HelpViewer::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers()& Qt::ControlModifier) { + event->accept(); + event->delta() > 0 ? scaleUp() : scaleDown(); + } else { + QWebView::wheelEvent(event); + } +} + +void HelpViewer::mousePressEvent(QMouseEvent *event) +{ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + if (HelpPage *currentPage = static_cast<HelpPage*> (page())) { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + + QWebView::mousePressEvent(event); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *event) +{ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + QWebView::mouseReleaseEvent(event); +} + +// -- private slots + +void HelpViewer::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 HelpViewer::setLoadFinished(bool ok) +{ + Q_UNUSED(ok) + emit sourceChanged(source()); +} + +// -- private + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + return QWebView::eventFilter(obj, event); +} + +void HelpViewer::contextMenuEvent(QContextMenuEvent *event) +{ + QWebView::contextMenuEvent(event); +} + +#endif // !QT_NO_WEBKIT diff --git a/src/plugins/help/openpagesmanager.h b/src/plugins/help/openpagesmanager.h index a20332c860bec8b0358133d4b534b5847ae61f26..aa1303a2ce94642ae079887212dca12d38fa8e78 100644 --- a/src/plugins/help/openpagesmanager.h +++ b/src/plugins/help/openpagesmanager.h @@ -39,11 +39,10 @@ QT_FORWARD_DECLARE_CLASS(QTreeView) QT_FORWARD_DECLARE_CLASS(QUrl) QT_FORWARD_DECLARE_CLASS(QWidget) -class HelpViewer; - namespace Help { namespace Internal { +class HelpViewer; class OpenPagesModel; class OpenPagesManager : public QObject diff --git a/src/plugins/help/openpagesmodel.h b/src/plugins/help/openpagesmodel.h index 2dc7c878819883c98c7a4c419254094a240313d4..a35b273963ee91a2b0bae2b26e703b1a8210a96b 100644 --- a/src/plugins/help/openpagesmodel.h +++ b/src/plugins/help/openpagesmodel.h @@ -34,11 +34,12 @@ #include <QtCore/QAbstractTableModel> QT_FORWARD_DECLARE_CLASS(QUrl) -class HelpViewer; namespace Help { namespace Internal { +class HelpViewer; + class OpenPagesModel : public QAbstractTableModel { Q_OBJECT