14 #include <QApplication>
16 #include <QWebHistory>
22 #include <QDomDocument>
23 #include <QNetworkCookieJar>
24 #include <QNetworkConfiguration>
52 {
"audio/mpeg3",
"mp3",
false },
53 {
"audio/x-mpeg-3",
"mp3",
false },
54 {
"audio/mpeg",
"mp2",
false },
55 {
"audio/x-mpeg",
"mp2",
false },
56 {
"audio/ogg",
"ogg",
false },
57 {
"audio/ogg",
"oga",
false },
58 {
"audio/flac",
"flac",
false },
59 {
"audio/x-ms-wma",
"wma",
false },
60 {
"audio/wav",
"wav",
false },
61 {
"audio/x-wav",
"wav",
false },
62 {
"audio/ac3",
"ac3",
false },
63 {
"audio/x-ac3",
"ac3",
false },
64 {
"audio/x-oma",
"oma",
false },
65 {
"audio/x-realaudio",
"ra",
false },
66 {
"audio/dts",
"dts",
false },
67 {
"audio/x-dts",
"dts",
false },
68 {
"audio/aac",
"aac",
false },
69 {
"audio/x-aac",
"aac",
false },
70 {
"audio/m4a",
"m4a",
false },
71 {
"audio/x-m4a",
"m4a",
false },
72 {
"video/mpeg",
"mpg",
true },
73 {
"video/mpeg",
"mpeg",
true },
74 {
"video/x-ms-wmv",
"wmv",
true },
75 {
"video/x-ms-wmv",
"avi",
true },
76 {
"application/x-troff-msvideo",
"avi",
true },
77 {
"video/avi",
"avi",
true },
78 {
"video/msvideo",
"avi",
true },
79 {
"video/x-msvideo",
"avi",
true }
84 QNetworkReply* reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
85 reply->ignoreSslErrors();
110 LOG(VB_GENERAL, LOG_DEBUG,
"Copying DLManager's Cookie Jar");
137 QWebPage *page = view->page();
141 connect(
m_frame, &QWebFrame::javaScriptWindowObjectCleared,
this,
147 m_frame->addToJavaScriptWindowObject(QString(
"MusicPlayer"),
this);
170 MythEvent me(QString(
"MUSIC_COMMAND %1 SET_VOLUME %2")
179 MythEvent me(QString(
"MUSIC_COMMAND %1 GET_VOLUME")
188 QCoreApplication::processEvents();
189 std::this_thread::sleep_for(10ms);
200 MythEvent me(QString(
"MUSIC_COMMAND %1 PLAY_FILE '%2'")
207 MythEvent me(QString(
"MUSIC_COMMAND %1 PLAY_TRACK %2")
214 MythEvent me(QString(
"MUSIC_COMMAND %1 PLAY_URL %2")
223 MythEvent me(QString(
"MUSIC_COMMAND %1 GET_METADATA")
232 QCoreApplication::processEvents();
233 std::this_thread::sleep_for(10ms);
250 const QString& message = me->
Message();
252 if (!message.startsWith(
"MUSIC_CONTROL"))
255 QStringList tokens = message.simplified().split(
" ");
257 if ((tokens.size() >= 4) && (tokens[1] ==
"ANSWER")
262 for (
int i = 4; i < tokens.size(); i++)
263 m_answer += QString(
" ") + tokens[i];
278 LOG(VB_GENERAL, LOG_DEBUG,
"Refreshing DLManager's Cookie Jar");
285 return extension == QWebPage::ErrorPageExtension;
291 if (
extension == QWebPage::ErrorPageExtension)
303 const auto *erroroption =
static_cast<const ErrorPageExtensionOption *
>(option);
304 ErrorPageExtensionReturn *erroroutput =
nullptr;
306 erroroutput =
static_cast<ErrorPageExtensionReturn *
>(
output);
308 QString
filename =
"htmls/notfound.html";
314 bool isOpened =
file.open(QIODevice::ReadOnly);
319 QString title = tr(
"Error loading page: %1").arg(erroroption->url.toString());
320 QString html = QString(QLatin1String(
file.readAll()))
322 erroroption->errorString,
323 erroroption->url.toString());
326 imageBuffer.open(QBuffer::ReadWrite);
327 QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning,
329 QPixmap pixmap = icon.pixmap(QSize(32, 32));
331 if (pixmap.save(&imageBuffer,
"PNG"))
333 html.replace(QLatin1String(
"IMAGE_BINARY_DATA_HERE"),
334 QString(QLatin1String(imageBuffer.buffer().toBase64())));
337 erroroutput->content = html.toUtf8();
347 return QWebPage::userAgentForUrl(url).replace(
"Safari",
"MythBrowser");
363 connect(page(), &QWebPage::unsupportedContent,
366 connect(page(), &QWebPage::downloadRequested,
369 page()->setForwardUnsupportedContent(
true);
386 function activeElement()\
389 type = document.activeElement.type;\
392 activeElement();") };
398 .toString().toLower();
399 bool editHasFocus = (
type ==
"text" ||
type ==
"textarea" ||
407 QWebView::keyPressEvent(event);
414 bool handled =
false;
418 for (
int i = 0; i < actions.size() && !handled; i++)
420 QString
action = actions[i];
425 QKeyEvent tabKey(event->type(), Qt::Key_Tab,
426 event->modifiers(), QString(),
427 event->isAutoRepeat(), event->count());
429 QWebView::keyPressEvent(event);
432 if (
action ==
"PREVIOUSLINK")
434 QKeyEvent shiftTabKey(event->type(), Qt::Key_Tab,
435 event->modifiers() | Qt::ShiftModifier,
437 event->isAutoRepeat(), event->count());
438 *
event = shiftTabKey;
439 QWebView::keyPressEvent(event);
442 if (
action ==
"FOLLOWLINK")
444 QKeyEvent returnKey(event->type(), Qt::Key_Return,
445 event->modifiers(), QString(),
446 event->isAutoRepeat(), event->count());
448 QWebView::keyPressEvent(event);
461 if (reply->error() == QNetworkReply::NoError)
465 QVariant header = reply->header(QNetworkRequest::ContentTypeHeader);
467 if (header != QVariant())
469 LOG(VB_GENERAL, LOG_ERR,
470 QString(
"MythWebView::handleUnsupportedContent - %1")
471 .arg(header.toString()));
494 QFileInfo fi(request.url().path());
495 QString basename(fi.completeBaseName());
496 QString extension = fi.suffix().toLower();
500 QString saveBaseName = basename;
505 saveBaseName = savefi.completeBaseName();
509 if (saveBaseName.isEmpty())
510 saveBaseName =
"unnamed_download";
513 if (extension.isEmpty())
516 if (!extension.isEmpty())
517 extension =
'.' + extension;
519 QString saveFilename = QString(
"%1%2%3")
525 if (QFile::exists(saveFilename))
531 saveFilename = QString(
"%1%2-%3%4")
534 QString::number(i++),
537 while (QFile::exists(saveFilename));
549 QString msg = tr(
"Enter filename to save file");
551 false, saveFilename);
555 input->SetReturnEvent(
this,
"filenamedialog");
565 if (saveFilename.isEmpty())
581 QString msg(tr(
"Downloading..."));
583 if (!message.isEmpty())
608 if (dce->GetResult() < 0)
611 QString resultid = dce->GetId();
612 QString resulttext = dce->GetResultText();
614 if (resultid ==
"filenamedialog")
616 else if (resultid ==
"downloadmenu")
618 if (resulttext == tr(
"Play the file"))
621 QString extension = fi.suffix();
626 MythEvent me(QString(
"MUSIC_COMMAND %1 PLAY_URL %2")
638 LOG(VB_GENERAL, LOG_ERR,
639 QString(
"MythWebView: Asked to play a file with "
640 "extension '%1' but don't know how")
644 else if (resulttext == tr(
"Download the file"))
648 else if (resulttext == tr(
"Download and play the file"))
657 auto *me =
dynamic_cast<MythEvent *
>(event);
661 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
662 QStringList tokens = me->
Message().split(
" ", QString::SkipEmptyParts);
664 QStringList tokens = me->Message().split(
" ", Qt::SkipEmptyParts);
666 if (tokens.isEmpty())
669 if (tokens[0] ==
"DOWNLOAD_FILE")
671 QStringList
args = me->ExtraDataList();
673 if (tokens[1] ==
"UPDATE")
677 else if (tokens[1] ==
"FINISHED")
679 int fileSize =
args[2].toInt();
680 int errorCode =
args[4].toInt();
685 if ((errorCode != 0) || (fileSize == 0))
700 QString extension = fi.suffix();
703 QString label = tr(
"What do you want to do with this file?");
715 menu->SetReturnEvent(
this,
"downloadmenu");
718 menu->AddButton(tr(
"Play the file"));
721 menu->AddButton(tr(
"Download and play the file"));
723 menu->AddButton(tr(
"Download the file"));
724 menu->AddButton(tr(
"Cancel"));
731 if (mimetype.isEmpty())
735 [mimetype] (
const MimeType& entry) ->
bool
736 { return mimetype == entry.m_mimeType; });
738 return it->m_extension;
745 [extension, mimetype](
const auto &entry){
748 if (!mimetype.isEmpty() &&
749 mimetype == entry.m_mimeType)
751 if (!extension.isEmpty() &&
752 extension.toLower() == entry.m_extension)
760 [extension, mimetype](
const auto &entry) {
761 if (!entry.m_isVideo)
763 if (!mimetype.isEmpty() &&
764 mimetype == entry.m_mimeType)
766 if (!extension.isEmpty() &&
767 extension.toLower() == entry.m_extension)
778 QVariant header =
m_downloadReply->header(QNetworkRequest::ContentTypeHeader);
780 if (header != QVariant())
781 mimeType = header.toString();
788 return (QWebView *)
this;
833 m_bgColor(
"White"), m_userCssFile(
""),
834 m_defaultSaveDir(
GetConfDir() +
"/MythBrowser/"),
835 m_defaultSaveFilename(
""),
836 m_lastMouseAction(
"")
877 m_browser->setPalette(QApplication::style()->standardPalette());
881 m_browser->page()->setLinkDelegationPolicy(QWebPage::DontDelegateLinks);
888 QWebFrame* frame =
m_browser->page()->currentFrame();
889 frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
898 QWebFrame* frame =
m_browser->page()->currentFrame();
899 frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
917 QString
filename =
"htmls/mythbrowser.css";
927 connect(
m_browser, &QWebView::loadStarted,
929 connect(
m_browser, &QWebView::loadFinished,
931 connect(
m_browser, &QWebView::loadProgress,
933 connect(
m_browser, &QWebView::titleChanged,
935 connect(
m_browser, &QWebView::iconChanged,
937 connect(
m_browser, &QWebView::statusBarMessage,
939 connect(
m_browser->page(), &QWebPage::linkHovered,
941 connect(
m_browser, &QWebView::linkClicked,
946 QObject *parentObject = parent();
955 parentObject = parentObject->parent();
959 LOG(VB_GENERAL, LOG_ERR,
960 "MythUIWebBrowser: failed to find our parent screen");
979 path +=
"/MythBrowser";
985 QWebSettings::setIconDatabasePath(path);
989 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: enabling plugins");
990 QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled,
995 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: disabling plugins");
996 QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled,
1002 LOG(VB_GENERAL, LOG_INFO,
"MythUIWebBrowser: disabling JavaScript");
1003 QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled,
false);
1081 LOG(VB_GENERAL, LOG_INFO,
1082 "MythUIWebBrowser: Loading css from - " + url.toString());
1084 m_browser->page()->settings()->setUserStyleSheetUrl(url);
1098 color.setAlpha(255);
1099 QPalette palette =
m_browser->page()->palette();
1100 palette.setBrush(QPalette::Window, QBrush(color));
1101 palette.setBrush(QPalette::Base, QBrush(color));
1134 if (QGuiApplication::platformName().contains(
"egl"))
1147 if (QGuiApplication::platformName().contains(
"egl"))
1196 if (!saveDir.isEmpty())
1229 return m_browser->history()->canGoForward();
1242 return m_browser->history()->canGoBack();
1275 return QWebSettings::iconForUrl(
m_browser->url());
1312 QWebFrame *frame =
m_browser->page()->currentFrame();
1313 return frame->evaluateJavaScript(scriptSource);
1323 QPoint startPos =
m_browser->page()->currentFrame()->scrollPosition();
1324 QPoint endPos = startPos + QPoint(dx, dy);
1342 m_browser->page()->currentFrame()->setScrollPosition(endPos);
1435 QPoint position =
m_browser->page()->currentFrame()->scrollPosition();
1439 m_browser->page()->currentFrame()->contentsSize().height() -
1449 m_browser->page()->currentFrame()->contentsSize().width() -
1485 m_browser->page()->currentFrame()->scrollPosition())
1490 m_browser->page()->currentFrame()->setScrollPosition(scrollPosition);
1508 int alphaMod, QRect clipRect)
1514 area.translate(xoffset, yoffset);
1516 p->SetClipRect(clipRect);
1517 p->DrawImage(area.x(), area.y(),
m_image, alphaMod);
1528 QStringList actions;
1529 bool handled =
false;
1532 for (
int i = 0; i < actions.size() && !handled; i++)
1534 QString
action = actions[i];
1537 if (
action ==
"TOGGLEINPUT")
1557 QWebFrame *frame =
m_browser->page()->currentFrame();
1560 int pos = frame->scrollPosition().y();
1569 else if (
action ==
"DOWN")
1571 int pos = frame->scrollPosition().y();
1574 if (pos != maximum.height())
1581 else if (
action ==
"LEFT")
1583 int pos = frame->scrollPosition().x();
1592 else if (
action ==
"RIGHT")
1594 int pos = frame->scrollPosition().x();
1597 if (pos != maximum.width())
1604 else if (
action ==
"PAGEUP")
1608 else if (
action ==
"PAGEDOWN")
1612 else if (
action ==
"ZOOMIN")
1616 else if (
action ==
"ZOOMOUT")
1620 else if (
action ==
"MOUSEUP" ||
action ==
"MOUSEDOWN" ||
1622 action ==
"MOUSELEFTBUTTON")
1626 else if (
action ==
"PAGELEFT")
1630 else if (
action ==
"PAGERIGHT")
1634 else if ((
action ==
"NEXTLINK") ||
1635 (
action ==
"PREVIOUSLINK") ||
1636 (
action ==
"FOLLOWLINK"))
1640 else if (
action ==
"HISTORYBACK")
1644 else if (
action ==
"HISTORYFORWARD")
1679 QPoint curPos = QCursor::pos();
1680 QCursor::setPos(curPos.x(), curPos.y() - step);
1682 else if (
action ==
"MOUSELEFT")
1684 QPoint curPos = QCursor::pos();
1685 QCursor::setPos(curPos.x() - step, curPos.y());
1687 else if (
action ==
"MOUSERIGHT")
1689 QPoint curPos = QCursor::pos();
1690 QCursor::setPos(curPos.x() + step, curPos.y());
1692 else if (
action ==
"MOUSEDOWN")
1694 QPoint curPos = QCursor::pos();
1695 QCursor::setPos(curPos.x(), curPos.y() + step);
1697 else if (
action ==
"MOUSELEFTBUTTON")
1699 QPoint curPos = QCursor::pos();
1700 QWidget *widget = QApplication::widgetAt(curPos);
1704 curPos = widget->mapFromGlobal(curPos);
1706 auto *me =
new QMouseEvent(QEvent::MouseButtonPress, curPos,
1707 Qt::LeftButton, Qt::LeftButton,
1709 QCoreApplication::postEvent(widget, me);
1711 me =
new QMouseEvent(QEvent::MouseButtonRelease, curPos,
1712 Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1713 QCoreApplication::postEvent(widget, me);
1737 const QString &
filename, QDomElement &element,
bool showWarnings)
1739 if (element.tagName() ==
"zoom")
1744 else if (element.tagName() ==
"url")
1748 else if (element.tagName() ==
"userstylesheet")
1752 else if (element.tagName() ==
"updateinterval")
1757 else if (element.tagName() ==
"background")
1759 m_bgColor = QColor(element.attribute(
"color",
"#ffffff"));
1760 int alpha = element.attribute(
"alpha",
"255").toInt();
1763 else if (element.tagName() ==
"browserarea")
1767 else if (element.tagName() ==
"scrollduration")
1772 else if (element.tagName() ==
"acceptsfocus")
1792 LOG(VB_GENERAL, LOG_ERR,
"ERROR, bad parsing");
1799 m_zoom = browser->m_zoom;
1815 browser->CopyFrom(
this);