15#include <QApplication>
16#include <QWebEngineHistory>
17#include <QWebEngineSettings>
18#include <QWebEngineScript>
19#include <QWebEngineScriptCollection>
24#include <QDomDocument>
54 {
"audio/mpeg3",
"mp3",
false },
55 {
"audio/x-mpeg-3",
"mp3",
false },
56 {
"audio/mpeg",
"mp2",
false },
57 {
"audio/x-mpeg",
"mp2",
false },
58 {
"audio/ogg",
"ogg",
false },
59 {
"audio/ogg",
"oga",
false },
60 {
"audio/flac",
"flac",
false },
61 {
"audio/x-ms-wma",
"wma",
false },
62 {
"audio/wav",
"wav",
false },
63 {
"audio/x-wav",
"wav",
false },
64 {
"audio/ac3",
"ac3",
false },
65 {
"audio/x-ac3",
"ac3",
false },
66 {
"audio/x-oma",
"oma",
false },
67 {
"audio/x-realaudio",
"ra",
false },
68 {
"audio/dts",
"dts",
false },
69 {
"audio/x-dts",
"dts",
false },
70 {
"audio/aac",
"aac",
false },
71 {
"audio/x-aac",
"aac",
false },
72 {
"audio/m4a",
"m4a",
false },
73 {
"audio/x-m4a",
"m4a",
false },
74 {
"video/mpeg",
"mpg",
true },
75 {
"video/mpeg",
"mpeg",
true },
76 {
"video/x-ms-wmv",
"wmv",
true },
77 {
"video/x-ms-wmv",
"avi",
true },
78 {
"application/x-troff-msvideo",
"avi",
true },
79 {
"video/avi",
"avi",
true },
80 {
"video/msvideo",
"avi",
true },
81 {
"video/x-msvideo",
"avi",
true }
91 : QWebEngineView(parent), m_parentBrowser(parentBrowser)
93 m_profile =
new QWebEngineProfile(
"MythTV",
this);
95 m_profile->setPersistentCookiesPolicy(QWebEngineProfile::AllowPersistentCookies);
101 installEventFilter(
this);
112 if (event->type() == QEvent::ShortcutOverride)
115 auto *keyEvent =
dynamic_cast<QKeyEvent *
>(event);
116 if (keyEvent ==
nullptr)
118 LOG(VB_GENERAL, LOG_ALERT,
119 "MythWebEngineView::eventFilter() couldn't cast event");
133 return QWebEngineView::eventFilter(obj, event);
138 Q_FOREACH(QObject* obj, children())
140 if (qobject_cast<QWidget*>(obj))
142 auto *
event =
new QKeyEvent(QEvent::KeyPress, key, modifiers, text,
false, 1);
143 QCoreApplication::postEvent(obj, event);
154 for (
int i = 0; i < actions.size() && !handled; i++)
156 const QString&
action = actions[i];
161 if (history()->canGoBack())
169 else if (
action ==
"NEXTLINK")
171 if (event->key() != Qt::Key_Tab)
173 sendKeyPress(Qt::Key_Tab, Qt::NoModifier, QString(
'\t'));
179 else if (
action ==
"PREVIOUSLINK")
181 if (event->key() != Qt::Key_Tab)
183 sendKeyPress(Qt::Key_Tab, Qt::ShiftModifier, QString(
'\t'));
189 else if (
action ==
"FOLLOWLINK")
191 if (event->key() != Qt::Key_Return)
193 sendKeyPress(Qt::Key_Return, Qt::NoModifier, QString(
'\r'));
199 else if (
action ==
"TOGGLEINPUT")
212 else if (
action ==
"ZOOMIN")
216 else if (
action ==
"ZOOMOUT")
220 else if (
action ==
"RELOAD")
224 else if (
action ==
"FULLRELOAD")
228 else if (
action ==
"MOUSEUP" ||
action ==
"MOUSEDOWN" ||
230 action ==
"MOUSELEFTBUTTON")
234 else if (
action ==
"HISTORYBACK")
238 else if (
action ==
"HISTORYFORWARD")
256 QString msg(tr(
"Downloading..."));
258 if (!message.isEmpty())
283 if (dce->GetResult() < 0)
286 QString resultid = dce->GetId();
287 QString resulttext = dce->GetResultText();
289 if (resultid ==
"filenamedialog")
293 else if (resultid ==
"downloadmenu")
295 if (resulttext == tr(
"Play the file"))
298 QString extension = fi.suffix();
303 MythEvent me(QString(
"MUSIC_COMMAND %1 PLAY_URL %2")
315 LOG(VB_GENERAL, LOG_ERR,
316 QString(
"MythWebEngineView: Asked to play a file with "
317 "extension '%1' but don't know how")
321 else if (resulttext == tr(
"Download the file"))
325 else if (resulttext == tr(
"Download and play the file"))
334 auto *me =
dynamic_cast<MythEvent *
>(event);
338 QStringList tokens = me->
Message().split(
" ", Qt::SkipEmptyParts);
339 if (tokens.isEmpty())
342 if (tokens[0] ==
"DOWNLOAD_FILE")
344 QStringList
args = me->ExtraDataList();
346 if (tokens[1] ==
"UPDATE")
350 else if (tokens[1] ==
"FINISHED")
352 int fileSize =
args[2].toInt();
353 int errorCode =
args[4].toInt();
358 if ((errorCode != 0) || (fileSize == 0))
369 if (event->type() == QEvent::UpdateRequest)
371 LOG(VB_GENERAL, LOG_ERR, QString(
"MythWebEngineView: customeEvent: QEvent::UpdateRequest"));
379 QString extension = fi.suffix();
382 QString label = tr(
"What do you want to do with this file?");
394 menu->SetReturnEvent(
this,
"downloadmenu");
397 menu->AddButton(tr(
"Play the file"));
400 menu->AddButton(tr(
"Download and play the file"));
402 menu->AddButton(tr(
"Download the file"));
403 menu->AddButton(tr(
"Cancel"));
410 if (mimetype.isEmpty())
414 [mimetype] (
const MimeType& entry) ->
bool
415 { return mimetype == entry.m_mimeType; });
417 return it->m_extension;
424 [extension, mimetype](
const auto &entry){
427 if (!mimetype.isEmpty() &&
428 mimetype == entry.m_mimeType)
430 if (!extension.isEmpty() &&
431 extension.toLower() == entry.m_extension)
439 [extension, mimetype](
const auto &entry) {
440 if (!entry.m_isVideo)
442 if (!mimetype.isEmpty() &&
443 mimetype == entry.m_mimeType)
445 if (!extension.isEmpty() &&
446 extension.toLower() == entry.m_extension)
457 QVariant header =
m_downloadReply->header(QNetworkRequest::ContentTypeHeader);
459 if (header != QVariant())
460 mimeType = header.toString();
467 return (QWebEngineView *)
this;
512 m_updateInterval(500), m_bgColor(
"Red"), m_userCssFile(
""),
513 m_defaultSaveDir(
GetConfDir() +
"/MythBrowser/"),
514 m_defaultSaveFilename(
""), m_lastMouseAction(
"")
554 m_webEngine->setPalette(QApplication::style()->standardPalette());
596 QString
filename =
"htmls/mythbrowser.css";
602 SetHttpUserAgent(
"Mozilla/5.0 (SMART-TV; Linux; Tizen 5.0) AppleWebKit/538.1 (KHTML, like Gecko) Version/5.0 NativeTVAds Safari/538.1");
623 QObject *parentObject = parent();
632 parentObject = parentObject->parent();
636 LOG(VB_GENERAL, LOG_ERR,
"MythUIWebBrowser: failed to find our parent screen");
649 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: enabling plugins");
650 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled,
true);
654 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: disabling plugins");
655 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled,
false);
660 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: disabling JavaScript");
661 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled,
false);
664 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled,
true);
665 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage,
true);
666 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled,
true);
667 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled,
true);
668 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled,
true);
669 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled,
true);
672 m_webEngine->page()->settings()->setAttribute(QWebEngineSettings::ShowScrollBars,
false);
674 m_webEngine->setWindowFlag(Qt::WindowStaysOnTopHint,
true);
755 LOG(VB_GENERAL, LOG_ERR,
"MythUIWebBrowser: Failed to download css from - " + url.toString());
761 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: Loading css from - " + url.toString());
763 QWebEngineScript script;
764 QString s = QString::fromLatin1(
"(function() {"\
765 " css = document.createElement('style');"\
766 " css.type = 'text/css';"\
768 " document.head.appendChild(css);"\
769 " css.innerText = '%2';"\
770 "})()").arg(name, QString(download).simplified());
772 m_webEngine->page()->runJavaScript(s, QWebEngineScript::ApplicationWorld);
774 script.setName(name);
775 script.setSourceCode(s);
776 script.setInjectionPoint(QWebEngineScript::DocumentReady);
777 script.setRunsOnSubFrames(
true);
778 script.setWorldId(QWebEngineScript::ApplicationWorld);
787#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
788 QList<QWebEngineScript> scripts =
m_webEngine->page()->scripts().find(name);
790 QList<QWebEngineScript> scripts =
m_webEngine->page()->scripts().findScripts(name);
793 if (!scripts.isEmpty())
797 QString s = QString::fromLatin1(
"(function() {"\
798 " var element = document.getElementById('%1');"\
799 " element.outerHTML = '';"\
803 m_webEngine->page()->runJavaScript(s, QWebEngineScript::ApplicationWorld);
828 m_webEngine->page()->profile()->setHttpUserAgent(userAgent);
844 palette.setBrush(QPalette::Window, QBrush(color));
845 palette.setBrush(QPalette::Base, QBrush(color));
947 if (!saveDir.isEmpty())
1083 LOG(VB_GENERAL, LOG_INFO, QString(
"MythUIWebBrowser::slotRenderProcessTerminated - terminationStatus: %1, exitStatus: %2").arg(terminationStatus).arg(exitCode));
1089 fullScreenRequest.accept();
1094 LOG(VB_GENERAL, LOG_INFO, QString(
"MythUIWebBrowser::slotWindowCloseRequested called"));
1099void MythUIWebBrowser::MythUIWebBrowser::slotLoadStarted(
void)
1205 QPoint position =
m_webEngine->page()->scrollPosition().toPoint();
1229 LOG(VB_GENERAL, LOG_ERR, QString(
"MythUIWebBrowser::UpdateBuffer called - m_image or m_webEngine is FALSE"));
1264 int alphaMod, QRect clipRect)
1270 area.translate(xoffset, yoffset);
1272 p->SetClipRect(clipRect);
1273 p->DrawImage(area.x(), area.y(),
m_image, alphaMod);
1300 QPoint curPos = QCursor::pos();
1301 QCursor::setPos(curPos.x(), curPos.y() - step);
1303 else if (
action ==
"MOUSELEFT")
1305 QPoint curPos = QCursor::pos();
1306 QCursor::setPos(curPos.x() - step, curPos.y());
1308 else if (
action ==
"MOUSERIGHT")
1310 QPoint curPos = QCursor::pos();
1311 QCursor::setPos(curPos.x() + step, curPos.y());
1313 else if (
action ==
"MOUSEDOWN")
1315 QPoint curPos = QCursor::pos();
1316 QCursor::setPos(curPos.x(), curPos.y() + step);
1318 else if (
action ==
"MOUSELEFTBUTTON")
1320 QPoint curPos = QCursor::pos();
1321 QWidget *widget = QApplication::widgetAt(curPos);
1325 curPos = widget->mapFromGlobal(curPos);
1327 auto *me =
new QMouseEvent(QEvent::MouseButtonPress, curPos, curPos,
1328 Qt::LeftButton, Qt::LeftButton,
1331 QCoreApplication::postEvent(widget, me);
1333 me =
new QMouseEvent(QEvent::MouseButtonRelease, curPos, curPos,
1334 Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1336 QCoreApplication::postEvent(widget, me);
1360 const QString &
filename, QDomElement &element,
bool showWarnings)
1362 if (element.tagName() ==
"zoom")
1365 m_zoom = zoom.toDouble();
1367 else if (element.tagName() ==
"url")
1371 else if (element.tagName() ==
"userstylesheet")
1375 else if (element.tagName() ==
"updateinterval")
1380 else if (element.tagName() ==
"background")
1382 m_bgColor = QColor(element.attribute(
"color",
"#ffffff"));
1383 int alpha = element.attribute(
"alpha",
"255").toInt();
1386 else if (element.tagName() ==
"browserarea")
1390 else if (element.tagName() ==
"scrollduration")
1394 else if (element.tagName() ==
"acceptsfocus")
1414 LOG(VB_GENERAL, LOG_ERR,
"ERROR, bad parsing");
1421 m_zoom = browser->m_zoom;
1437 browser->CopyFrom(
this);
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
static const Type kEventType
QString GetHostName(void)
void SaveSetting(const QString &key, int newValue)
double GetFloatSetting(const QString &key, double defaultval=0.0)
void dispatch(const MythEvent &event)
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
Basic menu dialog, message and a list of options.
This class is used as a container for messages.
const QString & Message() const
static const Type kMythEventMessage
virtual void SetChanged(bool change=true)
void Assign(const QImage &img)
int DecrRef(void) override
Decrements reference count and deletes on 0.
QWidget * GetPaintWindow()
MythScreenStack * GetStackAt(int Position)
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
bool HandleMedia(const QString &Handler, const QString &Mrl, const QString &Plot="", const QString &Title="", const QString &Subtitle="", const QString &Director="", int Season=0, int Episode=0, const QString &Inetref="", std::chrono::minutes LenMins=2h, const QString &Year="1895", const QString &Id="", bool UseBookmarks=false)
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
void CalculateArea(QRect parentArea)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void topScreenChanged(MythScreenType *screen)
virtual MythScreenType * GetTopScreen(void) const
Screen in which all other widgets are contained and rendered.
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool Create(void) override
The base class on which all widgets and screens are based.
void SetCanTakeFocus(bool set=true)
Set whether this widget can take focus.
virtual MythPainter * GetPainter(void)
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
bool IsOnTopScreen(void)
is our containing screen the top screen?
MythRect m_actualBrowserArea
void iconUrlChanged(const QUrl &url)
a pages fav icon has changed
void slotScrollBarHiding(void)
~MythUIWebBrowser() override
the classes destructor
void slotLinkClicked(const QUrl &url)
QWebEngineView * m_webEngine
QString GetTitle(void)
Gets the current page's title.
void iconChanged(const QIcon &icon)
link hit test messages
MythScreenType * GetParentScreen(void)
void UpdateScrollBars(void)
float GetZoom(void) const
Get the current zoom level.
bool IsInputToggled(void) const
returns true if all keypresses are to be passed to the web page
void titleChanged(const QString &title)
% of page loaded
void SetDefaultSaveDirectory(const QString &saveDir)
void LoadPage(const QUrl &url)
Loads the specified url and displays it.
void SetZoom(double zoom)
Set the text size to specific size.
void HandleMouseAction(const QString &action)
void RemoveUserStyleSheet(const QString &name)
QElapsedTimer m_lastUpdateTime
void Finalize(void) override
Perform any post-xml parsing initialisation tasks.
void ResetScrollBars(void)
QIcon GetIcon(void)
Gets the current page's fav icon.
void Init(void)
Initializes the widget ready for use.
void slotLoadFinished(bool Ok)
void RunJavaScript(const QString &scriptSource)
void slotWindowCloseRequested(void)
void TriggerPageAction(QWebEnginePage::WebAction action, bool checked=false)
void SetInputToggled(bool inputToggled)
void SetActive(bool active)
Toggles the active state of the widget.
MythUIScrollBar * m_horizontalScrollbar
void ZoomIn(void)
Increase the text size.
void slotTopScreenChanged(MythScreenType *screen)
void slotScrollBarShowing(void)
void Reload(bool useCache=true)
void Back(void)
Got backward in page history.
MythUIWebBrowser(MythUIType *parent, const QString &name)
the classes constructor
void statusBarMessage(const QString &text)
a pages title has changed
void slotIconChanged(const QIcon &icon)
void SetHttpUserAgent(const QString &userAgent)
void loadProgress(int progress)
a page has finished loading
QString m_defaultSaveFilename
void slotTitleChanged(const QString &title)
void slotScrollPositionChanged(QPointF position)
MythScreenType * m_parentScreen
QWebEngineSettings * GetWebEngineSettings(void)
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
void SetDefaultSaveFilename(const QString &filename)
QWebEngineProfile * GetWebEngineProfile(void)
void SendStatusBarMessage(const QString &text)
void slotLoadStarted(void)
a file has been downloaded
void ZoomOut(void)
Decrease the text size.
QUrl GetUrl(void)
Gets the current page's url.
QString m_lastMouseAction
QElapsedTimer m_lastMouseActionTime
void LoadUserStyleSheet(const QUrl &url, const QString &name=QString("mythtv"))
Sets the specified user style sheet.
void SetBackgroundColor(QColor color)
Sets the default background color.
bool CanGoBack(void)
Can we go backward in page history.
bool CanGoForward(void)
Can go forward in page history.
void SetHtml(const QString &html, const QUrl &baseUrl=QUrl())
Sets the content of the widget to the specified html.
void Forward(void)
Got forward in page history.
void slotRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
MythUIScrollBar * m_verticalScrollbar
void loadFinished(bool ok)
a page is starting to load
static void slotFullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest)
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
void slotContentsSizeChanged(QSizeF size)
void slotIconUrlChanged(const QUrl &url)
void slotLoadProgress(int progress)
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
void slotStatusBarMessage(const QString &text)
Subclass of QWebEngineView.
void sendKeyPress(int key, Qt::KeyboardModifiers modifiers, const QString &text=QString())
QString getReplyMimetype(void)
MythWebEngineView(QWidget *parent, MythUIWebBrowser *parentBrowser)
QWebEngineView * createWindow(QWebEnginePage::WebWindowType type) override
QWebEngineProfile * m_profile
QNetworkRequest m_downloadRequest
MythUIWebBrowser * m_parentBrowser
static bool isMusicFile(const QString &extension, const QString &mimetype)
QWebEnginePage * m_webpage
static bool isVideoFile(const QString &extension, const QString &mimetype)
void showDownloadMenu(void)
void openBusyPopup(const QString &message)
~MythWebEngineView(void) override
void closeBusyPopup(void)
void customEvent(QEvent *e) override
bool eventFilter(QObject *obj, QEvent *event) override
static QString getExtensionForMimetype(const QString &mimetype)
bool handleKeyPress(QKeyEvent *event)
QNetworkReply * m_downloadReply
MythUIBusyDialog * m_busyPopup
static MythUIType * GetGlobalObjectStore(void)
static MythRect parseRect(const QString &text, bool normalize=true)
static QString getFirstText(QDomElement &element)
static bool parseBool(const QString &text)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
static MythThemedMenu * menu
MythUIHelper * GetMythUI()
static const std::vector< MimeType > SupportedMimeTypes
static eu8 clamp(eu8 value, eu8 low, eu8 high)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)