forked from qt-creator/qt-creator
Task-number: QTCREATORBUG-2701 Task-number: QTCREATORBUG-4059 Enable plugins to support pdf, etc. files out of the box in Qt Creator. If we still fail we try to open the link using the desktop service, as last resort to open a page showing some error message and hints about the error. Adjust the old page not found message to match the new design. Change-Id: I7fef79d27e8bc279a6169b6f3da4787ffa0d023d Reviewed-by: Niels Weber <niels.2.weber@nokia.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com> Reviewed-by: Karsten Heimrich <karsten.heimrich@nokia.com>
592 lines
20 KiB
C++
592 lines
20 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
**
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
**
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
** Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** Other Usage
|
|
**
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
**
|
|
** If you have questions regarding the use of this file, please contact
|
|
** Nokia at qt-info@nokia.com.
|
|
**
|
|
**************************************************************************/
|
|
|
|
#include "helpviewer.h"
|
|
|
|
#if !defined(QT_NO_WEBKIT)
|
|
|
|
#include "centralwidget.h"
|
|
#include "helpconstants.h"
|
|
#include "localhelpmanager.h"
|
|
#include "openpagesmanager.h"
|
|
|
|
#include <QDebug>
|
|
#include <QFileInfo>
|
|
#include <QString>
|
|
#include <QStringBuilder>
|
|
#include <QTimer>
|
|
#include <QWebFrame>
|
|
|
|
#include <QApplication>
|
|
#include <QDesktopServices>
|
|
#include <QWheelEvent>
|
|
|
|
#include <QHelpEngine>
|
|
|
|
#include <QNetworkReply>
|
|
#include <QNetworkRequest>
|
|
|
|
#include <utils/networkaccessmanager.h>
|
|
|
|
using namespace Find;
|
|
using namespace Help;
|
|
using namespace Help::Internal;
|
|
|
|
static const char g_htmlPage[] = "<html><head><meta http-equiv=\"content-type\" content=\"text/html; "
|
|
"charset=UTF-8\"><title>%1</title><style>body{padding: 3em 0em;background: #eeeeee;}"
|
|
"hr{color: lightgray;width: 100%;}img{float: left;opacity: .8;}#box{background: white;border: 1px solid "
|
|
"lightgray;width: 600px;padding: 60px;margin: auto;}h1{font-size: 130%;font-weight: bold;border-bottom: "
|
|
"1px solid lightgray;margin-left: 48px;}h2{font-size: 100%;font-weight: normal;border-bottom: 1px solid "
|
|
"lightgray;margin-left: 48px;}ul{font-size: 80%;padding-left: 48px;margin: 0;}#reloadButton{padding-left:"
|
|
"48px;}</style></head><body><div id=\"box\"><img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACA"
|
|
"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\" width=\"32\"height=\"32\" /><h1>%2</h1><h2>%3</h2>"
|
|
"<ul>%4%5%6%7</ul></div></body></html>";
|
|
|
|
// some of the values we will replace %1...6 inside the former html
|
|
const QString g_percent1 = QCoreApplication::translate("HelpViewer", "Error 404...");
|
|
const QString g_percent2 = QCoreApplication::translate("HelpViewer", "The page could not be found!");
|
|
// percent3 will be the url of the page we got the error from
|
|
const QString g_percent4 = QCoreApplication::translate("HelpViewer", "<li>Check that you have one or more "
|
|
"documentation sets installed.</li>");
|
|
const QString g_percent5 = QCoreApplication::translate("HelpViewer", "<li>Check that you have installed the "
|
|
"appropriate browser plug-in to support the file your loading.</li>");
|
|
const QString g_percent6 = QCoreApplication::translate("HelpViewer", "<li>If you try to access a public "
|
|
"URL, make sure to have a network connection.</li>");
|
|
const QString g_percent7 = QCoreApplication::translate("HelpViewer", "<li>If your computer or network is "
|
|
"protected by a firewall or proxy, make sure the application is permitted to access the network.</li>");
|
|
|
|
|
|
// -- 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 dataLength;
|
|
};
|
|
|
|
HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request,
|
|
const QByteArray &fileData, const QString& mimeType)
|
|
: data(fileData)
|
|
, dataLength(fileData.length())
|
|
{
|
|
setRequest(request);
|
|
setOpenMode(QIODevice::ReadOnly);
|
|
|
|
setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
|
|
setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(dataLength));
|
|
QTimer::singleShot(0, this, SIGNAL(metaDataChanged()));
|
|
QTimer::singleShot(0, this, SIGNAL(readyRead()));
|
|
QTimer::singleShot(0, this, SIGNAL(finished()));
|
|
}
|
|
|
|
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);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
// -- HelpNetworkAccessManager
|
|
|
|
class HelpNetworkAccessManager : public Utils::NetworkAccessManager
|
|
{
|
|
public:
|
|
HelpNetworkAccessManager(QObject *parent);
|
|
|
|
protected:
|
|
virtual QNetworkReply *createRequest(Operation op,
|
|
const QNetworkRequest &request, QIODevice *outgoingData = 0);
|
|
};
|
|
|
|
HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent)
|
|
: Utils::NetworkAccessManager(parent)
|
|
{
|
|
}
|
|
|
|
QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op,
|
|
const QNetworkRequest &request, QIODevice* outgoingData)
|
|
{
|
|
if (!HelpViewer::isLocalUrl(request.url()))
|
|
return Utils::NetworkAccessManager::createRequest(op, request, outgoingData);
|
|
|
|
QString url = request.url().toString();
|
|
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
|
|
// TODO: For some reason the url to load is already wrong (passed from webkit)
|
|
// though the css file and the references inside should work that way. One
|
|
// possible problem might be that the css is loaded at the same level as the
|
|
// html, thus a path inside the css like (../images/foo.png) might cd out of
|
|
// the virtual folder
|
|
if (!engine.findFile(url).isValid()) {
|
|
if (url.startsWith(HelpViewer::NsNokia) || url.startsWith(HelpViewer::NsTrolltech)) {
|
|
QUrl newUrl = request.url();
|
|
if (!newUrl.path().startsWith(QLatin1String("/qdoc/")) ||
|
|
!newUrl.path().startsWith(QLatin1String("/doc/"))) {
|
|
QString path = newUrl.path();
|
|
newUrl.setPath(QLatin1String("/qdoc/") + path);
|
|
if (!engine.findFile(newUrl).isValid())
|
|
newUrl.setPath(QLatin1String("/doc/") + path);
|
|
url = newUrl.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
const QString &mimeType = HelpViewer::mimeFromUrl(url);
|
|
const QByteArray &data = engine.findFile(url).isValid() ? engine.fileData(url)
|
|
: QString::fromLatin1(g_htmlPage).arg(g_percent1, g_percent2, HelpViewer::tr("Error loading: %1")
|
|
.arg(url), g_percent4, g_percent6, g_percent7, QString()).toUtf8();
|
|
|
|
return new HelpNetworkReply(request, data, mimeType.isEmpty()
|
|
? QLatin1String("application/octet-stream") : mimeType);
|
|
}
|
|
|
|
// -- HelpPage
|
|
|
|
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;
|
|
};
|
|
#include "helpviewer_qwv.moc"
|
|
|
|
|
|
// - HelpPage
|
|
|
|
HelpPage::HelpPage(QObject *parent)
|
|
: QWebPage(parent)
|
|
, closeNewTabIfNeeded(false)
|
|
, m_pressedButtons(Qt::NoButton)
|
|
, m_keyboardModifiers(Qt::NoModifier)
|
|
{
|
|
setForwardUnsupportedContent(true);
|
|
connect(this, SIGNAL(unsupportedContent(QNetworkReply*)), this,
|
|
SLOT(onHandleUnsupportedContent(QNetworkReply*)));
|
|
}
|
|
|
|
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 *frame, 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;
|
|
}
|
|
|
|
if (frame == mainFrame())
|
|
m_loadingUrl = request.url();
|
|
|
|
return true;
|
|
}
|
|
|
|
void HelpPage::onHandleUnsupportedContent(QNetworkReply *reply)
|
|
{
|
|
// sub resource of this page
|
|
if (m_loadingUrl != reply->url()) {
|
|
qWarning() << "Resource" << reply->url().toEncoded() << "has unknown Content-Type, will be ignored.";
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
// set a default error string we are going to display
|
|
QString errorString = HelpViewer::tr("Unknown or unsupported Content!");
|
|
if (reply->error() == QNetworkReply::NoError) {
|
|
// try to open the url using using the desktop service
|
|
if (QDesktopServices::openUrl(reply->url())) {
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
// seems we failed, now we show the error page inside creator
|
|
} else {
|
|
errorString = reply->errorString();
|
|
}
|
|
|
|
// setup html
|
|
const QString html = QString::fromLatin1(g_htmlPage).arg(g_percent1, errorString,
|
|
HelpViewer::tr("Error loading: %1").arg(reply->url().toString()), g_percent4, g_percent5, g_percent6,
|
|
g_percent7);
|
|
|
|
// update the current layout
|
|
QList<QWebFrame*> frames;
|
|
frames.append(mainFrame());
|
|
while (!frames.isEmpty()) {
|
|
QWebFrame *frame = frames.takeFirst();
|
|
if (frame->url() == reply->url()) {
|
|
frame->setHtml(html, reply->url());
|
|
return;
|
|
}
|
|
|
|
QList<QWebFrame *> children = frame->childFrames();
|
|
foreach (QWebFrame *frame, children)
|
|
frames.append(frame);
|
|
}
|
|
|
|
if (m_loadingUrl == reply->url())
|
|
mainFrame()->setHtml(html, reply->url());
|
|
}
|
|
|
|
|
|
// -- HelpViewer
|
|
|
|
HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
|
|
: QWebView(parent)
|
|
{
|
|
setAcceptDrops(false);
|
|
installEventFilter(this);
|
|
|
|
QWebSettings::globalSettings()->setAttribute(QWebSettings::JavaEnabled, true);
|
|
QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
|
|
QWebSettings::globalSettings()->setAttribute(QWebSettings::DnsPrefetchEnabled, true);
|
|
|
|
setPage(new HelpPage(this));
|
|
HelpNetworkAccessManager *manager = new HelpNetworkAccessManager(this);
|
|
page()->setNetworkAccessManager(manager);
|
|
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
|
|
SLOT(slotNetworkReplyFinished(QNetworkReply*)));
|
|
|
|
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(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()));
|
|
|
|
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 = LocalHelpManager::helpEngine();
|
|
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(qreal(0.0), textSizeMultiplier() - qreal(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, Find::FindFlags flags,
|
|
bool incremental, bool fromSearch, bool *wrapped)
|
|
{
|
|
Q_UNUSED(incremental);
|
|
Q_UNUSED(fromSearch);
|
|
if (wrapped)
|
|
*wrapped = false;
|
|
QWebPage::FindFlags options;
|
|
if (flags & Find::FindBackward)
|
|
options |= QWebPage::FindBackward;
|
|
if (flags & Find::FindCaseSensitively)
|
|
options |= QWebPage::FindCaseSensitively;
|
|
|
|
bool found = QWebView::findText(text, options);
|
|
if (!found) {
|
|
options |= QWebPage::FindWrapsAroundDocument;
|
|
found = QWebView::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
|
|
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::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);
|
|
}
|
|
|
|
#endif // !QT_NO_WEBKIT
|