/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "browserapplication.h"#include "bookmarks.h"#include "browsermainwindow.h"#include "cookiejar.h"#include "downloadmanager.h"#include "history.h"#include "tabwidget.h"#include "webview.h"#include <QtCore/QBuffer>#include <QtCore/QDir>#include <QtCore/QLibraryInfo>#include <QtCore/QSettings>#include <QtCore/QTextStream>#include <QtCore/QTranslator>#include <QtGui/QDesktopServices>#include <QtGui/QFileOpenEvent>#include <QtWidgets/QMessageBox>#include <QtNetwork/QLocalServer>#include <QtNetwork/QLocalSocket>#include <QtNetwork/QNetworkProxy>#include <QtNetwork/QSslSocket>#include <QWebEngineProfile>#include <QWebEngineSettings>#include <QWebEngineScript>#include <QWebEngineScriptCollection>#include <QtCore/QDebug>
DownloadManager *BrowserApplication::s_downloadManager =0;
HistoryManager *BrowserApplication::s_historyManager =0;
QNetworkAccessManager*BrowserApplication::s_networkAccessManager =0;
BookmarksManager *BrowserApplication::s_bookmarksManager =0;
staticvoid setUserStyleSheet(QWebEngineProfile*profile,constQString&styleSheet, BrowserMainWindow *mainWindow =0)
{
Q_ASSERT(profile);
QString scriptName(QStringLiteral("userStyleSheet"));
QWebEngineScript script;
QList<QWebEngineScript> styleSheets = profile->scripts()->findScripts(scriptName);
if (!styleSheets.isEmpty())
script = styleSheets.first();
Q_FOREACH (constQWebEngineScript&s, styleSheets)
profile->scripts()->remove(s);
if (script.isNull()) {
script.setName(scriptName);
script.setInjectionPoint(QWebEngineScript::DocumentReady);
script.setRunsOnSubFrames(true);
script.setWorldId(QWebEngineScript::ApplicationWorld);
}
QString source =QString::fromLatin1("(function() {"\
"var css = document.getElementById(\"_qt_testBrowser_userStyleSheet\");"\
"if (css == undefined) {"\
" css = document.createElement(\"style\");"\
" css.type = \"text/css\";"\
" css.id = \"_qt_testBrowser_userStyleSheet\";"\
" document.head.appendChild(css);"\
"}"\
"css.innerText = \"%1\";"\
"})()").arg(styleSheet);
script.setSourceCode(source);
profile->scripts()->insert(script);
// run the script on the already loaded views// this has to be deferred as it could mess with the storage initialization on startupif (mainWindow)
QMetaObject::invokeMethod(mainWindow,"runScriptOnOpenViews",Qt::QueuedConnection, Q_ARG(QString, source));
}
BrowserApplication::BrowserApplication(int&argc,char**argv)
: QApplication(argc, argv)
, m_localServer(0)
, m_privateProfile(0)
, m_privateBrowsing(false)
{
QCoreApplication::setOrganizationName(QLatin1String("Qt"));
QCoreApplication::setApplicationName(QLatin1String("demobrowser"));
QCoreApplication::setApplicationVersion(QLatin1String("0.1"));
QString serverName =QCoreApplication::applicationName()
+QString::fromLatin1(QT_VERSION_STR).remove('.') + QLatin1String("webengine");
QLocalSocket socket;
socket.connectToServer(serverName);
if (socket.waitForConnected(500)) {
QTextStream stream(&socket);
stream << getCommandLineUrlArgument();
stream.flush();
socket.waitForBytesWritten();
return;
}
#if defined(Q_OS_OSX)QApplication::setQuitOnLastWindowClosed(false);
#elseQApplication::setQuitOnLastWindowClosed(true);
#endif
m_localServer =newQLocalServer(this);
connect(m_localServer, SIGNAL(newConnection()),this, SLOT(newLocalSocketConnection()));
if (!m_localServer->listen(serverName)
&& m_localServer->serverError() ==QAbstractSocket::AddressInUseError) {
QLocalServer::removeServer(serverName);
if (!m_localServer->listen(serverName))
qWarning("Could not create local socket %s.",qPrintable(serverName));
}
#ifndef QT_NO_OPENSSLif (!QSslSocket::supportsSsl()) {
QMessageBox::information(0,"Demo Browser","This system does not support OpenSSL. SSL websites will not be available.");
}
#endifQDesktopServices::setUrlHandler(QLatin1String("http"),this,"openUrl");
QString localSysName =QLocale::system().name();
installTranslator(QLatin1String("qt_") + localSysName);
QSettings settings;
settings.beginGroup(QLatin1String("sessions"));
m_lastSession = settings.value(QLatin1String("lastSession")).toByteArray();
settings.endGroup();
#if defined(Q_OS_OSX)
connect(this, SIGNAL(lastWindowClosed()),this, SLOT(lastWindowClosed()));
#endifQTimer::singleShot(0,this, SLOT(postLaunch()));
}
BrowserApplication::~BrowserApplication()
{
delete s_downloadManager;
for (int i =0; i < m_mainWindows.size(); ++i) {
BrowserMainWindow *window = m_mainWindows.at(i);
delete window;
}
delete s_networkAccessManager;
delete s_bookmarksManager;
}
void BrowserApplication::lastWindowClosed()
{
#if defined(Q_OS_OSX)
clean();
BrowserMainWindow *mw =new BrowserMainWindow;
mw->slotHome();
m_mainWindows.prepend(mw);
#endif
}
BrowserApplication *BrowserApplication::instance()
{
return (static_cast<BrowserApplication *>(QCoreApplication::instance()));
}
void BrowserApplication::quitBrowser()
{
#if defined(Q_OS_OSX)
clean();
int tabCount =0;
for (int i =0; i < m_mainWindows.count(); ++i) {
tabCount += m_mainWindows.at(i)->tabWidget()->count();
}
if (tabCount >1) {
int ret =QMessageBox::warning(mainWindow(),QString(),
tr("There are %1 windows and %2 tabs open\n""Do you want to quit anyway?").arg(m_mainWindows.count()).arg(tabCount),QMessageBox::Yes |QMessageBox::No,QMessageBox::No);
if (ret ==QMessageBox::No)
return;
}
exit(0);
#endif
}
/*!
Any actions that can be delayed until the window is visible
*/void BrowserApplication::postLaunch()
{
QString directory =QStandardPaths::writableLocation(QStandardPaths::DataLocation);
if (directory.isEmpty())
directory =QDir::homePath() + QLatin1String("/.") +QCoreApplication::applicationName();
#if defined(QWEBENGINESETTINGS_PATHS)QWebEngineSettings::setIconDatabasePath(directory);
QWebEngineSettings::setOfflineStoragePath(directory);
#endif
setWindowIcon(QIcon(QLatin1String(":demobrowser.svg")));
loadSettings();
// newMainWindow() needs to be called in main() for this to happenif (m_mainWindows.count() >0) {
constQString url = getCommandLineUrlArgument();
if (!url.isEmpty()) {
mainWindow()->loadPage(url);
} else {
mainWindow()->slotHome();
}
}
BrowserApplication::historyManager();
}
void BrowserApplication::loadSettings()
{
QSettings settings;
settings.beginGroup(QLatin1String("websettings"));
QWebEngineSettings*defaultSettings =QWebEngineSettings::globalSettings();
QWebEngineProfile*defaultProfile =QWebEngineProfile::defaultProfile();
QString standardFontFamily = defaultSettings->fontFamily(QWebEngineSettings::StandardFont);
int standardFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFontSize);
QFont standardFont =QFont(standardFontFamily, standardFontSize);
standardFont = qvariant_cast<QFont>(settings.value(QLatin1String("standardFont"), standardFont));
defaultSettings->setFontFamily(QWebEngineSettings::StandardFont, standardFont.family());
defaultSettings->setFontSize(QWebEngineSettings::DefaultFontSize, standardFont.pointSize());
QString fixedFontFamily = defaultSettings->fontFamily(QWebEngineSettings::FixedFont);
int fixedFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFixedFontSize);
QFont fixedFont =QFont(fixedFontFamily, fixedFontSize);
fixedFont = qvariant_cast<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont));
defaultSettings->setFontFamily(QWebEngineSettings::FixedFont, fixedFont.family());
defaultSettings->setFontSize(QWebEngineSettings::DefaultFixedFontSize, fixedFont.pointSize());
defaultSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"),true).toBool());
defaultSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value(QLatin1String("enableScrollAnimator"),true).toBool());
defaultSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"),true).toBool());
defaultSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled,true);
QString css = settings.value(QLatin1String("userStyleSheet")).toString();
setUserStyleSheet(defaultProfile, css, mainWindow());
defaultProfile->setHttpUserAgent(settings.value(QLatin1String("httpUserAgent")).toString());
defaultProfile->setHttpAcceptLanguage(settings.value(QLatin1String("httpAcceptLanguage")).toString());
switch (settings.value(QLatin1String("faviconDownloadMode"),1).toInt()) {
case0:
defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage,false);
break;
case1:
defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage,true);
defaultSettings->setAttribute(QWebEngineSettings::TouchIconsEnabled,false);
break;
case2:
defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage,true);
defaultSettings->setAttribute(QWebEngineSettings::TouchIconsEnabled,true);
break;
}
settings.endGroup();
settings.beginGroup(QLatin1String("cookies"));
QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy =QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy"),QWebEngineProfile::AllowPersistentCookies).toInt());
defaultProfile->setPersistentCookiesPolicy(persistentCookiesPolicy);
QString pdataPath = settings.value(QLatin1String("persistentDataPath")).toString();
defaultProfile->setPersistentStoragePath(pdataPath);
settings.endGroup();
settings.beginGroup(QLatin1String("proxy"));
QNetworkProxy proxy;
if (settings.value(QLatin1String("enabled"),false).toBool()) {
if (settings.value(QLatin1String("type"),0).toInt() ==0)
proxy =QNetworkProxy::Socks5Proxy;
else
proxy =QNetworkProxy::HttpProxy;
proxy.setHostName(settings.value(QLatin1String("hostName")).toString());
proxy.setPort(settings.value(QLatin1String("port"),1080).toInt());
proxy.setUser(settings.value(QLatin1String("userName")).toString());
proxy.setPassword(settings.value(QLatin1String("password")).toString());
QNetworkProxy::setApplicationProxy(proxy);
}
settings.endGroup();
}
QList<BrowserMainWindow*> BrowserApplication::mainWindows()
{
clean();
QList<BrowserMainWindow*> list;
for (int i =0; i < m_mainWindows.count(); ++i)
list.append(m_mainWindows.at(i));
return list;
}
void BrowserApplication::clean()
{
// cleanup any deleted main windows firstfor (int i = m_mainWindows.count() -1; i >=0; --i)
if (m_mainWindows.at(i).isNull())
m_mainWindows.removeAt(i);
}
void BrowserApplication::saveSession()
{
if (m_privateBrowsing)
return;
clean();
QSettings settings;
settings.beginGroup(QLatin1String("sessions"));
QByteArray data;
QBuffer buffer(&data);
QDataStream stream(&buffer);
buffer.open(QIODevice::ReadWrite);
stream << m_mainWindows.count();
for (int i =0; i < m_mainWindows.count(); ++i)
stream << m_mainWindows.at(i)->saveState();
settings.setValue(QLatin1String("lastSession"), data);
settings.endGroup();
}
bool BrowserApplication::canRestoreSession() const
{
return!m_lastSession.isEmpty();
}
void BrowserApplication::restoreLastSession()
{
QList<QByteArray> windows;
QBuffer buffer(&m_lastSession);
QDataStream stream(&buffer);
buffer.open(QIODevice::ReadOnly);
int windowCount;
stream >> windowCount;
for (int i =0; i < windowCount; ++i) {
QByteArray windowState;
stream >> windowState;
windows.append(windowState);
}
for (int i =0; i < windows.count(); ++i) {
BrowserMainWindow *newWindow =0;
if (m_mainWindows.count() ==1&& mainWindow()->tabWidget()->count() ==1&& mainWindow()->currentTab()->url() ==QUrl()) {
newWindow = mainWindow();
} else {
newWindow = newMainWindow();
}
newWindow->restoreState(windows.at(i));
}
}
bool BrowserApplication::isTheOnlyBrowser() const
{
return (m_localServer !=0);
}
void BrowserApplication::installTranslator(constQString&name)
{
QTranslator*translator =newQTranslator(this);
translator->load(name,QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QApplication::installTranslator(translator);
}
QString BrowserApplication::getCommandLineUrlArgument() const
{
constQStringList args =QCoreApplication::arguments();
if (args.count() >1) {
constQString lastArg = args.last();
const bool isValidUrl =QUrl::fromUserInput(lastArg).isValid();
if (isValidUrl)
return lastArg;
}
returnQString();
}
#if defined(Q_OS_OSX)
bool BrowserApplication::event(QEvent* event)
{
switch (event->type()) {
caseQEvent::ApplicationActivate: {
clean();
if (!m_mainWindows.isEmpty()) {
BrowserMainWindow *mw = mainWindow();
if (mw &&!mw->isMinimized()) {
mainWindow()->show();
}
returntrue;
}
}
caseQEvent::FileOpen:
if (!m_mainWindows.isEmpty()) {
mainWindow()->loadPage(static_cast<QFileOpenEvent*>(event)->file());
returntrue;
}
default:
break;
}
returnQApplication::event(event);
}
#endifvoid BrowserApplication::openUrl(constQUrl&url)
{
mainWindow()->loadPage(url.toString());
}
BrowserMainWindow *BrowserApplication::newMainWindow()
{
BrowserMainWindow *browser =new BrowserMainWindow();
m_mainWindows.prepend(browser);
browser->show();
return browser;
}
BrowserMainWindow *BrowserApplication::mainWindow()
{
clean();
if (m_mainWindows.isEmpty())
newMainWindow();
return m_mainWindows[0];
}
void BrowserApplication::newLocalSocketConnection()
{
QLocalSocket*socket = m_localServer->nextPendingConnection();
if (!socket)
return;
socket->waitForReadyRead(1000);
QTextStream stream(socket);
QString url;
stream >> url;
if (!url.isEmpty()) {
QSettings settings;
settings.beginGroup(QLatin1String("general"));
int openLinksIn = settings.value(QLatin1String("openLinksIn"),0).toInt();
settings.endGroup();
if (openLinksIn ==1)
newMainWindow();
else
mainWindow()->tabWidget()->newTab();
openUrl(url);
}
delete socket;
mainWindow()->raise();
mainWindow()->activateWindow();
}
CookieJar *BrowserApplication::cookieJar()
{
#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER)return (CookieJar*)networkAccessManager()->cookieJar();
#elsereturn0;
#endif
}
DownloadManager *BrowserApplication::downloadManager()
{
if (!s_downloadManager) {
s_downloadManager =new DownloadManager();
}
return s_downloadManager;
}
QNetworkAccessManager*BrowserApplication::networkAccessManager()
{
if (!s_networkAccessManager) {
s_networkAccessManager =newQNetworkAccessManager();
}
return s_networkAccessManager;
}
HistoryManager *BrowserApplication::historyManager()
{
if (!s_historyManager)
s_historyManager =new HistoryManager();
return s_historyManager;
}
BookmarksManager *BrowserApplication::bookmarksManager()
{
if (!s_bookmarksManager) {
s_bookmarksManager =new BookmarksManager;
}
return s_bookmarksManager;
}
QIcon BrowserApplication::icon(constQUrl&url) const
{
#if defined(QTWEBENGINE_ICONDATABASE)QIcon icon =QWebEngineSettings::iconForUrl(url);
if (!icon.isNull())
return icon.pixmap(16,16);
#else
Q_UNUSED(url);
#endifreturn defaultIcon();
}
QIcon BrowserApplication::defaultIcon() const
{
if (m_defaultIcon.isNull())
m_defaultIcon =QIcon(QLatin1String(":defaulticon.png"));
return m_defaultIcon;
}
void BrowserApplication::setPrivateBrowsing(bool privateBrowsing)
{
if (m_privateBrowsing == privateBrowsing)
return;
m_privateBrowsing = privateBrowsing;
if (privateBrowsing) {
if (!m_privateProfile)
m_privateProfile =newQWebEngineProfile(this);
Q_FOREACH (BrowserMainWindow* window, mainWindows()) {
window->tabWidget()->setProfile(m_privateProfile);
}
} else {
Q_FOREACH (BrowserMainWindow* window, mainWindows()) {
window->tabWidget()->setProfile(QWebEngineProfile::defaultProfile());
window->m_lastSearch =QString();
window->tabWidget()->clear();
}
}
emit privateBrowsingChanged(privateBrowsing);
}