Files
create/src/Mod/Web/Gui/BrowserView.cpp
2022-11-03 12:54:34 +01:00

908 lines
30 KiB
C++

/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
# include <QDesktopServices>
# include <QFileInfo>
# include <QLatin1String>
# include <QLineEdit>
# include <QMenu>
# include <QMessageBox>
# include <QMouseEvent>
# include <QNetworkRequest>
# include <QRegularExpression>
# include <QRegularExpressionMatch>
# include <QScreen>
# include <QSignalMapper>
# include <QStatusBar>
#endif
#if defined(QTWEBENGINE)
# if QT_VERSION < QT_VERSION_CHECK(6,0,0)
# include <QWebEngineContextMenuData>
# else
# include <QWebEngineContextMenuRequest>
# endif
# include <QWebEnginePage>
# include <QWebEngineProfile>
# include <QWebEngineSettings>
# include <QWebEngineUrlRequestInfo>
# include <QWebEngineUrlRequestInterceptor>
# include <QWebEngineView>
#elif defined(QTWEBKIT)
# include <QWebFrame>
# include <QNetworkAccessManager>
# include <QWebSettings>
# include <QWebView>
using QWebEngineView = QWebView;
using QWebEnginePage = QWebPage;
#endif
#include <App/Document.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/DownloadManager.h>
#include <Gui/MainWindow.h>
#include <Gui/MDIViewPy.h>
#include <Gui/ProgressBar.h>
#include <Gui/TextDocumentEditorView.h>
#include "BrowserView.h"
#include "CookieJar.h"
using namespace WebGui;
using namespace Gui;
namespace WebGui {
enum WebAction {
OpenLink = 0,
OpenLinkInNewWindow = 1,
ViewSource = 2 // QWebView doesn't have a ViewSource option
};
#ifdef QTWEBENGINE
class WebEngineUrlRequestInterceptor : public QWebEngineUrlRequestInterceptor
{
public:
explicit WebEngineUrlRequestInterceptor(BrowserView *parent) :
QWebEngineUrlRequestInterceptor(parent),
m_parent(parent)
{
}
void interceptRequest(QWebEngineUrlRequestInfo &info) override
{
// do something with this resource, click or get img for example
if (info.navigationType() == QWebEngineUrlRequestInfo::NavigationTypeLink) {
// wash out windows file:///C:/something ->file://C:/something
QUrl url = info.requestUrl();
QRegularExpression re(QLatin1String("^/([a-zA-Z]\\:.*)")); // match & catch drive letter forward
QRegularExpressionMatch match = re.match(url.path());
if (url.host().isEmpty() && url.isLocalFile() && match.hasMatch())
// clip / in file urs ie /C:/something -> C:/something
url.setPath(match.captured(1));
// invoke thread safe.
QMetaObject::invokeMethod(m_parent, "urlFilter", Q_ARG(QUrl, url));
}
}
private:
BrowserView *m_parent;
};
#endif
// ---------------------------------------------------------------------------------------------
UrlWidget::UrlWidget(BrowserView *view) :
QLineEdit(view), m_view(view)
{
setText(QLatin1String("https://"));
hide();
}
UrlWidget::~UrlWidget()
{
}
void UrlWidget::keyPressEvent(QKeyEvent *keyEvt)
{
switch (keyEvt->key()) {
case Qt::Key_Escape:
hide();
break;
case Qt::Key_Return:
case Qt::Key_Enter:
m_view->load(text().toLatin1());
hide();
break;
default:
QLineEdit::keyPressEvent(keyEvt);
}
}
void UrlWidget::display()
{
setFixedWidth(m_view->size().width());
setText(m_view->url().toString());
show();
setFocus(Qt::ActiveWindowFocusReason);
}
// ---------------------------------------------------------------------------------------------
class BrowserViewPy : public Py::PythonExtension<BrowserViewPy>
{
public:
using BaseType = Py::PythonExtension<BrowserViewPy>;
static void init_type(); // announce properties and methods
explicit BrowserViewPy(BrowserView* view);
~BrowserViewPy() override;
Py::Object repr() override;
Py::Object getattr(const char *) override;
Py::Object cast_to_base(const Py::Tuple&);
Py::Object setHtml(const Py::Tuple&);
Py::Object load(const Py::Tuple&);
Py::Object stop(const Py::Tuple&);
Py::Object url(const Py::Tuple&);
BrowserView* getBrowserViewPtr();
private:
Gui::MDIViewPy base;
};
void BrowserViewPy::init_type()
{
behaviors().name("BrowserView");
behaviors().doc("Python interface class to BrowserView");
// you must have overwritten the virtual functions
behaviors().supportRepr();
behaviors().supportGetattr();
behaviors().supportSetattr();
behaviors().readyType();
add_varargs_method("setHtml",&BrowserViewPy::setHtml,"setHtml(str)");
add_varargs_method("load",&BrowserViewPy::load,"load(url)");
add_varargs_method("stop",&BrowserViewPy::stop,"stop()");
add_varargs_method("url",&BrowserViewPy::url,"url()");
add_varargs_method("cast_to_base", &BrowserViewPy::cast_to_base, "cast_to_base() cast to MDIView class");
}
BrowserViewPy::BrowserViewPy(BrowserView* view) : base(view)
{
}
BrowserViewPy::~BrowserViewPy()
{
}
BrowserView* BrowserViewPy::getBrowserViewPtr()
{
return qobject_cast<BrowserView*>(base.getMDIViewPtr());
}
Py::Object BrowserViewPy::cast_to_base(const Py::Tuple&)
{
return Gui::MDIViewPy::create(base.getMDIViewPtr());
}
Py::Object BrowserViewPy::repr()
{
std::stringstream s;
s << "<BrowserView at " << this << ">";
return Py::String(s.str());
}
// Since with PyCXX it's not possible to make a sub-class of MDIViewPy
// a trick is to use MDIViewPy as class member and override getattr() to
// join the attributes of both classes. This way all methods of MDIViewPy
// appear for SheetViewPy, too.
Py::Object BrowserViewPy::getattr(const char * attr)
{
if (!getBrowserViewPtr()) {
std::ostringstream s_out;
s_out << "Cannot access attribute '" << attr << "' of deleted object";
throw Py::RuntimeError(s_out.str());
}
std::string name( attr );
if (name == "__dict__" || name == "__class__") {
Py::Dict dict_self(BaseType::getattr("__dict__"));
Py::Dict dict_base(base.getattr("__dict__"));
for (const auto& it : dict_base) {
dict_self.setItem(it.first, it.second);
}
return dict_self;
}
try {
return BaseType::getattr(attr);
}
catch (Py::AttributeError& e) {
e.clear();
return base.getattr(attr);
}
}
Py::Object BrowserViewPy::setHtml(const Py::Tuple& args)
{
char* HtmlCode;
char* BaseUrl;
if (!PyArg_ParseTuple(args.ptr(), "et|s","utf-8",&HtmlCode,&BaseUrl))
throw Py::Exception();
std::string EncodedHtml = std::string(HtmlCode);
PyMem_Free(HtmlCode);
getBrowserViewPtr()->setHtml(QString::fromUtf8(EncodedHtml.c_str()), QUrl(QString::fromUtf8(BaseUrl)));
return Py::None();
}
Py::Object BrowserViewPy::load(const Py::Tuple& args)
{
char* BaseUrl;
if (!PyArg_ParseTuple(args.ptr(), "s", &BaseUrl))
throw Py::Exception();
getBrowserViewPtr()->load(BaseUrl);
return Py::None();
}
Py::Object BrowserViewPy::stop(const Py::Tuple& args)
{
if (!PyArg_ParseTuple(args.ptr(), ""))
throw Py::Exception();
getBrowserViewPtr()->stop();
return Py::None();
}
Py::Object BrowserViewPy::url(const Py::Tuple& args)
{
if (!PyArg_ParseTuple(args.ptr(), ""))
throw Py::Exception();
QUrl url = getBrowserViewPtr()->url();
return Py::String(url.toString().toStdString());
}
}
/**
* Constructs a WebView widget which can be zoomed with Ctrl+Mousewheel
*
*/
WebView::WebView(QWidget *parent)
: QWebEngineView(parent)
{
#ifdef QTWEBKIT
// Increase html font size for high DPI displays
QRect mainScreenSize = QApplication::primaryScreen()->geometry();
if (mainScreenSize.width() > 1920){
setTextSizeMultiplier (mainScreenSize.width()/1920.0);
}
#endif
}
void WebView::mousePressEvent(QMouseEvent *event)
{
#ifdef QTWEBKIT
if (event->button() == Qt::MiddleButton) {
QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
if (!r.linkUrl().isEmpty()) {
openLinkInNewWindow(r.linkUrl());
return;
}
}
#endif
QWebEngineView::mousePressEvent(event);
}
void WebView::wheelEvent(QWheelEvent *event)
{
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
qreal factor = zoomFactor() + (-event->angleDelta().y() / 800.0);
setZoomFactor(factor);
event->accept();
return;
}
QWebEngineView::wheelEvent(event);
}
void WebView::contextMenuEvent(QContextMenuEvent *event)
{
#ifdef QTWEBENGINE
# if QT_VERSION < QT_VERSION_CHECK(6,0,0)
const QWebEngineContextMenuData r = page()->contextMenuData();
QUrl linkUrl = r.linkUrl();
# else
const QWebEngineContextMenuRequest* r = this->lastContextMenuRequest();
QUrl linkUrl = r->linkUrl();
# endif
#else
QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
QUrl linkUrl = r.linkUrl();
#endif
if (!linkUrl.isEmpty()) {
QMenu menu(this);
// building a custom signal for external browser action
QSignalMapper* signalMapper = new QSignalMapper (&menu);
signalMapper->setProperty("url", QVariant(linkUrl));
connect(signalMapper, SIGNAL(mapped(int)),
this, SLOT(triggerContextMenuAction(int)));
QAction* extAction = menu.addAction(tr("Open in External Browser"));
connect (extAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
signalMapper->setMapping(extAction, WebAction::OpenLink);
QAction* newAction = menu.addAction(tr("Open in new window"));
connect (newAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
signalMapper->setMapping(newAction, WebAction::OpenLinkInNewWindow);
menu.addAction(pageAction(QWebEnginePage::DownloadLinkToDisk));
menu.addAction(pageAction(QWebEnginePage::CopyLinkToClipboard));
menu.exec(mapToGlobal(event->pos()));
return;
}
#if defined(QTWEBENGINE)
else { // for view source
// QWebEngine caches standardContextMenu, guard so we only add signalmapper once
static bool firstRun = true;
if (firstRun) {
firstRun = false;
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
QMenu *menu = page()->createStandardContextMenu();
#else
QMenu *menu = this->createStandardContextMenu();
#endif
QList<QAction *> actions = menu->actions();
for(QAction *ac : actions) {
if (ac->data().toInt() == WebAction::ViewSource) {
QSignalMapper* signalMapper = new QSignalMapper (this);
signalMapper->setProperty("url", QVariant(linkUrl));
signalMapper->setMapping(ac, WebAction::ViewSource);
connect(signalMapper, SIGNAL(mapped(int)),
this, SLOT(triggerContextMenuAction(int)));
connect (ac, SIGNAL(triggered()), signalMapper, SLOT(map()));
}
}
}
}
#else
else {
QMenu *menu = page()->createStandardContextMenu();
QAction *ac = menu->addAction(tr("View source"));
ac->setData(WebAction::ViewSource);
QSignalMapper* signalMapper = new QSignalMapper (this);
signalMapper->setProperty("url", QVariant(linkUrl));
signalMapper->setMapping(ac, WebAction::ViewSource);
connect(signalMapper, SIGNAL(mapped(int)),
this, SLOT(triggerContextMenuAction(int)));
connect (ac, SIGNAL(triggered()), signalMapper, SLOT(map()));
menu->exec(event->globalPos());
}
#endif
QWebEngineView::contextMenuEvent(event);
}
void WebView::triggerContextMenuAction(int id)
{
QObject* s = sender();
QUrl url = s->property("url").toUrl();
switch (id) {
case WebAction::OpenLink:
Q_EMIT openLinkInExternalBrowser(url);
break;
case WebAction::OpenLinkInNewWindow:
Q_EMIT openLinkInNewWindow(url);
break;
case WebAction::ViewSource:
Q_EMIT viewSource(url);
break;
default:
break;
}
}
// ------------------------------------------------------------------------
/* TRANSLATOR Gui::BrowserView */
TYPESYSTEM_SOURCE_ABSTRACT(WebGui::BrowserView, Gui::MDIView)
/**
* Constructs a BrowserView which is a child of 'parent', with the
* name 'name'.
*/
BrowserView::BrowserView(QWidget* parent)
: MDIView(nullptr,parent,Qt::WindowFlags()),
WindowParameter( "Browser" ),
isLoading(false)
{
#if defined(QTWEBENGINE)
// Otherwise cause crash on exit, probably due to double deletion
setAttribute(Qt::WA_DeleteOnClose,false);
#endif
view = new WebView(this);
setCentralWidget(view);
view->setAttribute(Qt::WA_OpaquePaintEvent, true);
urlWgt = new UrlWidget(this);
#ifdef QTWEBKIT
textSizeMultiplier = 1.0;
view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
view->page()->setForwardUnsupportedContent(true);
// set our custom cookie manager
FcCookieJar* cookiejar = new FcCookieJar(this);
view->page()->networkAccessManager()->setCookieJar(cookiejar);
// enable local storage so we can store stuff across sessions (startpage)
QWebSettings* settings = view->settings();
settings->setAttribute(QWebSettings::LocalStorageEnabled, true);
settings->setLocalStoragePath(QString::fromUtf8((App::Application::getUserAppDataDir()+"webdata").c_str()));
// setting background to white
QPalette palette = view->palette();
palette.setBrush(QPalette::Base, Qt::white);
view->page()->setPalette(palette);
connect(view->page(), SIGNAL(linkHovered(const QString &, const QString &, const QString &)),
this, SLOT(onLinkHovered(const QString &, const QString &, const QString &)));
connect(view, SIGNAL(linkClicked(const QUrl &)),
this, SLOT(urlFilter(const QUrl &)));
connect(view->page(), SIGNAL(downloadRequested(const QNetworkRequest &)),
this, SLOT(onDownloadRequested(const QNetworkRequest &)));
connect(view->page(), SIGNAL(unsupportedContent(QNetworkReply*)),
this, SLOT(onUnsupportedContent(QNetworkReply*)));
#else // QTWEBENGINE
// QWebEngine doesn't support direct access to network
// nor rendering access
QWebEngineProfile *profile = view->page()->profile();
QString basePath = QString::fromStdString(App::Application::getUserAppDataDir()) + QLatin1String("webdata/");
profile->setPersistentStoragePath(basePath + QLatin1String("persistent"));
profile->setCachePath(basePath + QLatin1String("cache"));
interceptLinks = new WebEngineUrlRequestInterceptor(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
profile->setUrlRequestInterceptor(interceptLinks);
#else
profile->setRequestInterceptor(interceptLinks);
#endif
view->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, true);
view->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled,false);
connect(view->page()->profile(), &QWebEngineProfile::downloadRequested,
this, &BrowserView::onDownloadRequested);
connect(view->page(), SIGNAL(iconChanged(const QIcon &)),
this, SLOT(setWindowIcon(const QIcon &)));
connect(view->page(), SIGNAL(linkHovered(const QString &)),
this, SLOT(onLinkHovered(const QString &)));
#endif
connect(view, SIGNAL(viewSource(const QUrl&)),
this, SLOT(onViewSource(const QUrl&)));
connect(view, SIGNAL(loadStarted()),
this, SLOT(onLoadStarted()));
connect(view, SIGNAL(loadProgress(int)),
this, SLOT(onLoadProgress(int)));
connect(view, SIGNAL(loadFinished(bool)),
this, SLOT(onLoadFinished(bool)));
connect(view, SIGNAL(openLinkInExternalBrowser(const QUrl &)),
this, SLOT(onOpenLinkInExternalBrowser(const QUrl &)));
connect(view, SIGNAL(openLinkInNewWindow(const QUrl &)),
this, SLOT(onOpenLinkInNewWindow(const QUrl &)));
connect(view, SIGNAL(loadStarted()),
this, SLOT(onUpdateBrowserActions()));
connect(view, SIGNAL(loadFinished(bool)),
this, SLOT(onUpdateBrowserActions()));
}
/** Destroys the object and frees any allocated resources */
BrowserView::~BrowserView()
{
#ifdef QTWEBENGINE
delete interceptLinks; // cleanup not handled implicitly
#endif
delete view;
}
void BrowserView::urlFilter(const QUrl & url)
{
QString scheme = url.scheme();
QString host = url.host();
//QString username = url.userName();
// path handling
QString path = url.path();
QUrl exturl(url);
// query
QString q;
if (url.hasQuery())
q = url.query();
//QString fragment = url. fragment();
#ifdef QTWEBKIT
if (scheme==QString::fromLatin1("http") || scheme==QString::fromLatin1("https")) {
load(url);
}
#endif
// Small trick to force opening a link in an external browser: use exthttp or exthttps
// Write your URL as exthttp://www.example.com
else if (scheme==QString::fromLatin1("exthttp")) {
exturl.setScheme(QString::fromLatin1("http"));
QDesktopServices::openUrl(exturl);
stop();// stop qwebengine, should do nothing in qwebkit at this point
}
else if (scheme==QString::fromLatin1("exthttps")) {
exturl.setScheme(QString::fromLatin1("https"));
QDesktopServices::openUrl(exturl);
stop();// stop qwebengine, should do nothing in qwebkit at this point
}
// run scripts if not from somewhere else!
if ((scheme.size() < 2 || scheme==QString::fromLatin1("file"))&& host.isEmpty()) {
QFileInfo fi(path);
if (fi.exists()) {
QString ext = fi.completeSuffix();
if (ext == QString::fromLatin1("py")) {
stop(); // stop qwebengine, should do nothing in qwebkit at this point
try {
if (!q.isEmpty()) {
// encapsulate the value in quotes
q = q.replace(QString::fromLatin1("="),QString::fromLatin1("=\""))+QString::fromLatin1("\"");
q = q.replace(QString::fromLatin1("%"),QString::fromLatin1("%%"));
// url queries in the form of somescript.py?key=value, the first key=value will be printed in the py console as key="value"
Gui::Command::doCommand(Gui::Command::Gui,q.toStdString().c_str());
}
// Gui::Command::doCommand(Gui::Command::Gui,"execfile('%s')",(const char*) fi.absoluteFilePath(). toLocal8Bit());
QString filename = Base::Tools::escapeEncodeFilename(fi.absoluteFilePath());
Gui::Command::doCommand(Gui::Command::Gui,"with open('%s') as file:\n\texec(file.read())",(const char*) filename.toUtf8());
}
catch (const Base::Exception& e) {
QMessageBox::critical(this, tr("Error"), QString::fromUtf8(e.what()));
}
App::Document *doc = BaseView::getAppDocument();
if(doc && doc->testStatus(App::Document::PartialRestore))
QMessageBox::critical(this, tr("Error"), tr("There were errors while loading the file. Some data might have been modified or not recovered at all. Look in the report view for more specific information about the objects involved."));
if(doc && doc->testStatus(App::Document::RestoreError))
QMessageBox::critical(this, tr("Error"), tr("There were serious errors while loading the file. Some data might have been modified or not recovered at all. Saving the project will most likely result in loss of data."));
}
}
else {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("File does not exist!"),
fi.absoluteFilePath ());
}
}
}
bool BrowserView::chckHostAllowed(const QString& host)
{
// only check if a local file, later we can do here a dialog to ask the user if
return host.isEmpty();
}
#ifdef QTWEBENGINE
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
void BrowserView::onDownloadRequested(QWebEngineDownloadItem *request)
#else
void BrowserView::onDownloadRequested(QWebEngineDownloadRequest *request)
#endif
{
QUrl url = request->url();
if (!url.isLocalFile()) {
request->accept();
Gui::Dialog::DownloadManager::getInstance()->download(request->url());
}
else {
request->cancel();
Gui::getMainWindow()->loadUrls(App::GetApplication().getActiveDocument(), QList<QUrl>() << url);
}
}
void BrowserView::setWindowIcon(const QIcon &icon)
{
Gui::MDIView::setWindowIcon(icon);
}
void BrowserView::onLinkHovered(const QString& url)
{
Gui::getMainWindow()->statusBar()->showMessage(url);
}
void BrowserView::onViewSource(const QUrl &url)
{
Q_UNUSED(url);
view->page()->toHtml([=](const QString &pageSource){
QPlainTextEdit *editorWidget = new QPlainTextEdit {};
App::TextDocument *txtDoc = new App::TextDocument;
TextDocumentEditorView *textDocView = new TextDocumentEditorView {
txtDoc,
editorWidget, getMainWindow()};
editorWidget->setReadOnly(true);
editorWidget->setPlainText(pageSource);
getMainWindow()->addWindow(textDocView);
});
}
#else
void BrowserView::onDownloadRequested(const QNetworkRequest & request)
{
QUrl url = request.url();
if (!url.isLocalFile()) {
Gui::Dialog::DownloadManager::getInstance()->download(request);
}
else {
Gui::getMainWindow()->loadUrls(App::GetApplication().getActiveDocument(), QList<QUrl>() << url);
}
}
void BrowserView::onUnsupportedContent(QNetworkReply* reply)
{
// Do not call handleUnsupportedContent() directly otherwise we won't get
// the metaDataChanged() signal of the reply.
Gui::Dialog::DownloadManager::getInstance()->download(reply->url());
// Due to setting the policy QWebPage::DelegateAllLinks the urlFilter()
// slot is called even when clicking on a downloadable file but the page
// then fails to load. Thus, we reload the previous url.
view->reload();
}
void BrowserView::onLinkHovered(const QString& link, const QString& title, const QString& textContent)
{
Q_UNUSED(title)
Q_UNUSED(textContent)
QUrl url = QUrl::fromEncoded(link.toLatin1());
QString str = url.isValid() ? url.toString() : link;
Gui::getMainWindow()->statusBar()->showMessage(str);
}
void BrowserView::onViewSource(const QUrl &url)
{
Q_UNUSED(url);
if (!view->page() || !view->page()->currentFrame())
return;
QString pageSource = view->page()->currentFrame()->toHtml();
QPlainTextEdit *editorWidget = new QPlainTextEdit {};
App::TextDocument *txtDoc = new App::TextDocument;
TextDocumentEditorView *textDocView = new TextDocumentEditorView {
txtDoc, editorWidget, getMainWindow()
};
editorWidget->setReadOnly(true);
editorWidget->setPlainText(pageSource);
getMainWindow()->addWindow(textDocView);
}
#endif
void BrowserView::load(const char* URL)
{
QUrl url = QUrl::fromUserInput(QString::fromUtf8(URL));
load(url);
}
void BrowserView::load(const QUrl & url)
{
if (isLoading)
stop();
urlWgt->setText(url.toString());
view->load(url);
view->setUrl(url);
if (url.scheme().size() < 2) {
QString path = url.path();
QFileInfo fi(path);
QString name = fi.baseName();
setWindowTitle(name);
}
else {
setWindowTitle(url.host());
}
#ifdef QTWEBKIT
setWindowIcon(QWebSettings::iconForUrl(url));
#endif
}
void BrowserView::setHtml(const QString& HtmlCode,const QUrl & BaseUrl)
{
if (isLoading)
stop();
view->setHtml(HtmlCode, BaseUrl);
#ifdef QTWEBKIT
setWindowIcon(QWebSettings::iconForUrl(BaseUrl));
#endif
}
void BrowserView::stop()
{
view->stop();
}
QUrl BrowserView::url() const
{
return view->url();
}
void BrowserView::onLoadStarted()
{
QProgressBar* bar = Gui::SequencerBar::instance()->getProgressBar();
bar->setRange(0, 100);
bar->show();
Gui::getMainWindow()->showMessage(tr("Loading %1...").arg(view->url().toString()));
isLoading = true;
}
void BrowserView::onLoadProgress(int step)
{
QProgressBar* bar = Gui::SequencerBar::instance()->getProgressBar();
bar->setValue(step);
}
void BrowserView::onLoadFinished(bool ok)
{
Q_UNUSED(ok)
QProgressBar* bar = SequencerBar::instance()->getProgressBar();
bar->setValue(100);
bar->hide();
Gui::MainWindow* win = Gui::getMainWindow();
if (win) {
win->showMessage(QString());
}
isLoading = false;
}
void BrowserView::onOpenLinkInExternalBrowser(const QUrl& url)
{
QDesktopServices::openUrl(url);
}
void BrowserView::onOpenLinkInNewWindow(const QUrl& url)
{
BrowserView* view = new WebGui::BrowserView(Gui::getMainWindow());
view->setWindowTitle(QObject::tr("Browser"));
view->resize(400, 300);
view->load(url);
Gui::getMainWindow()->addWindow(view);
Gui::getMainWindow()->setActiveWindow(this);
}
void BrowserView::onUpdateBrowserActions()
{
CommandManager& mgr = Application::Instance->commandManager();
std::vector<const char*> cmds = {"Web_BrowserBack", "Web_BrowserNext", "Web_BrowserRefresh", "Web_BrowserStop",
"Web_BrowserZoomIn", "Web_BrowserZoomOut", "Web_BrowserSetURL"};
for (const auto& it : cmds) {
Gui::Command* cmd = mgr.getCommandByName(it);
if (cmd)
cmd->testActive();
}
}
void BrowserView::OnChange(Base::Subject<const char*> &rCaller,const char* rcReason)
{
Q_UNUSED(rCaller);
Q_UNUSED(rcReason);
}
/**
* Runs the action specified by \a pMsg.
*/
bool BrowserView::onMsg(const char* pMsg,const char** )
{
if (strcmp(pMsg,"Back")==0){
view->back();
return true;
} else if (strcmp(pMsg,"Next")==0){
view->forward();
return true;
} else if (strcmp(pMsg,"Refresh")==0){
view->reload();
return true;
} else if (strcmp(pMsg,"Stop")==0){
stop();
return true;
} else if (strcmp(pMsg,"ZoomIn")==0){
qreal factor = view->zoomFactor();
view->setZoomFactor(factor + 0.2);
return true;
} else if (strcmp(pMsg,"ZoomOut")==0){
qreal factor = view->zoomFactor();
view->setZoomFactor(factor - 0.2);
return true;
} else if (strcmp(pMsg,"SetURL")==0){
if (urlWgt->isVisible())
urlWgt->hide();
else
urlWgt->display();
return true;
}
return false;
}
/**
* Checks if the action \a pMsg is available. This is for enabling/disabling
* the corresponding buttons or menu items for this action.
*/
bool BrowserView::onHasMsg(const char* pMsg) const
{
if (strcmp(pMsg,"Back")==0)
return view->page()->action(QWebEnginePage::Back)->isEnabled();
if (strcmp(pMsg,"Next")==0)
return view->page()->action(QWebEnginePage::Forward)->isEnabled();
if (strcmp(pMsg,"Refresh")==0)
return !isLoading;
if (strcmp(pMsg,"Stop")==0)
return isLoading;
if (strcmp(pMsg,"ZoomIn")==0)
return true;
if (strcmp(pMsg,"ZoomOut")==0)
return true;
if (strcmp(pMsg,"SetURL")==0)
return true;
return false;
}
/** Checking on close state. */
bool BrowserView::canClose()
{
return true;
}
PyObject* BrowserView::getPyObject()
{
static bool init = false;
if (!init) {
init = true;
BrowserViewPy::init_type();
}
return new BrowserViewPy(this);
}
#include "moc_BrowserView.cpp"