/************************************************************************ * * 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