Assistant: Factor out web browser support.
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Thu, 27 Nov 2014 15:19:02 +0000 (16:19 +0100)
committerFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Tue, 9 Dec 2014 11:07:11 +0000 (12:07 +0100)
Task-number: QTBUG-41130
Change-Id: Ia1d29b6eaa56e0f9eb569326e05f4c56411db6a7
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
src/assistant/assistant/assistant.pro
src/assistant/assistant/helpbrowsersupport.cpp [new file with mode: 0644]
src/assistant/assistant/helpbrowsersupport.h [new file with mode: 0644]
src/assistant/assistant/helpviewer_qwv.cpp

index 5f96377..a310302 100644 (file)
@@ -24,6 +24,7 @@ HEADERS += aboutdialog.h \
     findwidget.h \
     filternamedialog.h \
     helpenginewrapper.h \
+    helpbrowsersupport.h \
     helpviewer.h \
     helpviewer_p.h \
     indexwindow.h \
@@ -56,6 +57,7 @@ SOURCES += aboutdialog.cpp \
     findwidget.cpp \
     filternamedialog.cpp \
     helpenginewrapper.cpp \
+    helpbrowsersupport.cpp \
     helpviewer.cpp \
     indexwindow.cpp \
     main.cpp \
diff --git a/src/assistant/assistant/helpbrowsersupport.cpp b/src/assistant/assistant/helpbrowsersupport.cpp
new file mode 100644 (file)
index 0000000..81c0ab2
--- /dev/null
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "helpbrowsersupport.h"
+#include "helpenginewrapper.h"
+#include "helpviewer.h"
+#include "tracer.h"
+
+#include <QtHelp/QHelpEngineCore>
+
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QNetworkRequest>
+
+#include <QtCore/QTimer>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QUrl>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+// -- messages
+
+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\"><h1>%2</h1><h2>%3</h2><h2><b>%4</b></h2></div></body></html>";
+
+QString HelpBrowserSupport::msgError404()
+{
+    return QCoreApplication::translate("HelpViewer", "Error 404...");
+}
+
+QString HelpBrowserSupport::msgPageNotFound()
+{
+    return QCoreApplication::translate("HelpViewer", "The page could not be found!");
+}
+
+QString HelpBrowserSupport::msgAllDocumentationSets()
+{
+     return QCoreApplication::translate("HelpViewer",
+                                        "Please make sure that you have all "
+                                        "documentation sets installed.");
+}
+
+QString HelpBrowserSupport::msgLoadError(const QUrl &url)
+{
+    return HelpViewer::tr("Error loading: %1").arg(url.toString());
+}
+
+QString HelpBrowserSupport::msgHtmlErrorPage(const QUrl &url)
+{
+    return QString::fromLatin1(g_htmlPage)
+        .arg(HelpBrowserSupport::msgError404(), HelpBrowserSupport::msgPageNotFound(),
+             HelpBrowserSupport::msgLoadError(url), HelpBrowserSupport::msgAllDocumentationSets());
+}
+
+// A QNetworkAccessManager implementing unhandled URL schema handling for WebKit-type browsers.
+
+// -- 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;
+    const qint64 origLen;
+};
+
+HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request,
+        const QByteArray &fileData, const QString& mimeType)
+    : data(fileData), origLen(fileData.length())
+{
+    TRACE_OBJ
+    setRequest(request);
+    setUrl(request.url());
+    setOpenMode(QIODevice::ReadOnly);
+
+    setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
+    setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen));
+    QTimer::singleShot(0, this, &QNetworkReply::metaDataChanged);
+    QTimer::singleShot(0, this, &QNetworkReply::readyRead);
+    QTimer::singleShot(0, this, &QNetworkReply::finished);
+}
+
+void HelpNetworkReply::abort()
+{
+    TRACE_OBJ
+}
+
+qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
+{
+    TRACE_OBJ
+    qint64 len = qMin(qint64(data.length()), maxlen);
+    if (len) {
+        memcpy(buffer, data.constData(), len);
+        data.remove(0, len);
+    }
+    if (!data.length())
+        QTimer::singleShot(0, this, &QNetworkReply::finished);
+    return len;
+}
+
+// -- HelpRedirectNetworkReply
+
+class HelpRedirectNetworkReply : public QNetworkReply
+{
+public:
+    HelpRedirectNetworkReply(const QNetworkRequest &request, const QUrl &newUrl)
+    {
+        setRequest(request);
+        setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 301);
+        setAttribute(QNetworkRequest::RedirectionTargetAttribute, newUrl);
+
+        QTimer::singleShot(0, this, &QNetworkReply::finished);
+    }
+
+protected:
+    void abort() { TRACE_OBJ }
+    qint64 readData(char*, qint64) { TRACE_OBJ return qint64(-1); }
+};
+
+// -- 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)
+{
+    TRACE_OBJ
+}
+
+QNetworkReply *HelpNetworkAccessManager::createRequest(Operation, const QNetworkRequest &request, QIODevice*)
+{
+    TRACE_OBJ
+
+    QByteArray data;
+    const QUrl url = request.url();
+    QUrl redirectedUrl;
+    switch (HelpBrowserSupport::resolveUrl(url, &redirectedUrl, &data)) {
+    case HelpBrowserSupport::UrlRedirect:
+        return new HelpRedirectNetworkReply(request, redirectedUrl);
+    case HelpBrowserSupport::UrlLocalData: {
+        const QString mimeType = HelpViewer::mimeFromUrl(url);
+        return new HelpNetworkReply(request, data, mimeType);
+    }
+    case HelpBrowserSupport::UrlResolveError:
+        break;
+    }
+    return new HelpNetworkReply(request, HelpBrowserSupport::msgHtmlErrorPage(request.url()).toUtf8(),
+                                QStringLiteral("text/html"));
+}
+
+QByteArray HelpBrowserSupport::fileDataForLocalUrl(const QUrl &url)
+{
+    return HelpEngineWrapper::instance().fileData(url);
+}
+
+HelpBrowserSupport::ResolveUrlResult HelpBrowserSupport::resolveUrl(const QUrl &url,
+                                                                    QUrl *targetUrlP,
+                                                                    QByteArray *dataP)
+{
+    const HelpEngineWrapper &engine = HelpEngineWrapper::instance();
+
+    const QUrl targetUrl = engine.findFile(url);
+    if (!targetUrl.isValid())
+        return UrlResolveError;
+
+    if (targetUrl != url) {
+        if (targetUrlP)
+            *targetUrlP = targetUrl;
+        return UrlRedirect;
+    }
+
+    if (dataP)
+        *dataP = HelpBrowserSupport::fileDataForLocalUrl(targetUrl);
+    return UrlLocalData;
+}
+
+QNetworkAccessManager *HelpBrowserSupport::createNetworkAccessManager(QObject *parent)
+{
+    return new HelpNetworkAccessManager(parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/assistant/assistant/helpbrowsersupport.h b/src/assistant/assistant/helpbrowsersupport.h
new file mode 100644 (file)
index 0000000..3901b56
--- /dev/null
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HELPBROWSERSUPPORT_H
+#define HELPBROWSERSUPPORT_H
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkAccessManager;
+class QObject;
+class QString;
+class QByteArray;
+class QUrl;
+
+// Provide helper functions for feeding the QtHelp data stored in the help database
+// into various browsers.
+class HelpBrowserSupport
+{
+public:
+    enum ResolveUrlResult {
+        UrlRedirect,
+        UrlLocalData,
+        UrlResolveError
+    };
+
+    static QString msgError404();
+    static QString msgPageNotFound();
+    static QString msgAllDocumentationSets();
+    static QString msgLoadError(const QUrl &url);
+    static QString msgHtmlErrorPage(const QUrl &url);
+
+    static ResolveUrlResult resolveUrl(const QUrl &url, QUrl *targetUrl,
+                                       QByteArray *data);
+    static QByteArray fileDataForLocalUrl(const QUrl &url);
+
+    // Create an instance of QNetworkAccessManager for WebKit-type browsers.
+    static QNetworkAccessManager *createNetworkAccessManager(QObject *parent = 0);
+};
+
+QT_END_NAMESPACE
+
+#endif // HELPBROWSERSUPPORT_H
index 427f3ad..79a3d55 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "centralwidget.h"
 #include "helpenginewrapper.h"
+#include "helpbrowsersupport.h"
 #include "openpagesmanager.h"
 #include "tracer.h"
 
 #include <QtWidgets/QApplication>
 #include <QtGui/QWheelEvent>
 
-#include <QtHelp/QHelpEngineCore>
-
-#include <QtNetwork/QNetworkAccessManager>
 #include <QtNetwork/QNetworkReply>
-#include <QtNetwork/QNetworkRequest>
 
 QT_BEGIN_NAMESPACE
 
-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\"><h1>%2</h1><h2>%3</h2><h2><b>%4</b></h2></div></body></html>";
-
-// some of the values we will replace %1...4 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", "Please make sure that you have all "
-    "documentation sets installed.");
-
-
-// -- 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())
-{
-    TRACE_OBJ
-    setRequest(request);
-    setUrl(request.url());
-    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()));
-    QTimer::singleShot(0, this, SIGNAL(finished()));
-}
-
-void HelpNetworkReply::abort()
-{
-    TRACE_OBJ
-}
-
-qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
-{
-    TRACE_OBJ
-    qint64 len = qMin(qint64(data.length()), maxlen);
-    if (len) {
-        memcpy(buffer, data.constData(), len);
-        data.remove(0, len);
-    }
-    if (!data.length())
-        QTimer::singleShot(0, this, SIGNAL(finished()));
-    return len;
-}
-
-// -- HelpRedirectNetworkReply
-
-class HelpRedirectNetworkReply : public QNetworkReply
-{
-public:
-    HelpRedirectNetworkReply(const QNetworkRequest &request, const QUrl &newUrl)
-    {
-        setRequest(request);
-        setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 301);
-        setAttribute(QNetworkRequest::RedirectionTargetAttribute, newUrl);
-
-        QTimer::singleShot(0, this, SIGNAL(finished()));
-    }
-
-protected:
-    void abort() { TRACE_OBJ }
-    qint64 readData(char*, qint64) { TRACE_OBJ return qint64(-1); }
-};
-
-// -- 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)
-{
-    TRACE_OBJ
-}
-
-QNetworkReply *HelpNetworkAccessManager::createRequest(Operation, const QNetworkRequest &request, QIODevice*)
-{
-    TRACE_OBJ
-    const HelpEngineWrapper &engine = HelpEngineWrapper::instance();
-
-    const QUrl url = engine.findFile(request.url());
-    if (url.isValid() && (url != request.url()))
-        return new HelpRedirectNetworkReply(request, url);
-
-    if (url.isValid())
-        return new HelpNetworkReply(request, engine.fileData(url), HelpViewer::mimeFromUrl(url));
-
-    return new HelpNetworkReply(request, QString::fromLatin1(g_htmlPage).arg(g_percent1, g_percent2,
-        HelpViewer::tr("Error loading: %1").arg(request.url().toString()), g_percent4).toUtf8(),
-        QLatin1String("text/html"));
-}
-
 // -- HelpPage
 
 class HelpPage : public QWebPage
@@ -283,7 +155,7 @@ HelpViewer::HelpViewer(qreal zoom, QWidget *parent)
     settings()->setAttribute(QWebSettings::PluginsEnabled, false);
 
     setPage(new HelpPage(this));
-    page()->setNetworkAccessManager(new HelpNetworkAccessManager(this));
+    page()->setNetworkAccessManager(HelpBrowserSupport::createNetworkAccessManager(this));
 
     QAction* action = pageAction(QWebPage::OpenLinkInNewWindow);
     action->setText(tr("Open Link in New Page"));