/************************************************************************
*
* Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com)
*
* This file is part of SuperCollider Qt GUI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
************************************************************************/
#ifdef SC_USE_QTWEBENGINE
# include "QcWebView.h"
# include "../widgets/web_page.hpp"
# include "../QcWidgetFactory.h"
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
QC_DECLARE_QWIDGET_FACTORY(WebView);
namespace QtCollider {
WebView::WebView(QWidget* parent): QWebEngineView(parent), _interpretSelection(false), _editable(false) {
QtCollider::WebPage* page = new WebPage(this);
page->setDelegateReload(true);
setPage(page);
connectPage(page);
// Set the style's standard palette to avoid system's palette incoherencies
// get in the way of rendering web pages
setPalette(style()->standardPalette());
setAttribute(Qt::WA_AcceptTouchEvents);
page->action(QWebEnginePage::Copy)->setShortcut(QKeySequence::Copy);
page->action(QWebEnginePage::Paste)->setShortcut(QKeySequence::Paste);
page->action(QWebEnginePage::Reload)->setShortcut(QKeySequence::Refresh);
connect(this, SIGNAL(interpret(QString)), qApp, SLOT(interpret(QString)), Qt::QueuedConnection);
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(updateEditable(bool)));
}
void WebView::connectPage(QtCollider::WebPage* page) {
connect(page, SIGNAL(jsConsoleMsg(const QString&, int, const QString&)), this,
SIGNAL(jsConsoleMsg(const QString&, int, const QString&)));
connect(page, SIGNAL(linkHovered(const QString&)), this, SIGNAL(linkHovered(const QString&)));
connect(page, SIGNAL(geometryChangeRequested(const QRect&)), this, SIGNAL(geometryChangeRequested(const QRect&)));
connect(page, SIGNAL(windowCloseRequested()), this, SIGNAL(windowCloseRequested()));
connect(page, SIGNAL(scrollPositionChanged(const QPointF&)), this, SIGNAL(scrollPositionChanged(const QPointF&)));
connect(page, SIGNAL(contentsSizeChanged(const QSizeF&)), this, SIGNAL(contentsSizeChanged(const QSizeF&)));
connect(page, SIGNAL(audioMutedChanged(bool)), this, SIGNAL(audioMutedChanged(bool)));
connect(page, SIGNAL(recentlyAudibleChanged(bool)), this, SIGNAL(recentlyAudibleChanged(bool)));
connect(page, SIGNAL(navigationRequested(QUrl, QWebEnginePage::NavigationType, bool)), this,
SLOT(onLinkClicked(QUrl, QWebEnginePage::NavigationType, bool)));
connect(page->action(QWebEnginePage::Reload), SIGNAL(triggered(bool)), this, SLOT(onPageReload()));
connect(page, &WebPage::renderProcessTerminated, this, &WebView::onRenderProcessTerminated);
}
void WebView::onRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus status, int code) {
Q_EMIT(renderProcessTerminated((int)status, code));
}
void WebView::triggerPageAction(int action, bool checked) {
QWebEngineView::triggerPageAction((QWebEnginePage::WebAction)action, checked);
}
QString WebView::url() const { return QWebEngineView::url().toString(); }
void WebView::setUrl(const QString& str) { load(urlFromString(str)); }
bool WebView::delegateReload() const {
WebPage* p = qobject_cast(page());
Q_ASSERT(p);
return p->delegateReload();
}
void WebView::setDelegateReload(bool flag) {
WebPage* p = qobject_cast(page());
Q_ASSERT(p);
p->setDelegateReload(flag);
}
void WebView::setFontFamily(int generic, const QString& specific) {
settings()->setFontFamily((QWebEngineSettings::FontFamily)generic, specific);
}
QAction* WebView::pageAction(QWebEnginePage::WebAction action) const { return QWebEngineView::pageAction(action); }
void WebView::setHtml(const QString& html, const QString& baseUrl) {
if (page()) {
page()->setHtml(html, baseUrl);
}
}
void WebView::setContent(const QVector& data, const QString& mimeType, const QString& baseUrl) {
if (page()) {
QByteArray byteData;
for (int val : data) {
byteData.push_back((char)val);
}
page()->setContent(byteData, mimeType, baseUrl);
}
}
void WebView::toHtml(QcCallback* cb) const {
if (page()) {
if (cb) {
page()->toHtml(cb->asFunctor());
} else {
page()->toHtml([](const QString&) {});
}
} else {
cb->asFunctor()(QString());
}
}
void WebView::toPlainText(QcCallback* cb) const {
if (page()) {
if (cb) {
page()->toPlainText(cb->asFunctor());
} else {
page()->toPlainText([](const QString&) {});
}
} else {
cb->asFunctor()(QString());
}
}
void WebView::runJavaScript(const QString& script, QcCallback* cb) {
if (page()) {
if (cb) {
page()->runJavaScript(script, cb->asFunctor());
} else {
page()->runJavaScript(script, [](const QVariant&) {});
}
} else {
cb->asFunctor()(QString());
}
}
void WebView::setWebAttribute(int attr, bool on) {
if (page()) {
page()->settings()->setAttribute((QWebEngineSettings::WebAttribute)attr, on);
}
}
bool WebView::testWebAttribute(int attr) {
return page() ? page()->settings()->testAttribute((QWebEngineSettings::WebAttribute)attr) : false;
}
void WebView::resetWebAttribute(int attr) {
if (page()) {
page()->settings()->resetAttribute((QWebEngineSettings::WebAttribute)attr);
}
}
void WebView::navigate(const QString& urlString) {
QUrl url(urlString);
this->load(url);
}
void WebView::findText(const QString& searchText, bool reversed, QcCallback* cb) {
QWebEnginePage::FindFlags flags;
if (reversed)
flags |= QWebEnginePage::FindBackward;
if (!cb) {
QWebEngineView::findText(searchText, flags);
} else {
QWebEngineView::findText(searchText, flags, cb->asFunctor());
}
}
void WebView::onPageReload() { Q_EMIT(reloadTriggered(url())); }
void WebView::contextMenuEvent(QContextMenuEvent* event) {
QMenu menu;
const QWebEngineContextMenuData& contextData = page()->contextMenuData();
if (!contextData.linkUrl().isEmpty()) {
menu.addAction(pageAction(QWebEnginePage::CopyLinkToClipboard));
menu.addSeparator();
}
if (contextData.isContentEditable() || !contextData.selectedText().isEmpty()) {
menu.addAction(pageAction(QWebEnginePage::Copy));
if (contextData.isContentEditable()) {
menu.addAction(pageAction(QWebEnginePage::Paste));
}
menu.addSeparator();
}
menu.addAction(pageAction(QWebEnginePage::Back));
menu.addAction(pageAction(QWebEnginePage::Forward));
menu.addAction(pageAction(QWebEnginePage::Reload));
menu.exec(event->globalPos());
}
void WebView::keyPressEvent(QKeyEvent* e) {
int key = e->key();
int mods = e->modifiers();
if (_interpretSelection
&& (key == Qt::Key_Enter || (key == Qt::Key_Return && mods & (Qt::ControlModifier | Qt::ShiftModifier)))) {
QString selection = selectedText();
if (!selection.isEmpty()) {
Q_EMIT(interpret(selection));
return;
}
}
QWebEngineView::keyPressEvent(e);
}
void WebView::updateEditable(bool ok) {
if (ok) {
if (_editable) {
page()->runJavaScript("document.documentElement.contentEditable = true");
} else {
page()->runJavaScript("document.documentElement.contentEditable = false");
}
}
}
bool WebView::overrideNavigation() const {
WebPage* p = qobject_cast(page());
return p ? p->delegateNavigation() : false;
}
void WebView::setOverrideNavigation(bool b) {
WebPage* p = qobject_cast(page());
if (p) {
p->setDelegateNavigation(b);
}
}
void WebView::onLinkClicked(const QUrl& url, QWebEnginePage::NavigationType type, bool isMainFrame) {
Q_EMIT(navigationRequested(url, (int)type, isMainFrame));
}
} // namespace QtCollider
#endif // SC_USE_QTWEBENGINE