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;
68#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
69inline QString questionForPermissionType(QWebEnginePermission::PermissionType permissionType)
71 switch (permissionType) {
72 case QWebEnginePermission::PermissionType::Geolocation:
73 return QObject::tr(
"Allow %1 to access your location information?");
74 case QWebEnginePermission::PermissionType::MediaAudioCapture:
75 return QObject::tr(
"Allow %1 to access your microphone?");
76 case QWebEnginePermission::PermissionType::MediaVideoCapture:
77 return QObject::tr(
"Allow %1 to access your webcam?");
78 case QWebEnginePermission::PermissionType::MediaAudioVideoCapture:
79 return QObject::tr(
"Allow %1 to access your microphone and webcam?");
80 case QWebEnginePermission::PermissionType::MouseLock:
81 return QObject::tr(
"Allow %1 to lock your mouse cursor?");
82 case QWebEnginePermission::PermissionType::DesktopVideoCapture:
83 return QObject::tr(
"Allow %1 to capture video of your desktop?");
84 case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture:
85 return QObject::tr(
"Allow %1 to capture audio and video of your desktop?");
86 case QWebEnginePermission::PermissionType::Notifications:
87 return QObject::tr(
"Allow %1 to show notification on your desktop?");
88 case QWebEnginePermission::PermissionType::ClipboardReadWrite:
89 return QObject::tr(
"Allow %1 to read from and write to the clipboard?");
90 case QWebEnginePermission::PermissionType::LocalFontsAccess:
91 return QObject::tr(
"Allow %1 to access fonts stored on this machine?");
92 case QWebEnginePermission::PermissionType::Unsupported:
99void CFrmWebView::setPage(QWebEnginePage *page)
101 CreateWebActionTrigger(page,QWebEnginePage::Forward);
102 CreateWebActionTrigger(page,QWebEnginePage::Back);
103 CreateWebActionTrigger(page,QWebEnginePage::Reload);
104 CreateWebActionTrigger(page,QWebEnginePage::Stop);
106 if (
auto oldPage = QWebEngineView::page()) {
107 oldPage->disconnect(
this);
109 QWebEngineView::setPage(page);
110 connect(page, &QWebEnginePage::linkHovered,
this, &CFrmWebView::sigLinkHovered);
111 connect(page, &QWebEnginePage::windowCloseRequested,
112 this, &CFrmWebView::sigCloseRequested);
113 connect(page, &QWebEnginePage::selectClientCertificate,
114 this, &CFrmWebView::slotSelectClientCertificate);
115 connect(page, &QWebEnginePage::authenticationRequired,
this,
116 &CFrmWebView::slotAuthenticationRequired);
117 connect(page, &QWebEnginePage::proxyAuthenticationRequired,
this,
118 &CFrmWebView::slotProxyAuthenticationRequired);
119 connect(page, &QWebEnginePage::registerProtocolHandlerRequested,
this,
121 #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
122 connect(page, &QWebEnginePage::certificateError,
123 this, &CFrmWebView::slotCertificateError);
124 connect(page, &QWebEnginePage::permissionRequested,
this,
125 &CFrmWebView::slotPermissionRequested);
127 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
128 connect(page, &QWebEnginePage::fileSystemAccessRequested,
this,
131 #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
132 connect(page, &QWebEnginePage::desktopMediaRequested,
this,
133 &CFrmWebView::slotDesktopMediaRequest);
134 connect(page, &QWebEnginePage::webAuthUxRequested,
135 this, &CFrmWebView::slotWebAuthUxRequested);
139int CFrmWebView::progress()
const
141 return m_loadProgress;
144QIcon CFrmWebView::favIcon()
const
146 QIcon favIcon = icon();
147 if (!favIcon.isNull())
150 if (m_loadProgress < 0) {
151 static QIcon errorIcon(
"dialog-error");
154 if (m_loadProgress < 100) {
155 static QIcon loadingIcon = QIcon::fromTheme(
"view-refresh");
159 static QIcon defaultIcon(
"text-html");
163QWebEngineView *CFrmWebView::createWindow(QWebEnginePage::WebWindowType type)
166 return m_pBrowser->createWindow(type);
170void CFrmWebView::CreateWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction webAction)
172 QAction *action = page->action(webAction);
173#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
174 connect(action, &QAction::enabledChanged, [
this, action, webAction](
bool enabled){
175 qDebug(log) <<
"webAction:" << webAction << enabled;
176 emit sigWebActionEnabledChanged(webAction, enabled);
179 connect(action, &QAction::changed, [
this, action, webAction]{
180 emit sigWebActionEnabledChanged(webAction, action->isEnabled());
185void CFrmWebView::contextMenuEvent(QContextMenuEvent *event)
188#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
189 menu = createStandardContextMenu();
191 menu = page()->createStandardContextMenu();
193 const QList<QAction *> actions = menu->actions();
194 auto inspectElement = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::InspectElement));
195 if (inspectElement == actions.cend()) {
196 auto viewSource = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::ViewSource));
197 if (viewSource == actions.cend())
198 menu->addSeparator();
200 QAction *action = menu->addAction(
"Open inspector");
201 connect(action, &QAction::triggered, [
this]() { emit sigDevToolsRequested(page());});
203 (*inspectElement)->setText(tr(
"Inspect element"));
205#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
207 QMenu *editImageAnimation =
new QMenu(tr(
"Image animation policy"));
209 m_imageAnimationGroup =
new QActionGroup(editImageAnimation);
210 m_imageAnimationGroup->setExclusive(
true);
212 QAction *disableImageAnimation =
213 editImageAnimation->addAction(tr(
"Disable all image animation"));
214 disableImageAnimation->setCheckable(
true);
215 m_imageAnimationGroup->addAction(disableImageAnimation);
216 connect(disableImageAnimation, &QAction::triggered, [
this]() {
217 handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Disallow);
219 QAction *allowImageAnimationOnce =
220 editImageAnimation->addAction(tr(
"Allow animated images, but only once"));
221 allowImageAnimationOnce->setCheckable(
true);
222 m_imageAnimationGroup->addAction(allowImageAnimationOnce);
223 connect(allowImageAnimationOnce, &QAction::triggered,
224 [
this]() { handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::AnimateOnce); });
225 QAction *allowImageAnimation = editImageAnimation->addAction(tr(
"Allow all animated images"));
226 allowImageAnimation->setCheckable(
true);
227 m_imageAnimationGroup->addAction(allowImageAnimation);
228 connect(allowImageAnimation, &QAction::triggered, [
this]() {
229 handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Allow);
232 switch (page()->settings()->imageAnimationPolicy()) {
233 case QWebEngineSettings::ImageAnimationPolicy::Allow:
234 allowImageAnimation->setChecked(
true);
236 case QWebEngineSettings::ImageAnimationPolicy::AnimateOnce:
237 allowImageAnimationOnce->setChecked(
true);
239 case QWebEngineSettings::ImageAnimationPolicy::Disallow:
240 disableImageAnimation->setChecked(
true);
243 allowImageAnimation->setChecked(
true);
247 menu->addMenu(editImageAnimation);
249 menu->popup(event->globalPos());
252void CFrmWebView::slotSelectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection)
254 qDebug(log) << Q_FUNC_INFO;
255 if(clientCertSelection.certificates().size() > 0) {
257 clientCertSelection.select(clientCertSelection.certificates().at(0));
261#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
262void CFrmWebView::slotCertificateError(QWebEngineCertificateError error)
264 qDebug(log) << Q_FUNC_INFO;
268 if (!error.isMainFrame()) {
269 error.rejectCertificate();
275 szMsg = error.description() +
"\n\n";
276 szMsg += tr(
"If you wish so, you may continue with an unverified certificate. "
277 "Accepting an unverified certificate mean you may not be connected with the host you tried to connect to.") +
278 "\n\n" + tr(
"Do you wish to override the security check and continue ?");
279 int nRet = QMessageBox::critical(window(), tr(
"Certificate Error"), szMsg,
280 QMessageBox::StandardButton::Yes
281 | QMessageBox::StandardButton::No,
282 QMessageBox::StandardButton::No);
283 if(QMessageBox::StandardButton::Yes == nRet)
284 error.acceptCertificate();
286 error.rejectCertificate();
290void CFrmWebView::slotAuthenticationRequired(
const QUrl &requestUrl, QAuthenticator *auth)
292 qDebug(log) << Q_FUNC_INFO;
321#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
322void CFrmWebView::slotPermissionRequested(QWebEnginePermission permission)
324 qDebug(log) << Q_FUNC_INFO;
325 QString title = tr(
"Permission Request");
326 QString question = questionForPermissionType(permission.permissionType()).arg(permission.origin().host());
327 if (!question.isEmpty() && QMessageBox::question(window(), title, question) == QMessageBox::Yes)
333void CFrmWebView::handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy policy)
335 qDebug(log) << Q_FUNC_INFO;
339 page()->settings()->setImageAnimationPolicy(policy);
343void CFrmWebView::slotProxyAuthenticationRequired(
const QUrl &url, QAuthenticator *auth,
344 const QString &proxyHost)
346 qDebug(log) << Q_FUNC_INFO;
374#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
375void CFrmWebView::slotDesktopMediaRequest(
const QWebEngineDesktopMediaRequest &request)
377 qDebug(log) << Q_FUNC_INFO;
379 request.selectScreen(request.screensModel()->index(0));
382void CFrmWebView::slotWebAuthUxRequested(QWebEngineWebAuthUxRequest *request)
384 qDebug(log) << Q_FUNC_INFO;
398void CFrmWebView::onStateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState state)
400 qDebug(log) << Q_FUNC_INFO;
417 QWebEngineRegisterProtocolHandlerRequest request)
419 qDebug(log) << Q_FUNC_INFO;
420 auto answer = QMessageBox::question(window(), tr(
"Permission Request"),
421 tr(
"Allow %1 to open all %2 links?")
422 .arg(request.origin().host())
423 .arg(request.scheme()));
424 if (answer == QMessageBox::Yes)
431#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
434 qDebug(log) << Q_FUNC_INFO;
436 switch (request.accessFlags()) {
437 case QWebEngineFileSystemAccessRequest::Read:
440 case QWebEngineFileSystemAccessRequest::Write:
441 accessType =
"write";
443 case QWebEngineFileSystemAccessRequest::Read | QWebEngineFileSystemAccessRequest::Write:
444 accessType =
"read and write";
450 auto answer = QMessageBox::question(window(), tr(
"File system access request"),
451 tr(
"Give %1 %2 access to %3?")
452 .arg(request.origin().host())
454 .arg(request.filePath().toString()));
455 if (answer == QMessageBox::Yes)
void slotFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request)
[registerProtocolHandlerRequested]
void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request)
[registerProtocolHandlerRequested]