Falkon Develop
Cross-platform Qt-based web browser
webpage.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "webpage.h"
19#include "tabbedwebview.h"
20#include "browserwindow.h"
21#include "pluginproxy.h"
22#include "downloadmanager.h"
23#include "mainapplication.h"
24#include "checkboxdialog.h"
25#include "qztools.h"
26#include "speeddial.h"
27#include "autofill.h"
28#include "popupwebview.h"
29#include "popupwindow.h"
30#include "iconprovider.h"
31#include "qzsettings.h"
32#include "useragentmanager.h"
33#include "delayedfilewatcher.h"
36#include "sitesettingsmanager.h"
38#include "tabwidget.h"
39#include "networkmanager.h"
40#include "webhittestresult.h"
41#include "ui_jsconfirm.h"
42#include "ui_jsalert.h"
43#include "ui_jsprompt.h"
44#include "passwordmanager.h"
45#include "scripts.h"
46#include "ocssupport.h"
47
48#include <iostream>
49
50#include <QDir>
51#include <QMouseEvent>
52#include <QWebChannel>
53#include <QWebEngineHistory>
54#include <QWebEngineSettings>
55#include <QTimer>
56#include <QDesktopServices>
57#include <QMessageBox>
58#include <QFileDialog>
59#include <QAuthenticator>
60#include <QPushButton>
61#include <QUrlQuery>
62#include <QtWebEngineWidgetsVersion>
63
64#include <QWebEngineRegisterProtocolHandlerRequest>
65
66QString WebPage::s_lastUploadLocation = QDir::homePath();
67QUrl WebPage::s_lastUnsupportedUrl;
68QElapsedTimer WebPage::s_lastUnsupportedUrlTime;
70
71static const bool kEnableJsOutput = qEnvironmentVariableIsSet("FALKON_ENABLE_JS_OUTPUT");
72static const bool kEnableJsNonBlockDialogs = qEnvironmentVariableIsSet("FALKON_ENABLE_JS_NONBLOCK_DIALOGS");
73
74WebPage::WebPage(QObject* parent)
75 : QWebEnginePage(mApp->webProfile(), parent)
76 , m_fileWatcher(nullptr)
77 , m_runningLoop(nullptr)
78 , m_loadProgress(100)
79 , m_blockAlerts(false)
80 , m_secureStatus(false)
81{
82 auto *channel = new QWebChannel(this);
84 setWebChannel(channel, SafeJsWorld);
85
86 connect(this, &QWebEnginePage::loadProgress, this, &WebPage::progress);
87 connect(this, &QWebEnginePage::loadFinished, this, &WebPage::finished);
88 connect(this, &QWebEnginePage::urlChanged, this, &WebPage::urlChanged);
89 connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionRequested);
90 connect(this, &QWebEnginePage::windowCloseRequested, this, &WebPage::windowCloseRequested);
91 connect(this, &QWebEnginePage::fullScreenRequested, this, &WebPage::fullScreenRequested);
92 connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessTerminated);
93 connect(this, &QWebEnginePage::certificateError, this, &WebPage::onCertificateError);
94
95 connect(this, &QWebEnginePage::authenticationRequired, this, [this](const QUrl &url, QAuthenticator *auth) {
96 mApp->networkManager()->authentication(url, auth, view());
97 });
98
99 connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, [this](const QUrl &, QAuthenticator *auth, const QString &proxyHost) {
100 mApp->networkManager()->proxyAuthentication(proxyHost, auth, view());
101 });
102
103 // Workaround QWebEnginePage not scrolling to anchors when opened in background tab
104 m_contentsResizedConnection = connect(this, &QWebEnginePage::contentsSizeChanged, this, [this]() {
105 const QString fragment = url().fragment();
106 if (!fragment.isEmpty()) {
107 runJavaScript(Scripts::scrollToAnchor(fragment));
108 }
109 disconnect(m_contentsResizedConnection);
110 });
111
112 // Workaround for broken load started/finished signals in QtWebEngine 5.10, 5.11
113 connect(this, &QWebEnginePage::loadProgress, this, [this](int progress) {
114 if (progress == 100) {
115 Q_EMIT loadFinished(true);
116 }
117 });
118
119 connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, [this](QWebEngineRegisterProtocolHandlerRequest request) {
120 delete m_registerProtocolHandlerRequest;
121 m_registerProtocolHandlerRequest = new QWebEngineRegisterProtocolHandlerRequest(request);
122 });
123 connect(this, &QWebEnginePage::printRequested, this, &WebPage::printRequested);
124 connect(this, &QWebEnginePage::selectClientCertificate, this, [this](QWebEngineClientCertificateSelection selection) {
125 // TODO: It should prompt user
126 selection.select(selection.certificates().at(0));
127 });
128}
129
131{
132 delete m_registerProtocolHandlerRequest;
133
134 if (m_runningLoop) {
135 m_runningLoop->exit(1);
136 m_runningLoop = nullptr;
137 }
138}
139
141{
142 return static_cast<WebView*>(QWebEngineView::forPage(this));
143}
144
145bool WebPage::execPrintPage(QPrinter *printer, int timeout)
146{
147 QPointer<QEventLoop> loop = new QEventLoop;
148 bool result = false;
149 QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit);
150
151 connect(view(), &QWebEngineView::printFinished, this, [loop, &result](bool res) {
152 if (loop && loop->isRunning()) {
153 result = res;
154 loop->quit();
155 }
156 });
157 view()->print(printer);
158
159 loop->exec();
160 delete loop;
161
162 return result;
163}
164
165QVariant WebPage::execJavaScript(const QString &scriptSource, quint32 worldId, int timeout)
166{
167 QPointer<QEventLoop> loop = new QEventLoop;
168 QVariant result;
169 QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit);
170
171 runJavaScript(scriptSource, worldId, [loop, &result](const QVariant &res) {
172 if (loop && loop->isRunning()) {
173 result = res;
174 loop->quit();
175 }
176 });
177
178 loop->exec(QEventLoop::ExcludeUserInputEvents);
179 delete loop;
180
181 return result;
182}
183
184QPointF WebPage::mapToViewport(const QPointF &pos) const
185{
186 return QPointF(pos.x() / zoomFactor(), pos.y() / zoomFactor());
187}
188
190{
191 return WebHitTestResult(this, pos);
192}
193
194void WebPage::scroll(int x, int y)
195{
196 runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), SafeJsWorld);
197}
198
199void WebPage::setScrollPosition(const QPointF &pos)
200{
201 const QPointF v = mapToViewport(pos.toPoint());
202 runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), SafeJsWorld);
203}
204
206{
207 return m_runningLoop;
208}
209
211{
212 return m_loadProgress < 100;
213}
214
215// static
217{
218 return QStringList{
219 QSL("http"),
220 QSL("https"),
221 QSL("file"),
222 QSL("ftp"),
223 QSL("data"),
224 QSL("about"),
225 QSL("view-source"),
226 QSL("chrome")
227 };
228}
229
230// static
232{
233 if (s_supportedSchemes.isEmpty()) {
235 }
236 return s_supportedSchemes;
237}
238
239// static
240void WebPage::addSupportedScheme(const QString &scheme)
241{
243 if (!s_supportedSchemes.contains(scheme)) {
244 s_supportedSchemes.append(scheme);
245 }
246}
247
248// static
249void WebPage::removeSupportedScheme(const QString &scheme)
250{
251 s_supportedSchemes.removeOne(scheme);
252}
253
254void WebPage::urlChanged(const QUrl &url)
255{
256 Q_UNUSED(url)
257
258 if (isLoading()) {
259 m_blockAlerts = false;
260 }
261}
262
263void WebPage::progress(int prog)
264{
265 m_loadProgress = prog;
266
267 bool secStatus = url().scheme() == QL1S("https");
268
269 if (secStatus != m_secureStatus) {
270 m_secureStatus = secStatus;
271 Q_EMIT privacyChanged(secStatus);
272 }
273}
274
276{
277 progress(100);
278
279 // File scheme watcher
280 if (url().scheme() == QLatin1String("file")) {
281 QFileInfo info(url().toLocalFile());
282 if (info.isFile()) {
283 if (!m_fileWatcher) {
284 m_fileWatcher = new DelayedFileWatcher(this);
285 connect(m_fileWatcher, &DelayedFileWatcher::delayedFileChanged, this, &WebPage::watchedFileChanged);
286 }
287
288 const QString filePath = url().toLocalFile();
289
290 if (QFile::exists(filePath) && !m_fileWatcher->files().contains(filePath)) {
291 m_fileWatcher->addPath(filePath);
292 }
293 }
294 }
295 else if (m_fileWatcher && !m_fileWatcher->files().isEmpty()) {
296 m_fileWatcher->removePaths(m_fileWatcher->files());
297 }
298
299 // AutoFill
300 m_autoFillUsernames = mApp->autoFill()->completePage(this, url());
301}
302
303void WebPage::watchedFileChanged(const QString &file)
304{
305 if (url().toLocalFile() == file) {
306 triggerAction(QWebEnginePage::Reload);
307 }
308}
309
310void WebPage::handleUnknownProtocol(const QUrl &url)
311{
312 const QString protocol = url.scheme();
313
314 if (protocol == QLatin1String("mailto")) {
315 desktopServicesOpen(url);
316 return;
317 }
318
319 if (qzSettings->blockedProtocols.contains(protocol)) {
320 qDebug() << "WebPage::handleUnknownProtocol Protocol" << protocol << "is blocked!";
321 return;
322 }
323
324 if (qzSettings->autoOpenProtocols.contains(protocol)) {
325 desktopServicesOpen(url);
326 return;
327 }
328
329 CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, view());
330 dialog.setDefaultButton(QMessageBox::Yes);
331
332 const QString wrappedUrl = QzTools::alignTextToWidth(url.toString(), QSL("<br/>"), dialog.fontMetrics(), 450);
333 const QString text = tr("Falkon cannot handle <b>%1:</b> links. The requested link "
334 "is <ul><li>%2</li></ul>Do you want Falkon to try "
335 "open this link in system application?").arg(protocol, wrappedUrl);
336
337 dialog.setText(text);
338 dialog.setCheckBoxText(tr("Remember my choice for this protocol"));
339 dialog.setWindowTitle(tr("External Protocol Request"));
340 dialog.setIcon(QMessageBox::Question);
341
342 switch (dialog.exec()) {
343 case QMessageBox::Yes:
344 if (dialog.isChecked()) {
345 qzSettings->autoOpenProtocols.append(protocol);
346 qzSettings->saveSettings();
347 }
348
349
350 QDesktopServices::openUrl(url);
351 break;
352
353 case QMessageBox::No:
354 if (dialog.isChecked()) {
355 qzSettings->blockedProtocols.append(protocol);
356 qzSettings->saveSettings();
357 }
358
359 break;
360
361 default:
362 break;
363 }
364}
365
366void WebPage::desktopServicesOpen(const QUrl &url)
367{
368 // Open same url only once in 2 secs
369 const int sameUrlTimeout = 2 * 1000;
370
371 if ((s_lastUnsupportedUrl != url) || (!s_lastUnsupportedUrlTime.isValid()) || (s_lastUnsupportedUrlTime.elapsed() > sameUrlTimeout)) {
372 s_lastUnsupportedUrl = url;
373 s_lastUnsupportedUrlTime.restart();
374 QDesktopServices::openUrl(url);
375 }
376 else {
377 qWarning() << "WebPage::desktopServicesOpen Url" << url << "has already been opened!\n"
378 "Ignoring it to prevent infinite loop!";
379 }
380}
381
382void WebPage::windowCloseRequested()
383{
384 if (!view())
385 return;
386 view()->closeView();
387}
388
389void WebPage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest)
390{
391 view()->requestFullScreen(fullScreenRequest.toggleOn());
392
393 const bool accepted = fullScreenRequest.toggleOn() == view()->isFullScreen();
394
395 if (accepted)
396 fullScreenRequest.accept();
397 else
398 fullScreenRequest.reject();
399}
400
401void WebPage::featurePermissionRequested(const QUrl &origin, const QWebEnginePage::Feature &feature)
402{
403 if (feature == MouseLock && view()->isFullScreen())
404 setFeaturePermission(origin, feature, PermissionGrantedByUser);
405 else
406 mApp->html5PermissionsManager()->requestPermissions(this, origin, feature);
407}
408
409void WebPage::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
410{
411 Q_UNUSED(exitCode)
412
413 if (terminationStatus == NormalTerminationStatus)
414 return;
415
416 QTimer::singleShot(0, this, [this]() {
417 QString page = QzTools::readAllFileContents(QSL(":html/tabcrash.html"));
418 page.replace(QL1S("%IMAGE%"), QzTools::pixmapToDataUrl(IconProvider::standardIcon(QStyle::SP_MessageBoxWarning).pixmap(45)).toString());
419 page.replace(QL1S("%TITLE%"), tr("Failed loading page"));
420 page.replace(QL1S("%HEADING%"), tr("Failed loading page"));
421 page.replace(QL1S("%LI-1%"), tr("Something went wrong while loading this page."));
422 page.replace(QL1S("%LI-2%"), tr("Try reloading the page or closing some tabs to make more memory available."));
423 page.replace(QL1S("%RELOAD-PAGE%"), tr("Reload page"));
425 setHtml(page, url());
426 });
427}
428
429bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
430{
431 if (mApp->isClosing()) {
432 return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
433 }
434
435 if (!mApp->plugins()->acceptNavigationRequest(this, url, type, isMainFrame))
436 return false;
437
438 if (url.scheme() == QL1S("falkon")) {
439 if (url.path() == QL1S("AddSearchProvider")) {
440 QUrlQuery query(url);
441 mApp->searchEnginesManager()->addEngine(QUrl(query.queryItemValue(QSL("url"))));
442 return false;
443 }
444 }
445
446 if (url.scheme() == QL1S("ocs") && OcsSupport::instance()->handleUrl(url)) {
447 return false;
448 }
449
450 const bool result = QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
451
452 if (result) {
453 if (isMainFrame) {
454 const bool isWeb = url.scheme() == QL1S("http") || url.scheme() == QL1S("https") || url.scheme() == QL1S("file");
455
456 if (isWeb) {
457 auto webAttributes = mApp->siteSettingsManager()->getWebAttributes(url);
458 if (!webAttributes.empty()) {
459 for (auto it = webAttributes.begin(); it != webAttributes.end(); ++it) {
460 settings()->setAttribute(it.key(), it.value());
461 }
462 }
463 else {
464 auto const webAttributes = mApp->siteSettingsManager()->getSupportedAttribute();
465 for (auto attribute : webAttributes) {
466 settings()->setAttribute(attribute, mApp->webSettings()->testAttribute(attribute));
467 }
468 }
469 }
470 else {
471 settings()->setAttribute(QWebEngineSettings::AutoLoadImages, true);
472 settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
473 settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
474 settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true);
475 settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste, false);
476 settings()->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, false);
477 settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
478 settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, mApp->webSettings()->testAttribute(QWebEngineSettings::FullScreenSupportEnabled));
479 settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, false);
480 settings()->setAttribute(QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false);
481 settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, mApp->webSettings()->testAttribute(QWebEngineSettings::PlaybackRequiresUserGesture));
482 settings()->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, false);
483 }
484 }
485 Q_EMIT navigationRequestAccepted(url, type, isMainFrame);
486 }
487
488 return result;
489}
490
491void WebPage::onCertificateError(QWebEngineCertificateError error)
492{
493 auto mutableError = const_cast<QWebEngineCertificateError&>(error);
494 if (mApp->networkManager()->certificateError(mutableError, view()))
495 mutableError.acceptCertificate();
496 else
497 mutableError.rejectCertificate();
498}
499
500QStringList WebPage::chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes)
501{
502 Q_UNUSED(acceptedMimeTypes);
503
504 QStringList files;
505 QString suggestedFileName = s_lastUploadLocation;
506 if (!oldFiles.isEmpty())
507 suggestedFileName = oldFiles.at(0);
508
509 switch (mode) {
510 case FileSelectOpen:
511 files = QStringList(QzTools::getOpenFileName(QSL("WebPage-ChooseFile"), view(), tr("Choose file..."), suggestedFileName));
512 break;
513
514 case FileSelectOpenMultiple:
515 files = QzTools::getOpenFileNames(QSL("WebPage-ChooseFile"), view(), tr("Choose files..."), suggestedFileName);
516 break;
517
518 default:
519 files = QWebEnginePage::chooseFiles(mode, oldFiles, acceptedMimeTypes);
520 break;
521 }
522
523 if (!files.isEmpty())
524 s_lastUploadLocation = files.at(0);
525
526 return files;
527}
528
529QStringList WebPage::autoFillUsernames() const
530{
531 return m_autoFillUsernames;
532}
533
535{
536 if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) {
537 return m_registerProtocolHandlerRequest->origin();
538 }
539 return {};
540}
541
543{
544 if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) {
545 return m_registerProtocolHandlerRequest->scheme();
546 }
547 return {};
548}
549
550bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result)
551{
552 if (!kEnableJsNonBlockDialogs) {
553 return QWebEnginePage::javaScriptPrompt(securityOrigin, msg, defaultValue, result);
554 }
555
556 if (m_runningLoop) {
557 return false;
558 }
559
560 auto *widget = new QFrame(view()->overlayWidget());
561
562 widget->setObjectName("jsFrame");
563 auto* ui = new Ui_jsPrompt();
564 ui->setupUi(widget);
565 ui->message->setText(msg);
566 ui->lineEdit->setText(defaultValue);
567 ui->lineEdit->setFocus();
568 widget->resize(view()->size());
569 widget->show();
570
571 QAbstractButton *clicked = nullptr;
572 connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [&](QAbstractButton *button) {
573 clicked = button;
574 });
575
576 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize));
577 connect(ui->lineEdit, SIGNAL(returnPressed()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(animateClick()));
578
579 QEventLoop eLoop;
580 m_runningLoop = &eLoop;
581 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit);
582
583 if (eLoop.exec() == 1) {
584 return result;
585 }
586 m_runningLoop = nullptr;
587
588 QString x = ui->lineEdit->text();
589 bool _result = ui->buttonBox->buttonRole(clicked) == QDialogButtonBox::AcceptRole;
590 *result = x;
591
592 delete widget;
593 view()->setFocus();
594
595 return _result;
596}
597
598bool WebPage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg)
599{
600 if (!kEnableJsNonBlockDialogs) {
601 return QWebEnginePage::javaScriptConfirm(securityOrigin, msg);
602 }
603
604 if (m_runningLoop) {
605 return false;
606 }
607
608 auto *widget = new QFrame(view()->overlayWidget());
609
610 widget->setObjectName("jsFrame");
611 auto* ui = new Ui_jsConfirm();
612 ui->setupUi(widget);
613 ui->message->setText(msg);
614 ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
615 widget->resize(view()->size());
616 widget->show();
617
618 QAbstractButton *clicked = nullptr;
619 connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [&](QAbstractButton *button) {
620 clicked = button;
621 });
622
623 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize));
624
625 QEventLoop eLoop;
626 m_runningLoop = &eLoop;
627 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit);
628
629 if (eLoop.exec() == 1) {
630 return false;
631 }
632 m_runningLoop = nullptr;
633
634 bool result = ui->buttonBox->buttonRole(clicked) == QDialogButtonBox::AcceptRole;
635
636 delete widget;
637 view()->setFocus();
638
639 return result;
640}
641
642void WebPage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg)
643{
644 Q_UNUSED(securityOrigin)
645
646 if (m_blockAlerts || m_runningLoop) {
647 return;
648 }
649
650 if (!kEnableJsNonBlockDialogs) {
651 QString title = tr("JavaScript alert");
652 if (!url().host().isEmpty()) {
653 title.append(QSL(" - %1").arg(url().host()));
654 }
655
656 CheckBoxDialog dialog(QMessageBox::Ok, view());
657 dialog.setDefaultButton(QMessageBox::Ok);
658 dialog.setWindowTitle(title);
659 dialog.setText(msg);
660 dialog.setCheckBoxText(tr("Prevent this page from creating additional dialogs"));
661 dialog.setIcon(QMessageBox::Information);
662 dialog.exec();
663
664 m_blockAlerts = dialog.isChecked();
665 return;
666 }
667
668 auto *widget = new QFrame(view()->overlayWidget());
669
670 widget->setObjectName("jsFrame");
671 auto* ui = new Ui_jsAlert();
672 ui->setupUi(widget);
673 ui->message->setText(msg);
674 ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
675 widget->resize(view()->size());
676 widget->show();
677
678 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize));
679
680 QEventLoop eLoop;
681 m_runningLoop = &eLoop;
682 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit);
683
684 if (eLoop.exec() == 1) {
685 return;
686 }
687 m_runningLoop = nullptr;
688
689 m_blockAlerts = ui->preventAlerts->isChecked();
690
691 delete widget;
692
693 view()->setFocus();
694}
695
696void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID)
697{
698 if (!kEnableJsOutput) {
699 return;
700 }
701
702 switch (level) {
703 case InfoMessageLevel:
704 std::cout << "[I] ";
705 break;
706
707 case WarningMessageLevel:
708 std::cout << "[W] ";
709 break;
710
711 case ErrorMessageLevel:
712 std::cout << "[E] ";
713 break;
714 }
715
716 std::cout << qPrintable(sourceID) << ":" << lineNumber << " " << qPrintable(message);
717}
718
719QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type)
720{
721 auto *tView = qobject_cast<TabbedWebView*>(view());
722 BrowserWindow *window = tView ? tView->browserWindow() : mApp->getWindow();
723
724 auto createTab = [=](Qz::NewTabPositionFlags pos) {
725 int index = window->tabWidget()->addView(QUrl(), pos);
726 TabbedWebView* view = window->weView(index);
727 view->setPage(new WebPage);
728 if (tView) {
729 tView->webTab()->addChildTab(view->webTab());
730 }
731 // Workaround focus issue when creating tab
732 if (pos.testFlag(Qz::NT_SelectedTab)) {
733 QPointer<TabbedWebView> pview = view;
734 pview->setFocus();
735 QTimer::singleShot(100, this, [pview]() {
736 if (pview && pview->webTab()->isCurrentTab()) {
737 pview->setFocus();
738 }
739 });
740 }
741 return view->page();
742 };
743
744 switch (type) {
745 case QWebEnginePage::WebBrowserWindow: {
746 BrowserWindow *window = mApp->createWindow(Qz::BW_NewWindow);
747 auto *page = new WebPage;
748 window->setStartPage(page);
749 return page;
750 }
751
752 case QWebEnginePage::WebDialog:
753 if (!qzSettings->openPopupsInTabs) {
754 auto* view = new PopupWebView;
755 view->setPage(new WebPage);
756 auto* popup = new PopupWindow(view);
757 popup->show();
758 window->addDeleteOnCloseWidget(popup);
759 return view->page();
760 }
761 // else fallthrough
762
763 case QWebEnginePage::WebBrowserTab:
764 return createTab(Qz::NT_CleanSelectedTab);
765
766 case QWebEnginePage::WebBrowserBackgroundTab:
767 return createTab(Qz::NT_CleanNotSelectedTab);
768
769 default:
770 break;
771 }
772
773 return nullptr;
774}
void setStartPage(WebPage *page)
TabWidget * tabWidget() const
void addDeleteOnCloseWidget(QWidget *widget)
TabbedWebView * weView() const
bool isChecked() const
void setCheckBoxText(const QString &text)
void delayedFileChanged(const QString &path)
static void setupWebChannel(QWebChannel *webChannel, WebPage *page)
static QIcon standardIcon(QStyle::StandardPixmap icon)
static OcsSupport * instance()
Definition: ocssupport.cpp:115
static QStringList getOpenFileNames(const QString &name, QWidget *parent=nullptr, const QString &caption=QString(), const QString &dir=QString(), const QString &filter=QString(), QString *selectedFilter=nullptr, QFileDialog::Options options=QFileDialog::Options())
Definition: qztools.cpp:684
static QUrl pixmapToDataUrl(const QPixmap &pix)
Definition: qztools.cpp:83
static QString readAllFileContents(const QString &filename)
Definition: qztools.cpp:98
static QString applyDirectionToPage(QString &pageContents)
Definition: qztools.cpp:439
static QString getOpenFileName(const QString &name, QWidget *parent=nullptr, const QString &caption=QString(), const QString &dir=QString(), const QString &filter=QString(), QString *selectedFilter=nullptr, QFileDialog::Options options=QFileDialog::Options())
Definition: qztools.cpp:659
static QString alignTextToWidth(const QString &string, const QString &text, const QFontMetrics &metrics, int width)
Definition: qztools.cpp:348
static QString scrollToAnchor(const QString &anchor)
Definition: scripts.cpp:368
int addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine=false, bool pinned=false)
Definition: tabwidget.cpp:314
void privacyChanged(bool status)
~WebPage() override
Definition: webpage.cpp:130
bool isRunningLoop()
Definition: webpage.cpp:205
QVariant execJavaScript(const QString &scriptSource, quint32 worldId=UnsafeJsWorld, int timeout=500)
Definition: webpage.cpp:165
bool javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString *result) override
Definition: webpage.cpp:550
bool execPrintPage(QPrinter *printer, int timeout=1000)
Definition: webpage.cpp:145
void finished()
Definition: webpage.cpp:275
static QStringList internalSchemes()
Definition: webpage.cpp:216
bool javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) override
Definition: webpage.cpp:598
void printRequested()
void progress(int prog)
Definition: webpage.cpp:263
static void removeSupportedScheme(const QString &scheme)
Definition: webpage.cpp:249
WebView * view() const
Definition: webpage.cpp:140
bool isLoading() const
Definition: webpage.cpp:210
void navigationRequestAccepted(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
QStringList autoFillUsernames() const
Definition: webpage.cpp:529
void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) override
Definition: webpage.cpp:696
void setScrollPosition(const QPointF &pos)
Definition: webpage.cpp:199
WebPage(QObject *parent=nullptr)
Definition: webpage.cpp:74
static QStringList supportedSchemes()
Definition: webpage.cpp:231
@ SafeJsWorld
Definition: webpage.h:45
WebHitTestResult hitTestContent(const QPoint &pos) const
Definition: webpage.cpp:189
void scroll(int x, int y)
Definition: webpage.cpp:194
QString registerProtocolHandlerRequestScheme() const
Definition: webpage.cpp:542
void javaScriptAlert(const QUrl &securityOrigin, const QString &msg) override
Definition: webpage.cpp:642
static void addSupportedScheme(const QString &scheme)
Definition: webpage.cpp:240
QPointF mapToViewport(const QPointF &pos) const
Definition: webpage.cpp:184
QUrl registerProtocolHandlerRequestUrl() const
Definition: webpage.cpp:534
virtual void closeView()=0
WebPage * page() const
Definition: webview.cpp:132
virtual void requestFullScreen(bool enable)=0
virtual bool isFullScreen()=0
void setPage(WebPage *page)
Definition: webview.cpp:137
void viewportResized(QSize)
#define mApp
@ BW_NewWindow
Definition: qzcommon.h:67
@ NT_CleanSelectedTab
Definition: qzcommon.h:107
@ NT_SelectedTab
Definition: qzcommon.h:97
@ NT_CleanNotSelectedTab
Definition: qzcommon.h:108
#define QL1S(x)
Definition: qzcommon.h:44
#define QSL(x)
Definition: qzcommon.h:40
#define qzSettings
Definition: qzsettings.h:69
QStringList s_supportedSchemes
Definition: webpage.cpp:69