Help: Unify help content loading and error message.

Task-number: QTCREATORBUG-12352
Change-Id: If74453e75cc8eaf27c114d0976099388be778fa6
Reviewed-by: Karsten Heimrich <karsten.heimrich@digia.com>
This commit is contained in:
Eike Ziller
2014-06-17 15:37:40 +02:00
parent 46cdd91024
commit be68fe7f4a
5 changed files with 115 additions and 122 deletions

View File

@@ -31,6 +31,7 @@
#include "bookmarkmanager.h"
#include "helpconstants.h"
#include "helpviewer.h"
#include <app/app_version.h>
#include <coreplugin/helpmanager.h>
@@ -55,6 +56,7 @@ LocalHelpManager::LocalHelpManager(QObject *parent)
, m_needsCollectionFile(true)
{
m_instance = this;
qRegisterMetaType<Help::Internal::LocalHelpManager::HelpData>("Help::Internal::LocalHelpManager::HelpData");
}
LocalHelpManager::~LocalHelpManager()
@@ -143,10 +145,85 @@ bool LocalHelpManager::isValidUrl(const QString &link)
|| scheme == QLatin1String("https"));
}
QByteArray LocalHelpManager::helpData(const QUrl &url)
QByteArray LocalHelpManager::loadErrorMessage(const QUrl &url, const QString &errorString)
{
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;}"
"p {font-size: 90%; margin-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>"
"%4"
"</div>"
"</body>"
"</html>";
// some of the values we will replace %1...6 inside the former html
const QString g_percent1 = QCoreApplication::translate("Help", "Error loading page");
// percent2 will be the error details
// percent3 will be the url of the page we got the error from
const QString g_percent4 = QCoreApplication::translate("Help", "<p>Check that you have the corresponding "
"documentation set installed.</p>");
return QString::fromLatin1(g_htmlPage).arg(g_percent1, errorString,
QCoreApplication::translate("Help", "Error loading: %1").arg(url.toString()),
g_percent4).toUtf8();
}
LocalHelpManager::HelpData LocalHelpManager::helpData(const QUrl &url)
{
HelpData data;
const QHelpEngineCore &engine = helpEngine();
return engine.findFile(url).isValid() ? engine.fileData(url)
: tr("Could not load \"%1\".").arg(url.toString()).toUtf8();
data.resolvedUrl = engine.findFile(url);
if (data.resolvedUrl.isValid()) {
data.data = engine.fileData(data.resolvedUrl);
data.mimeType = HelpViewer::mimeFromUrl(data.resolvedUrl);
if (data.mimeType.isEmpty())
data.mimeType = QLatin1String("application/octet-stream");
} else {
data.data = loadErrorMessage(url, QCoreApplication::translate(
"Help", "The page could not be found"));
data.mimeType = QLatin1String("text/html");
}
return data;
}

View File

@@ -32,20 +32,26 @@
#include <QMutex>
#include <QObject>
#include <QUrl>
QT_FORWARD_DECLARE_CLASS(QHelpEngine)
QT_FORWARD_DECLARE_CLASS(QUrl)
class BookmarkManager;
namespace Help {
namespace Internal {
namespace Internal {
class LocalHelpManager : public QObject
{
Q_OBJECT
public:
struct HelpData {
QUrl resolvedUrl;
QByteArray data;
QString mimeType;
};
LocalHelpManager(QObject *parent = 0);
~LocalHelpManager();
@@ -60,7 +66,8 @@ public:
static QVariant engineFontSettings();
static bool isValidUrl(const QString &link);
Q_INVOKABLE QByteArray helpData(const QUrl &url);
static QByteArray loadErrorMessage(const QUrl &url, const QString &errorString);
Q_INVOKABLE static Help::Internal::LocalHelpManager::HelpData helpData(const QUrl &url);
private:
bool m_guiNeedsSetup;
@@ -72,7 +79,10 @@ private:
static QMutex m_bkmarkMutex;
static BookmarkManager *m_bookmarkManager;
};
} // Internal
} // Internal
} // Help
Q_DECLARE_METATYPE(Help::Internal::LocalHelpManager::HelpData)
#endif // LOCALHELPMANAGER_H

View File

@@ -163,22 +163,19 @@ AutoreleasePool::~AutoreleasePool()
- (void)startLoading
{
const QUrl &url = QUrl::fromNSURL(self.request.URL);
QByteArray data;
Help::Internal::LocalHelpManager::HelpData data;
Help::Internal::LocalHelpManager *helpManager = Help::Internal::LocalHelpManager::instance();
QMetaObject::invokeMethod(helpManager, "helpData", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QByteArray, data), Q_ARG(QUrl, url));
Q_RETURN_ARG(Help::Internal::LocalHelpManager::HelpData, data),
Q_ARG(QUrl, url));
QString mtString = Help::Internal::HelpViewer::mimeFromUrl(url);
if (mtString.isEmpty())
mtString = QLatin1String("application/octet-stream");
NSString *mimeType = mtString.toNSString();
NSData *nsdata = QtMac::toNSData(data); // Qt 5.3 has this in QByteArray
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL
NSURL *resolvedURL = data.resolvedUrl.toNSURL();
NSString *mimeType = data.mimeType.toNSString();
NSData *nsdata = QtMac::toNSData(data.data); // Qt 5.3 has this in QByteArray
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:resolvedURL
MIMEType:mimeType
expectedContentLength:data.length()
expectedContentLength:data.data.length()
textEncodingName:@"UTF8"];
[self.client URLProtocol:self didReceiveResponse:response
cacheStoragePolicy:NSURLCacheStorageNotAllowed];

View File

@@ -66,52 +66,6 @@ using namespace Core;
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
@@ -182,16 +136,8 @@ QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op,
if (!HelpViewer::isLocalUrl(request.url()))
return Utils::NetworkAccessManager::createRequest(op, request, outgoingData);
QString url = request.url().toString();
const QHelpEngineCore &engine = LocalHelpManager::helpEngine();
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);
LocalHelpManager::HelpData data = LocalHelpManager::helpData(request.url());
return new HelpNetworkReply(request, data.data, data.mimeType);
}
// - HelpPage
@@ -266,7 +212,7 @@ void HelpPage::onHandleUnsupportedContent(QNetworkReply *reply)
}
// set a default error string we are going to display
QString errorString = HelpViewer::tr("Unknown or unsupported Content!");
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())) {
@@ -278,10 +224,8 @@ void HelpPage::onHandleUnsupportedContent(QNetworkReply *reply)
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);
const QString html = QString::fromUtf8(LocalHelpManager::loadErrorMessage(reply->url(),
errorString));
// update the current layout
QList<QWebFrame*> frames;
@@ -416,9 +360,8 @@ 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()));
setHtml(QString::fromUtf8(LocalHelpManager::loadErrorMessage(reply->url(),
reply->errorString())));
}
}

View File

@@ -122,36 +122,11 @@ QUrl TextBrowserHelpViewer::source() const
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;
}
}
if (launchWithExternalApp(url))
return;
slotLoadStarted();
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();
}
@@ -321,18 +296,9 @@ TextBrowserHelpWidget::TextBrowserHelpWidget(int zoom, TextBrowserHelpViewer *pa
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;
if (type < 4)
return LocalHelpManager::helpData(name).data;
return QByteArray();
}
bool TextBrowserHelpWidget::hasAnchorAt(const QPoint &pos)