4#include "FrmWebBrowser.h"
5#include <QContextMenuEvent>
8#include <QAuthenticator>
11#include <QLoggingCategory>
13static Q_LOGGING_CATEGORY(log,
"WebBrowser.View")
16 : QWebEngineView(parent)
19 connect(
this, &QWebEngineView::loadStarted, [
this]() {
21 emit favIconChanged(favIcon());
23 connect(
this, &QWebEngineView::loadProgress, [
this](
int progress) {
24 m_loadProgress = progress;
26 connect(
this, &QWebEngineView::loadFinished, [
this](
bool success) {
27 m_loadProgress = success ? 100 : -1;
28 emit favIconChanged(favIcon());
30 connect(
this, &QWebEngineView::iconChanged, [
this](
const QIcon &) {
31 emit favIconChanged(favIcon());
34 connect(
this, &QWebEngineView::renderProcessTerminated,
35 [
this](QWebEnginePage::RenderProcessTerminationStatus termStatus,
int statusCode) {
38 case QWebEnginePage::NormalTerminationStatus:
39 status = tr(
"Render process normal exit");
41 case QWebEnginePage::AbnormalTerminationStatus:
42 status = tr(
"Render process abnormal exit");
44 case QWebEnginePage::CrashedTerminationStatus:
45 status = tr(
"Render process crashed");
47 case QWebEnginePage::KilledTerminationStatus:
48 status = tr(
"Render process killed");
51 QMessageBox::StandardButton btn = QMessageBox::question(window(), status,
52 tr(
"Render process exited with code: %1\n"
53 "Do you want to reload the page ?").arg(statusCode));
54 if (btn == QMessageBox::Yes)
55 QTimer::singleShot(0,
this, &CFrmWebView::reload);
59CFrmWebView::~CFrmWebView()
61 qDebug(log) << Q_FUNC_INFO;
62 if (m_imageAnimationGroup)
63 delete m_imageAnimationGroup;
65 m_imageAnimationGroup =
nullptr;
69#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
70inline QString questionForPermissionType(QWebEnginePermission::PermissionType permissionType)
72 switch (permissionType) {
73 case QWebEnginePermission::PermissionType::Geolocation:
74 return QObject::tr(
"Allow %1 to access your location information?");
75 case QWebEnginePermission::PermissionType::MediaAudioCapture:
76 return QObject::tr(
"Allow %1 to access your microphone?");
77 case QWebEnginePermission::PermissionType::MediaVideoCapture:
78 return QObject::tr(
"Allow %1 to access your webcam?");
79 case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
80 return QObject::tr(
"Allow %1 to access your microphone and webcam?");
81 case QWebEnginePermission::PermissionType::MouseLock:
82 return QObject::tr(
"Allow %1 to lock your mouse cursor?");
83 case QWebEnginePermission::PermissionType::DesktopVideoCapture:
84 return QObject::tr(
"Allow %1 to capture video of your desktop?");
85 case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture:
86 return QObject::tr(
"Allow %1 to capture audio and video of your desktop?");
87 case QWebEnginePermission::PermissionType::Notifications:
88 return QObject::tr(
"Allow %1 to show notification on your desktop?");
89 case QWebEnginePermission::PermissionType::ClipboardReadWrite:
90 return QObject::tr(
"Allow %1 to read from and write to the clipboard?");
91 case QWebEnginePermission::PermissionType::LocalFontsAccess:
92 return QObject::tr(
"Allow %1 to access fonts stored on this machine?");
93 case QWebEnginePermission::PermissionType::Unsupported:
100void CFrmWebView::setPage(QWebEnginePage *page)
102 CreateWebActionTrigger(page,QWebEnginePage::Forward);
103 CreateWebActionTrigger(page,QWebEnginePage::Back);
104 CreateWebActionTrigger(page,QWebEnginePage::Reload);
105 CreateWebActionTrigger(page,QWebEnginePage::Stop);
107 if (
auto oldPage = QWebEngineView::page()) {
108 oldPage->disconnect(
this);
110 QWebEngineView::setPage(page);
111 connect(page, &QWebEnginePage::linkHovered,
this, &CFrmWebView::sigLinkHovered);
112 connect(page, &QWebEnginePage::windowCloseRequested,
113 this, &CFrmWebView::sigCloseRequested);
114 connect(page, &QWebEnginePage::selectClientCertificate,
115 this, &CFrmWebView::slotSelectClientCertificate);
116 connect(page, &QWebEnginePage::authenticationRequired,
this,
117 &CFrmWebView::slotAuthenticationRequired);
118 connect(page, &QWebEnginePage::proxyAuthenticationRequired,
this,
119 &CFrmWebView::slotProxyAuthenticationRequired);
120 connect(page, &QWebEnginePage::registerProtocolHandlerRequested,
this,
122 #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
123 connect(page, &QWebEnginePage::certificateError,
124 this, &CFrmWebView::slotCertificateError);
125 connect(page, &QWebEnginePage::permissionRequested,
this,
126 &CFrmWebView::slotPermissionRequested);
128 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
129 connect(page, &QWebEnginePage::fileSystemAccessRequested,
this,
132 #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
133 connect(page, &QWebEnginePage::desktopMediaRequested,
this,
134 &CFrmWebView::slotDesktopMediaRequest);
135 connect(page, &QWebEnginePage::webAuthUxRequested,
136 this, &CFrmWebView::slotWebAuthUxRequested);
140int CFrmWebView::progress()
const
142 return m_loadProgress;
145QIcon CFrmWebView::favIcon()
const
147 QIcon favIcon = icon();
148 if (!favIcon.isNull())
151 if (m_loadProgress < 0) {
152 static QIcon errorIcon(
"dialog-error");
155 if (m_loadProgress < 100) {
156 static QIcon loadingIcon = QIcon::fromTheme(
"view-refresh");
160 static QIcon defaultIcon(
"text-html");
164QWebEngineView *CFrmWebView::createWindow(QWebEnginePage::WebWindowType type)
167 return m_pBrowser->createWindow(type);
171void CFrmWebView::CreateWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction webAction)
173 QAction *action = page->action(webAction);
174#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
175 connect(action, &QAction::enabledChanged, [
this, action, webAction](
bool enabled){
176 qDebug(log) <<
"webAction:" << webAction << enabled;
177 emit sigWebActionEnabledChanged(webAction, enabled);
180 connect(action, &QAction::changed, [
this, action, webAction]{
181 emit sigWebActionEnabledChanged(webAction, action->isEnabled());
186void CFrmWebView::contextMenuEvent(QContextMenuEvent *event)
189#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
190 menu = createStandardContextMenu();
192 menu = page()->createStandardContextMenu();
194 const QList<QAction *> actions = menu->actions();
195 auto inspectElement = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::InspectElement));
196 if (inspectElement == actions.cend()) {
197 auto viewSource = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::ViewSource));
198 if (viewSource == actions.cend())
199 menu->addSeparator();
201 QAction *action = menu->addAction(
"Open inspector");
202 connect(action, &QAction::triggered, [
this]() { emit sigDevToolsRequested(page());});
204 (*inspectElement)->setText(tr(
"Inspect element"));
206#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
208 QMenu *editImageAnimation =
new QMenu(tr(
"Image animation policy"));
210 m_imageAnimationGroup =
new QActionGroup(editImageAnimation);
211 m_imageAnimationGroup->setExclusive(
true);
213 QAction *disableImageAnimation =
214 editImageAnimation->addAction(tr(
"Disable all image animation"));
215 disableImageAnimation->setCheckable(
true);
216 m_imageAnimationGroup->addAction(disableImageAnimation);
217 connect(disableImageAnimation, &QAction::triggered, [
this]() {
218 handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Disallow);
220 QAction *allowImageAnimationOnce =
221 editImageAnimation->addAction(tr(
"Allow animated images, but only once"));
222 allowImageAnimationOnce->setCheckable(
true);
223 m_imageAnimationGroup->addAction(allowImageAnimationOnce);
224 connect(allowImageAnimationOnce, &QAction::triggered,
225 [
this]() { handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::AnimateOnce); });
226 QAction *allowImageAnimation = editImageAnimation->addAction(tr(
"Allow all animated images"));
227 allowImageAnimation->setCheckable(
true);
228 m_imageAnimationGroup->addAction(allowImageAnimation);
229 connect(allowImageAnimation, &QAction::triggered, [
this]() {
230 handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Allow);
233 switch (page()->settings()->imageAnimationPolicy()) {
234 case QWebEngineSettings::ImageAnimationPolicy::Allow:
235 allowImageAnimation->setChecked(
true);
237 case QWebEngineSettings::ImageAnimationPolicy::AnimateOnce:
238 allowImageAnimationOnce->setChecked(
true);
240 case QWebEngineSettings::ImageAnimationPolicy::Disallow:
241 disableImageAnimation->setChecked(
true);
244 allowImageAnimation->setChecked(
true);
248 menu->addMenu(editImageAnimation);
250 menu->popup(event->globalPos());
253void CFrmWebView::slotSelectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection)
255 qDebug(log) << Q_FUNC_INFO;
256 if(clientCertSelection.certificates().size() > 0) {
258 clientCertSelection.select(clientCertSelection.certificates().at(0));
262#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
263void CFrmWebView::slotCertificateError(QWebEngineCertificateError error)
265 qDebug(log) << Q_FUNC_INFO;
269 if (!error.isMainFrame()) {
270 error.rejectCertificate();
276 szMsg = error.description() +
"\n\n";
277 szMsg += tr(
"If you wish so, you may continue with an unverified certificate. "
278 "Accepting an unverified certificate mean you may not be connected with the host you tried to connect to.") +
279 "\n\n" + tr(
"Do you wish to override the security check and continue ?");
280 int nRet = QMessageBox::critical(window(), tr(
"Certificate Error"), szMsg,
281 QMessageBox::StandardButton::Yes
282 | QMessageBox::StandardButton::No,
283 QMessageBox::StandardButton::No);
284 if(QMessageBox::StandardButton::Yes == nRet)
285 error.acceptCertificate();
287 error.rejectCertificate();
291void CFrmWebView::slotAuthenticationRequired(
const QUrl &requestUrl, QAuthenticator *auth)
293 qDebug(log) << Q_FUNC_INFO;
322#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
323void CFrmWebView::slotPermissionRequested(QWebEnginePermission permission)
325 qDebug(log) << Q_FUNC_INFO;
326 QString title = tr(
"Permission Request");
327 QString question = questionForPermissionType(permission.permissionType()).arg(permission.origin().host());
328 if (!question.isEmpty() && QMessageBox::question(window(), title, question) == QMessageBox::Yes)
334void CFrmWebView::handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy policy)
336 qDebug(log) << Q_FUNC_INFO;
340 page()->settings()->setImageAnimationPolicy(policy);
344void CFrmWebView::slotProxyAuthenticationRequired(
const QUrl &url, QAuthenticator *auth,
345 const QString &proxyHost)
347 qDebug(log) << Q_FUNC_INFO;
375#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
376void CFrmWebView::slotDesktopMediaRequest(
const QWebEngineDesktopMediaRequest &request)
378 qDebug(log) << Q_FUNC_INFO;
380 request.selectScreen(request.screensModel()->index(0));
383void CFrmWebView::slotWebAuthUxRequested(QWebEngineWebAuthUxRequest *request)
385 qDebug(log) << Q_FUNC_INFO;
399void CFrmWebView::onStateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState state)
401 qDebug(log) << Q_FUNC_INFO;
418 QWebEngineRegisterProtocolHandlerRequest request)
420 qDebug(log) << Q_FUNC_INFO;
421 auto answer = QMessageBox::question(window(), tr(
"Permission Request"),
422 tr(
"Allow %1 to open all %2 links?")
423 .arg(request.origin().host())
424 .arg(request.scheme()));
425 if (answer == QMessageBox::Yes)
432#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
435 qDebug(log) << Q_FUNC_INFO;
437 switch (request.accessFlags()) {
438 case QWebEngineFileSystemAccessRequest::Read:
441 case QWebEngineFileSystemAccessRequest::Write:
442 accessType =
"write";
444 case QWebEngineFileSystemAccessRequest::Read | QWebEngineFileSystemAccessRequest::Write:
445 accessType =
"read and write";
451 auto answer = QMessageBox::question(window(), tr(
"File system access request"),
452 tr(
"Give %1 %2 access to %3?")
453 .arg(request.origin().host())
455 .arg(request.filePath().toString()));
456 if (answer == QMessageBox::Yes)
void slotFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request)
[registerProtocolHandlerRequested]
void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request)
[registerProtocolHandlerRequested]