Falkon Develop
Cross-platform Qt-based web browser
webview.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 "webview.h"
19#include "webpage.h"
20#include "mainapplication.h"
21#include "qztools.h"
22#include "iconprovider.h"
23#include "history.h"
24#include "pluginproxy.h"
25#include "downloadmanager.h"
26#include "siteinfo.h"
28#include "browsinglibrary.h"
29#include "bookmarkstools.h"
30#include "settings.h"
31#include "qzsettings.h"
32#include "enhancedmenu.h"
33#include "locationbar.h"
34#include "webinspector.h"
35#include "scripts.h"
36#include "webhittestresult.h"
37#include "webscrollbarmanager.h"
38
39#include <iostream>
40
41#include <QDir>
42#include <QTimer>
43#include <QDesktopServices>
44#include <QWebEngineHistory>
45#include <QClipboard>
46#include <QMimeData>
47#include <QWebEngineContextMenuRequest>
48#include <QStackedLayout>
49#include <QScrollBar>
50#include <QPrintDialog>
51#include <QPrinter>
52#include <QQuickWidget>
53#include <QtWebEngineWidgetsVersion>
54
55bool WebView::s_forceContextMenuOnMouseRelease = false;
56
57WebView::WebView(QWidget* parent)
58 : QWebEngineView(parent)
59 , m_progress(100)
60 , m_backgroundActivity(false)
61 , m_page(nullptr)
62 , m_firstLoad(false)
63{
64 connect(this, &QWebEngineView::loadStarted, this, &WebView::slotLoadStarted);
65 connect(this, &QWebEngineView::loadProgress, this, &WebView::slotLoadProgress);
66 connect(this, &QWebEngineView::loadFinished, this, &WebView::slotLoadFinished);
67 connect(this, &QWebEngineView::iconChanged, this, &WebView::slotIconChanged);
68 connect(this, &QWebEngineView::urlChanged, this, &WebView::slotUrlChanged);
69 connect(this, &QWebEngineView::titleChanged, this, &WebView::slotTitleChanged);
70
71 m_currentZoomLevel = zoomLevels().indexOf(100);
72
73 setAcceptDrops(true);
74 installEventFilter(this);
75 if (parentWidget()) {
76 parentWidget()->installEventFilter(this);
77 }
78
80}
81
83{
84 mApp->plugins()->emitWebPageDeleted(m_page);
85
88}
89
90QIcon WebView::icon(bool allowNull) const
91{
92 if (!QWebEngineView::icon().isNull()) {
93 return QWebEngineView::icon();
94 }
95
96 if (url().scheme() == QLatin1String("ftp")) {
97 return IconProvider::standardIcon(QStyle::SP_ComputerIcon);
98 }
99
100 if (url().scheme() == QLatin1String("file")) {
101 return IconProvider::standardIcon(QStyle::SP_DriveHDIcon);
102 }
103
104 return IconProvider::iconForUrl(url(), allowNull);
105}
106
107QString WebView::title(bool allowEmpty) const
108{
109 QString title = QWebEngineView::title();
110
111 if (allowEmpty) {
112 return title;
113 }
114
115 const QUrl u = url().isEmpty() ? m_page->requestedUrl() : url();
116
117 if (title.isEmpty()) {
118 title = u.host();
119 }
120
121 if (title.isEmpty()) {
122 title = u.toString(QUrl::RemoveFragment);
123 }
124
125 if (title.isEmpty() || title == QL1S("about:blank")) {
126 return tr("Empty Page");
127 }
128
129 return title;
130}
131
133{
134 return m_page;
135}
136
138{
139 if (m_page == page) {
140 return;
141 }
142
143 if (m_page) {
144 if (m_page->isLoading()) {
145 Q_EMIT m_page->loadProgress(100);
146 Q_EMIT m_page->loadFinished(true);
147 }
148 mApp->plugins()->emitWebPageDeleted(m_page);
149 }
150
151 page->setParent(this);
152 QWebEngineView::setPage(page);
153 delete m_page;
154 m_page = page;
155
156 if (m_page->isLoading()) {
157 Q_EMIT loadStarted();
158 Q_EMIT loadProgress(m_page->m_loadProgress);
159 }
160
161 connect(m_page, &WebPage::privacyChanged, this, &WebView::privacyChanged);
162 connect(m_page, &WebPage::printRequested, this, &WebView::printPage);
163
164 // Set default zoom level
165 zoomReset();
166
167 // Actions needs to be initialized for every QWebEnginePage change
168 initializeActions();
169
170 // Scrollbars must be added only after QWebEnginePage is set
172
173 Q_EMIT pageChanged(m_page);
174 mApp->plugins()->emitWebPageCreated(m_page);
175}
176
177void WebView::load(const QUrl &url)
178{
179 if (m_page && !m_page->acceptNavigationRequest(url, QWebEnginePage::NavigationTypeTyped, true)) {
180 return;
181 }
182
183 QWebEngineView::load(url);
184
185 if (!m_firstLoad) {
186 m_firstLoad = true;
188 }
189}
190
191void WebView::load(const LoadRequest &request)
192{
193 const QUrl reqUrl = request.url();
194
195 if (reqUrl.isEmpty())
196 return;
197
198 if (reqUrl.scheme() == QL1S("javascript")) {
199 const QString scriptSource = reqUrl.toString().mid(11);
200 // Is the javascript source percent encoded or not?
201 // Looking for % character in source should work in most cases
202 if (scriptSource.contains(QL1C('%')))
203 page()->runJavaScript(QUrl::fromPercentEncoding(scriptSource.toUtf8()));
204 else
205 page()->runJavaScript(scriptSource);
206 return;
207 }
208
209 if (isUrlValid(reqUrl)) {
210 loadRequest(request);
211 }
212}
213
215{
216 return m_progress < 100;
217}
218
220{
221 return m_progress;
222}
223
225{
226 return m_backgroundActivity;
227}
228
230{
231 return m_currentZoomLevel;
232}
233
235{
236 m_currentZoomLevel = level;
237 applyZoom();
238}
239
240QPointF WebView::mapToViewport(const QPointF &pos) const
241{
242 return page()->mapToViewport(pos);
243}
244
245QRect WebView::scrollBarGeometry(Qt::Orientation orientation) const
246{
247 QScrollBar *s = WebScrollBarManager::instance()->scrollBar(orientation, const_cast<WebView*>(this));
248 return s && s->isVisible() ? s->geometry() : QRect();
249}
250
251QWidget *WebView::inputWidget() const
252{
253 return m_rwhvqt ? m_rwhvqt : const_cast<WebView*>(this);
254}
255
256// static
257bool WebView::isUrlValid(const QUrl &url)
258{
259 // Valid url must have scheme and actually contains something (therefore scheme:// is invalid)
260 return url.isValid() && !url.scheme().isEmpty() && (!url.host().isEmpty() || !url.path().isEmpty() || url.hasQuery());
261}
262
263// static
265{
266 return QList<int>() << 30 << 40 << 50 << 67 << 80 << 90 << 100
267 << 110 << 120 << 133 << 150 << 170 << 200
268 << 220 << 233 << 250 << 270 << 285 << 300;
269}
270
271// static
273{
274 return s_forceContextMenuOnMouseRelease;
275}
276
277// static
279{
280 // Windows open context menu on mouse release by default
281#ifndef Q_OS_WIN
282 s_forceContextMenuOnMouseRelease = force;
283#endif
284}
285
286void WebView::addNotification(QWidget* notif)
287{
288 Q_EMIT showNotification(notif);
289}
290
292{
293 setZoomFactor(qreal(zoomLevels().at(m_currentZoomLevel)) / 100.0);
294
295 Q_EMIT zoomLevelChanged(m_currentZoomLevel);
296}
297
299{
300 if (m_currentZoomLevel < zoomLevels().count() - 1) {
301 m_currentZoomLevel++;
302 applyZoom();
303 }
304}
305
307{
308 if (m_currentZoomLevel > 0) {
309 m_currentZoomLevel--;
310 applyZoom();
311 }
312}
313
315{
316 if (m_currentZoomLevel != qzSettings->defaultZoomLevel) {
317 m_currentZoomLevel = qzSettings->defaultZoomLevel;
318 applyZoom();
319 }
320}
321
323{
324 triggerPageAction(QWebEnginePage::Undo);
325}
326
328{
329 triggerPageAction(QWebEnginePage::Redo);
330}
331
333{
334 triggerPageAction(QWebEnginePage::Cut);
335}
336
338{
339 triggerPageAction(QWebEnginePage::Copy);
340}
341
343{
344 triggerPageAction(QWebEnginePage::Paste);
345}
346
348{
349 triggerPageAction(QWebEnginePage::SelectAll);
350}
351
353{
354 QKeyEvent ev(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier);
355 QApplication::sendEvent(this, &ev);
356}
357
359{
360 triggerPageAction(QWebEnginePage::ReloadAndBypassCache);
361}
362
364{
365 QWebEngineHistory* history = page()->history();
366
367 if (history->canGoBack()) {
368 history->back();
369
370 Q_EMIT urlChanged(url());
371 }
372}
373
375{
376 QWebEngineHistory* history = page()->history();
377
378 if (history->canGoForward()) {
379 history->forward();
380
381 Q_EMIT urlChanged(url());
382 }
383}
384
386{
387 Q_ASSERT(m_page);
388
389 auto *printer = new QPrinter();
390 printer->setCreator(tr("Falkon %1 (%2)").arg(QString::fromLatin1(Qz::VERSION), QString::fromLatin1(Qz::WWWADDRESS)));
391 printer->setDocName(QzTools::filterCharsFromFilename(title()));
392
393 auto *dialog = new QPrintDialog(printer, this);
394 dialog->setOptions(QAbstractPrintDialog::PrintToFile | QAbstractPrintDialog::PrintShowPageSize);
395#ifndef Q_OS_WIN
396 dialog->setOption(QAbstractPrintDialog::PrintPageRange);
397 dialog->setOption(QAbstractPrintDialog::PrintCollateCopies);
398#endif
399
400 if (dialog->exec() == QDialog::Accepted) {
401 if (dialog->printer()->outputFormat() == QPrinter::PdfFormat) {
402 m_page->printToPdf(dialog->printer()->outputFileName(), dialog->printer()->pageLayout());
403 delete dialog;
404 } else {
405 connect(this, &QWebEngineView::printFinished, this, [&dialog](bool success) {
406 Q_UNUSED(success);
407 delete dialog;
408 });
409 }
410 }
411}
412
414{
415 m_progress = 0;
416
417 if (title(/*allowEmpty*/true).isEmpty()) {
418 Q_EMIT titleChanged(title());
419 }
420}
421
423{
424 if (m_progress < 100) {
425 m_progress = progress;
426 }
427
428 // QtWebEngine sometimes forgets applied zoom factor
429 if (!qFuzzyCompare(zoomFactor(), zoomLevels().at(m_currentZoomLevel) / 100.0)) {
430 applyZoom();
431 }
432}
433
435{
436 m_progress = 100;
437
438 if (ok)
439 mApp->history()->addHistoryEntry(this);
440}
441
443{
445}
446
447void WebView::slotUrlChanged(const QUrl &url)
448{
449 if (!url.isEmpty() && title(/*allowEmpty*/true).isEmpty()) {
450 // Don't treat this as background activity change
451 const bool oldActivity = m_backgroundActivity;
452 m_backgroundActivity = true;
453 Q_EMIT titleChanged(title());
454 m_backgroundActivity = oldActivity;
455 }
456}
457
458void WebView::slotTitleChanged(const QString &title)
459{
460 Q_UNUSED(title)
461
462 if (!isVisible() && !isLoading() && !m_backgroundActivity) {
463 m_backgroundActivity = true;
464 Q_EMIT backgroundActivityChanged(m_backgroundActivity);
465 }
466}
467
469{
470 if (auto* action = qobject_cast<QAction*>(sender())) {
471 mApp->createWindow(Qz::BW_NewWindow, action->data().toUrl());
472 }
473}
474
476{
477 if (auto* action = qobject_cast<QAction*>(sender())) {
478 const QUrl mailUrl = QUrl::fromEncoded(
479 QByteArray("mailto:%20?body=" +
480 QUrl::toPercentEncoding(action->data().toString())));
481 QDesktopServices::openUrl(mailUrl);
482 }
483}
484
486{
487 const QUrl mailUrl = QUrl::fromEncoded(QByteArray(
488 "mailto:%20?body=" +
489 QUrl::toPercentEncoding(QString::fromUtf8(url().toEncoded())) +
490 "&subject=" + QUrl::toPercentEncoding(title())));
491 QDesktopServices::openUrl(mailUrl);
492}
493
495{
496 if (auto* action = qobject_cast<QAction*>(sender())) {
497 QApplication::clipboard()->setText(QString::fromUtf8(action->data().toUrl().toEncoded()));
498 }
499}
500
502{
503 page()->runJavaScript(QSL("document.contentType"), WebPage::SafeJsWorld, [this](const QVariant &res) {
504 const QSet<QString> webPageTypes = {
505 QSL("text/html"),
506 QSL("application/xhtml+xml")
507 };
508 if (res.isNull() || webPageTypes.contains(res.toString())) {
509 triggerPageAction(QWebEnginePage::SavePage);
510 } else {
511 page()->download(url());
512 }
513 });
514}
515
517{
518 triggerPageAction(QWebEnginePage::CopyImageToClipboard);
519}
520
522{
523 triggerPageAction(QWebEnginePage::DownloadLinkToDisk);
524}
525
527{
528 triggerPageAction(QWebEnginePage::DownloadImageToDisk);
529}
530
532{
533 triggerPageAction(QWebEnginePage::DownloadMediaToDisk);
534}
535
536void WebView::openUrlInNewTab(const QUrl &url, Qz::NewTabPositionFlags position)
537{
538 loadInNewTab(url, position);
539}
540
542{
543 if (auto* action = qobject_cast<QAction*>(sender())) {
544 load(action->data().toUrl());
545 }
546}
547
549{
550 // view-source: doesn't work on itself and custom schemes
551 if (url().scheme() == QL1S("view-source") || url().scheme() == QL1S("falkon") || url().scheme() == QL1S("qrc")) {
552 page()->toHtml([](const QString &html) {
553 std::cout << html.toLocal8Bit().constData() << std::endl;
554 });
555 return;
556 }
557
558 triggerPageAction(QWebEnginePage::ViewSource);
559}
560
562{
563 auto* s = new SiteInfo(this);
564 s->show();
565}
566
568{
569 SearchEngine engine = mApp->searchEnginesManager()->defaultEngine();
570 if (auto* act = qobject_cast<QAction*>(sender())) {
571 if (act->data().isValid()) {
572 engine = act->data().value<SearchEngine>();
573 }
574 }
575
576 const LoadRequest req = mApp->searchEnginesManager()->searchResult(engine, selectedText());
578}
579
581{
582 SearchEngine engine = mApp->searchEnginesManager()->defaultEngine();
583 if (auto* act = qobject_cast<QAction*>(sender())) {
584 if (act->data().isValid()) {
585 engine = act->data().value<SearchEngine>();
586 }
587 }
588
589 const LoadRequest req = mApp->searchEnginesManager()->searchResult(engine, selectedText());
591}
592
594{
595 if (auto* action = qobject_cast<QAction*>(sender())) {
596 if (action->data().isNull()) {
598 }
599 else {
600 const QVariantList bData = action->data().value<QVariantList>();
601 const QString bookmarkTitle = bData.at(1).toString().isEmpty() ? title() : bData.at(1).toString();
602
603 BookmarksTools::addBookmarkDialog(this, bData.at(0).toUrl(), bookmarkTitle);
604 }
605 }
606}
607
609{
610 if (auto* action = qobject_cast<QAction*>(sender())) {
611 openUrlInNewTab(action->data().toUrl(), Qz::NT_CleanSelectedTab);
612 }
613}
614
616{
617 if (auto* action = qobject_cast<QAction*>(sender())) {
618 openUrlInNewTab(action->data().toUrl(), Qz::NT_CleanNotSelectedTab);
619 }
620}
621
622void WebView::userDefinedOpenUrlInNewTab(const QUrl &url, bool invert)
623{
624 Qz::NewTabPositionFlags position = qzSettings->newTabPosition;
625 if (invert) {
626 if (position & Qz::NT_SelectedTab) {
627 position &= ~Qz::NT_SelectedTab;
628 position |= Qz::NT_NotSelectedTab;
629 }
630 else {
631 position &= ~Qz::NT_NotSelectedTab;
632 position |= Qz::NT_SelectedTab;
633 }
634 }
635
636 QUrl actionUrl;
637
638 if (!url.isEmpty()) {
639 actionUrl = url;
640 }
641 else if (auto* action = qobject_cast<QAction*>(sender())) {
642 actionUrl = action->data().toUrl();
643 }
644
645 openUrlInNewTab(actionUrl, position);
646}
647
649{
650 QUrl actionUrl;
651
652 if (!url.isEmpty()) {
653 actionUrl = url;
654 }
655 else if (auto* action = qobject_cast<QAction*>(sender())) {
656 actionUrl = action->data().toUrl();
657 }
658
659 userDefinedOpenUrlInNewTab(actionUrl, true);
660}
661
662void WebView::showEvent(QShowEvent *event)
663{
664 QWebEngineView::showEvent(event);
665
666 if (m_backgroundActivity) {
667 m_backgroundActivity = false;
668 Q_EMIT backgroundActivityChanged(m_backgroundActivity);
669 }
670}
671
673{
674 // cppcheck-suppress variableScope
675 int spellCheckActionCount = 0;
676
677 const QWebEngineContextMenuRequest *contextMenuDataPtr = lastContextMenuRequest();
678 if (contextMenuDataPtr == NULL) {
679 return;
680 }
681 const QWebEngineContextMenuRequest &contextMenuData = *contextMenuDataPtr;
682
683 hitTest.updateWithContextMenuData(contextMenuData);
684
685 if (!contextMenuData.misspelledWord().isEmpty()) {
686 QFont boldFont = menu->font();
687 boldFont.setBold(true);
688
689 for (const QString &suggestion : contextMenuData.spellCheckerSuggestions()) {
690 QAction *action = menu->addAction(suggestion);
691 action->setFont(boldFont);
692
693 connect(action, &QAction::triggered, this, [=]() {
694 page()->replaceMisspelledWord(suggestion);
695 });
696 }
697
698 if (menu->actions().isEmpty()) {
699 menu->addAction(tr("No suggestions"))->setEnabled(false);
700 }
701
702 menu->addSeparator();
703 spellCheckActionCount = menu->actions().count();
704 }
705
706 if (!hitTest.linkUrl().isEmpty() && hitTest.linkUrl().scheme() != QL1S("javascript")) {
707 createLinkContextMenu(menu, hitTest);
708 }
709
710 if (!hitTest.imageUrl().isEmpty()) {
711 createImageContextMenu(menu, hitTest);
712 }
713
714 if (!hitTest.mediaUrl().isEmpty()) {
715 createMediaContextMenu(menu, hitTest);
716 }
717
718 if (hitTest.isContentEditable()) {
719 // This only checks if the menu is empty (only spellchecker actions added)
720 if (menu->actions().count() == spellCheckActionCount) {
721 menu->addAction(pageAction(QWebEnginePage::Undo));
722 menu->addAction(pageAction(QWebEnginePage::Redo));
723 menu->addSeparator();
724 menu->addAction(pageAction(QWebEnginePage::Cut));
725 menu->addAction(pageAction(QWebEnginePage::Copy));
726 menu->addAction(pageAction(QWebEnginePage::Paste));
727 }
728
729 if (hitTest.tagName() == QL1S("input")) {
730 QAction *act = menu->addAction(QString());
731 act->setVisible(false);
732 checkForForm(act, hitTest.pos());
733 }
734 }
735
736 if (!selectedText().isEmpty()) {
737 createSelectedTextContextMenu(menu, hitTest);
738 }
739
740 if (menu->isEmpty()) {
742 }
743
744 menu->addSeparator();
745 mApp->plugins()->populateWebViewMenu(menu, this, hitTest);
746}
747
749{
750 QAction* action = menu->addAction(tr("&Back"), this, SLOT(back()));
751 action->setIcon(IconProvider::standardIcon(QStyle::SP_ArrowBack));
752 action->setEnabled(history()->canGoBack());
753
754 action = menu->addAction(tr("&Forward"), this, SLOT(forward()));
755 action->setIcon(IconProvider::standardIcon(QStyle::SP_ArrowForward));
756 action->setEnabled(history()->canGoForward());
757
758 // Special menu for Speed Dial page
759 if (url().toString() == QL1S("falkon:speeddial")) {
760 menu->addSeparator();
761 menu->addAction(QIcon::fromTheme(QSL("list-add")), tr("&Add New Page"), this, &WebView::addSpeedDial);
762 menu->addAction(IconProvider::settingsIcon(), tr("&Configure Speed Dial"), this, &WebView::configureSpeedDial);
763 menu->addSeparator();
764 menu->addAction(QIcon::fromTheme(QSL("view-refresh")), tr("Reload All Dials"), this, &WebView::reloadAllSpeedDials);
765 return;
766 }
767
768 QAction *reloadAction = pageAction(QWebEnginePage::Reload);
769 action = menu->addAction(reloadAction->icon(), reloadAction->text(), reloadAction, &QAction::trigger);
770 action->setVisible(reloadAction->isEnabled());
771 connect(reloadAction, &QAction::changed, action, [=]() {
772 action->setVisible(reloadAction->isEnabled());
773 });
774
775 QAction *stopAction = pageAction(QWebEnginePage::Stop);
776 action = menu->addAction(stopAction->icon(), stopAction->text(), stopAction, &QAction::trigger);
777 action->setVisible(stopAction->isEnabled());
778 connect(stopAction, &QAction::changed, action, [=]() {
779 action->setVisible(stopAction->isEnabled());
780 });
781
782 menu->addSeparator();
783 menu->addAction(QIcon::fromTheme(QSL("bookmark-new")), tr("Book&mark page"), this, &WebView::bookmarkLink);
784 menu->addAction(QIcon::fromTheme(QSL("document-save")), tr("&Save page as..."), this, &WebView::savePageAs);
785 menu->addAction(QIcon::fromTheme(QSL("edit-copy")), tr("&Copy page link"), this, &WebView::copyLinkToClipboard)->setData(url());
786 menu->addAction(QIcon::fromTheme(QSL("mail-message-new")), tr("Send page link..."), this, &WebView::sendPageByMail);
787 menu->addSeparator();
788 menu->addAction(QIcon::fromTheme(QSL("edit-select-all")), tr("Select &all"), this, &WebView::editSelectAll);
789 menu->addSeparator();
790
791 const QString scheme = url().scheme();
792
793 if (scheme != QL1S("view-source") && WebPage::internalSchemes().contains(scheme)) {
794 menu->addAction(QIcon::fromTheme(QSL("text-html")), tr("Show so&urce code"), this, &WebView::showSource);
795 }
796
797 if (SiteInfo::canShowSiteInfo(url()))
798 menu->addAction(QIcon::fromTheme(QSL("dialog-information")), tr("Show info ab&out site"), this, &WebView::showSiteInfo);
799}
800
801void WebView::createLinkContextMenu(QMenu* menu, const WebHitTestResult &hitTest)
802{
803 menu->addSeparator();
804 auto* act = new Action(IconProvider::newTabIcon(), tr("Open link in new &tab"));
805 act->setData(hitTest.linkUrl());
806 connect(act, SIGNAL(triggered()), this, SLOT(userDefinedOpenUrlInNewTab()));
807 connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInBgTab()));
808 menu->addAction(act);
809 menu->addAction(IconProvider::newWindowIcon(), tr("Open link in new &window"), this, &WebView::openUrlInNewWindow)->setData(hitTest.linkUrl());
810 menu->addAction(IconProvider::privateBrowsingIcon(), tr("Open link in &private window"), mApp, SLOT(startPrivateBrowsing()))->setData(hitTest.linkUrl());
811 menu->addSeparator();
812
813 QVariantList bData;
814 bData << hitTest.linkUrl() << hitTest.linkTitle();
815 menu->addAction(QIcon::fromTheme(QSL("bookmark-new")), tr("B&ookmark link"), this, &WebView::bookmarkLink)->setData(bData);
816
817 menu->addAction(QIcon::fromTheme(QSL("document-save")), tr("&Save link as..."), this, &WebView::downloadLinkToDisk);
818 menu->addAction(QIcon::fromTheme(QSL("mail-message-new")), tr("Send link..."), this, &WebView::sendTextByMail)->setData(hitTest.linkUrl().toEncoded());
819 menu->addAction(QIcon::fromTheme(QSL("edit-copy")), tr("&Copy link address"), this, &WebView::copyLinkToClipboard)->setData(hitTest.linkUrl());
820 menu->addSeparator();
821
822 if (!selectedText().isEmpty()) {
823 pageAction(QWebEnginePage::Copy)->setIcon(QIcon::fromTheme(QSL("edit-copy")));
824 menu->addAction(pageAction(QWebEnginePage::Copy));
825 }
826}
827
828void WebView::createImageContextMenu(QMenu* menu, const WebHitTestResult &hitTest)
829{
830 menu->addSeparator();
831 if (hitTest.imageUrl() != url()) {
832 auto *act = new Action(tr("Show i&mage"));
833 act->setData(hitTest.imageUrl());
834 connect(act, &QAction::triggered, this, &WebView::openActionUrl);
835 connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInNewTab()));
836 menu->addAction(act);
837 }
838 menu->addAction(tr("Copy image"), this, &WebView::copyImageToClipboard);
839 menu->addAction(QIcon::fromTheme(QSL("edit-copy")), tr("Copy image ad&dress"), this, &WebView::copyLinkToClipboard)->setData(hitTest.imageUrl());
840 menu->addSeparator();
841 menu->addAction(QIcon::fromTheme(QSL("document-save")), tr("&Save image as..."), this, &WebView::downloadImageToDisk);
842 menu->addAction(QIcon::fromTheme(QSL("mail-message-new")), tr("Send image..."), this, &WebView::sendTextByMail)->setData(hitTest.imageUrl().toEncoded());
843 menu->addSeparator();
844
845 if (!selectedText().isEmpty()) {
846 pageAction(QWebEnginePage::Copy)->setIcon(QIcon::fromTheme(QSL("edit-copy")));
847 menu->addAction(pageAction(QWebEnginePage::Copy));
848 }
849}
850
852{
853 Q_UNUSED(hitTest)
854
855 QString selectedText = page()->selectedText();
856
857 menu->addSeparator();
858 if (!menu->actions().contains(pageAction(QWebEnginePage::Copy))) {
859 menu->addAction(pageAction(QWebEnginePage::Copy));
860 }
861 menu->addAction(QIcon::fromTheme(QSL("mail-message-new")), tr("Send text..."), this, &WebView::sendTextByMail)->setData(selectedText);
862 menu->addSeparator();
863
864 // #379: Remove newlines
865 QString selectedString = selectedText.trimmed().remove(QLatin1Char('\n'));
866 if (!selectedString.contains(QLatin1Char('.'))) {
867 // Try to add .com
868 selectedString.append(QLatin1String(".com"));
869 }
870 QUrl guessedUrl = QUrl::fromUserInput(selectedString);
871
872 if (isUrlValid(guessedUrl)) {
873 auto* act = new Action(QIcon::fromTheme(QSL("document-open-remote")), tr("Go to &web address"));
874 act->setData(guessedUrl);
875
876 connect(act, &QAction::triggered, this, &WebView::openActionUrl);
877 connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInNewTab()));
878 menu->addAction(act);
879 }
880
881 menu->addSeparator();
882 selectedText.truncate(20);
883 // KDE is displaying newlines in menu actions ... weird -,-
884 selectedText.replace(QLatin1Char('\n'), QLatin1Char(' ')).replace(QLatin1Char('\t'), QLatin1Char(' '));
885
886 SearchEngine engine = mApp->searchEnginesManager()->defaultEngine();
887 auto* act = new Action(engine.icon, tr("Search \"%1 ..\" with %2").arg(selectedText, engine.name));
888 connect(act, &QAction::triggered, this, &WebView::searchSelectedText);
890 menu->addAction(act);
891
892 // Search with ...
893 Menu* swMenu = new Menu(tr("Search with..."), menu);
894 swMenu->setCloseOnMiddleClick(true);
895 SearchEnginesManager* searchManager = mApp->searchEnginesManager();
896 const auto engines = searchManager->allEngines();
897 for (const SearchEngine &en : engines) {
898 auto* act = new Action(en.icon, en.name);
899 act->setData(QVariant::fromValue(en));
900
901 connect(act, &QAction::triggered, this, &WebView::searchSelectedText);
903 swMenu->addAction(act);
904 }
905
906 menu->addMenu(swMenu);
907}
908
909void WebView::createMediaContextMenu(QMenu *menu, const WebHitTestResult &hitTest)
910{
911 bool paused = hitTest.mediaPaused();
912 bool muted = hitTest.mediaMuted();
913
914 menu->addSeparator();
915 menu->addAction(paused ? tr("&Play") : tr("&Pause"), this, &WebView::toggleMediaPause)->setIcon(QIcon::fromTheme(paused ? QSL("media-playback-start") : QSL("media-playback-pause")));
916 menu->addAction(muted ? tr("Un&mute") : tr("&Mute"), this, &WebView::toggleMediaMute)->setIcon(QIcon::fromTheme(muted ? QSL("audio-volume-muted") : QSL("audio-volume-high")));
917 menu->addSeparator();
918 menu->addAction(QIcon::fromTheme(QSL("edit-copy")), tr("&Copy Media Address"), this, &WebView::copyLinkToClipboard)->setData(hitTest.mediaUrl());
919 menu->addAction(QIcon::fromTheme(QSL("mail-message-new")), tr("&Send Media Address"), this, &WebView::sendTextByMail)->setData(hitTest.mediaUrl().toEncoded());
920 menu->addAction(QIcon::fromTheme(QSL("document-save")), tr("Save Media To &Disk"), this, &WebView::downloadMediaToDisk);
921}
922
923void WebView::checkForForm(QAction *action, const QPoint &pos)
924{
925 m_clickedPos = mapToViewport(pos);
926 QPointer<QAction> act = action;
927
928 page()->runJavaScript(Scripts::getFormData(m_clickedPos), WebPage::SafeJsWorld, [this, act](const QVariant &res) {
929 const QVariantMap &map = res.toMap();
930 if (!act || map.isEmpty())
931 return;
932
933 const QUrl url = map.value(QSL("action")).toUrl();
934 const QString method = map.value(QSL("method")).toString();
935
936 if (!url.isEmpty() && (method == QL1S("get") || method == QL1S("post"))) {
937 act->setVisible(true);
938 act->setIcon(QIcon::fromTheme(QSL("edit-find"), QIcon(QSL(":icons/menu/search-icon.svg"))));
939 act->setText(tr("Create Search Engine"));
940 connect(act.data(), &QAction::triggered, this, &WebView::createSearchEngine);
941 }
942 });
943}
944
946{
947 page()->runJavaScript(Scripts::getFormData(m_clickedPos), WebPage::SafeJsWorld, [this](const QVariant &res) {
948 mApp->searchEnginesManager()->addEngineFromForm(res.toMap(), this);
949 });
950}
951
952void WebView::addSpeedDial()
953{
954 page()->runJavaScript(QSL("addSpeedDial()"), WebPage::SafeJsWorld);
955}
956
957void WebView::configureSpeedDial()
958{
959 page()->runJavaScript(QSL("configureSpeedDial()"), WebPage::SafeJsWorld);
960}
961
962void WebView::reloadAllSpeedDials()
963{
964 page()->runJavaScript(QSL("reloadAll()"), WebPage::SafeJsWorld);
965}
966
967void WebView::toggleMediaPause()
968{
969 triggerPageAction(QWebEnginePage::ToggleMediaPlayPause);
970}
971
972void WebView::toggleMediaMute()
973{
974 triggerPageAction(QWebEnginePage::ToggleMediaMute);
975}
976
977void WebView::initializeActions()
978{
979 QAction* undoAction = pageAction(QWebEnginePage::Undo);
980 undoAction->setText(tr("&Undo"));
981 undoAction->setShortcut(QKeySequence(QSL("Ctrl+Z")));
982 undoAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
983 undoAction->setIcon(QIcon::fromTheme(QSL("edit-undo")));
984
985 QAction* redoAction = pageAction(QWebEnginePage::Redo);
986 redoAction->setText(tr("&Redo"));
987 redoAction->setShortcut(QKeySequence(QSL("Ctrl+Shift+Z")));
988 redoAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
989 redoAction->setIcon(QIcon::fromTheme(QSL("edit-redo")));
990
991 QAction* cutAction = pageAction(QWebEnginePage::Cut);
992 cutAction->setText(tr("&Cut"));
993 cutAction->setShortcut(QKeySequence(QSL("Ctrl+X")));
994 cutAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
995 cutAction->setIcon(QIcon::fromTheme(QSL("edit-cut")));
996
997 QAction* copyAction = pageAction(QWebEnginePage::Copy);
998 copyAction->setText(tr("&Copy"));
999 copyAction->setShortcut(QKeySequence(QSL("Ctrl+C")));
1000 copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
1001 copyAction->setIcon(QIcon::fromTheme(QSL("edit-copy")));
1002
1003 QAction* pasteAction = pageAction(QWebEnginePage::Paste);
1004 pasteAction->setText(tr("&Paste"));
1005 pasteAction->setShortcut(QKeySequence(QSL("Ctrl+V")));
1006 pasteAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
1007 pasteAction->setIcon(QIcon::fromTheme(QSL("edit-paste")));
1008
1009 QAction* selectAllAction = pageAction(QWebEnginePage::SelectAll);
1010 selectAllAction->setText(tr("Select All"));
1011 selectAllAction->setShortcut(QKeySequence(QSL("Ctrl+A")));
1012 selectAllAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
1013 selectAllAction->setIcon(QIcon::fromTheme(QSL("edit-select-all")));
1014
1015 QAction* reloadAction = pageAction(QWebEnginePage::Reload);
1016 reloadAction->setText(tr("&Reload"));
1017 reloadAction->setIcon(QIcon::fromTheme(QSL("view-refresh")));
1018
1019 QAction* stopAction = pageAction(QWebEnginePage::Stop);
1020 stopAction->setText(tr("S&top"));
1021 stopAction->setIcon(QIcon::fromTheme(QSL("process-stop")));
1022
1023 // Make action shortcuts available for webview
1024 addAction(undoAction);
1025 addAction(redoAction);
1026 addAction(cutAction);
1027 addAction(copyAction);
1028 addAction(pasteAction);
1029 addAction(selectAllAction);
1030}
1031
1032void WebView::_wheelEvent(QWheelEvent *event)
1033{
1034 if (mApp->plugins()->processWheelEvent(Qz::ON_WebView, this, event)) {
1035 event->accept();
1036 return;
1037 }
1038
1039 if (event->modifiers() & Qt::ControlModifier) {
1040 m_wheelHelper.processEvent(event);
1041 while (WheelHelper::Direction direction = m_wheelHelper.takeDirection()) {
1042 switch (direction) {
1045 zoomIn();
1046 break;
1047
1050 zoomOut();
1051 break;
1052
1053 default:
1054 break;
1055 }
1056 }
1057 event->accept();
1058 return;
1059 }
1060
1061 m_wheelHelper.reset();
1062
1063 // QtWebEngine ignores QApplication::wheelScrollLines() and instead always scrolls 3 lines
1064 if (event->spontaneous()) {
1065 const qreal multiplier = QApplication::wheelScrollLines() / 3.0;
1066 if (multiplier != 1.0) {
1067 QWheelEvent e(event->position(), event->globalPosition(), event->pixelDelta(),
1068 event->angleDelta() * multiplier, event->buttons(),
1069 event->modifiers(), event->phase(), event->inverted(), event->source());
1070 QApplication::sendEvent(m_rwhvqt, &e);
1071 event->accept();
1072 }
1073 }
1074}
1075
1076void WebView::_mousePressEvent(QMouseEvent *event)
1077{
1078 m_clickedUrl = QUrl();
1079 m_clickedPos = QPointF();
1080
1081 if (mApp->plugins()->processMousePress(Qz::ON_WebView, this, event)) {
1082 event->accept();
1083 return;
1084 }
1085
1086 switch (event->button()) {
1087 case Qt::BackButton:
1088 back();
1089 event->accept();
1090 break;
1091
1092 case Qt::ForwardButton:
1093 forward();
1094 event->accept();
1095 break;
1096
1097 case Qt::MiddleButton:
1098 m_clickedUrl = page()->hitTestContent(event->position().toPoint()).linkUrl();
1099 if (!m_clickedUrl.isEmpty())
1100 event->accept();
1101 break;
1102
1103 case Qt::LeftButton:
1104 m_clickedUrl = page()->hitTestContent(event->position().toPoint()).linkUrl();
1105 break;
1106
1107 default:
1108 break;
1109 }
1110}
1111
1112void WebView::_mouseReleaseEvent(QMouseEvent *event)
1113{
1114 if (mApp->plugins()->processMouseRelease(Qz::ON_WebView, this, event)) {
1115 event->accept();
1116 return;
1117 }
1118
1119 switch (event->button()) {
1120 case Qt::BackButton:
1121 case Qt::ForwardButton:
1122 event->accept();
1123 break;
1124
1125 case Qt::MiddleButton:
1126 if (!m_clickedUrl.isEmpty()) {
1127 const QUrl link = page()->hitTestContent(event->position().toPoint()).linkUrl();
1128 if (m_clickedUrl == link && isUrlValid(link)) {
1129 userDefinedOpenUrlInNewTab(link, event->modifiers() & Qt::ShiftModifier);
1130 event->accept();
1131 }
1132 }
1133 break;
1134
1135 case Qt::LeftButton:
1136 if (!m_clickedUrl.isEmpty()) {
1137 const QUrl link = page()->hitTestContent(event->position().toPoint()).linkUrl();
1138 if (m_clickedUrl == link && isUrlValid(link)) {
1139 if (event->modifiers() & Qt::ControlModifier) {
1140 userDefinedOpenUrlInNewTab(link, event->modifiers() & Qt::ShiftModifier);
1141 event->accept();
1142 }
1143 }
1144 }
1145 break;
1146
1147 case Qt::RightButton:
1148 if (s_forceContextMenuOnMouseRelease) {
1149 QContextMenuEvent ev(QContextMenuEvent::Mouse, event->position().toPoint(), event->globalPosition().toPoint(), event->modifiers());
1150 _contextMenuEvent(&ev);
1151 event->accept();
1152 }
1153 break;
1154
1155 default:
1156 break;
1157 }
1158}
1159
1160void WebView::_mouseMoveEvent(QMouseEvent *event)
1161{
1162 if (mApp->plugins()->processMouseMove(Qz::ON_WebView, this, event)) {
1163 event->accept();
1164 }
1165}
1166
1167void WebView::_keyPressEvent(QKeyEvent *event)
1168{
1169 if (mApp->plugins()->processKeyPress(Qz::ON_WebView, this, event)) {
1170 event->accept();
1171 return;
1172 }
1173
1174 switch (event->key()) {
1175 case Qt::Key_ZoomIn:
1176 zoomIn();
1177 event->accept();
1178 break;
1179
1180 case Qt::Key_ZoomOut:
1181 zoomOut();
1182 event->accept();
1183 break;
1184
1185 case Qt::Key_Plus:
1186 if (event->modifiers() & Qt::ControlModifier) {
1187 zoomIn();
1188 event->accept();
1189 }
1190 break;
1191
1192 case Qt::Key_Minus:
1193 if (event->modifiers() & Qt::ControlModifier) {
1194 zoomOut();
1195 event->accept();
1196 }
1197 break;
1198
1199 case Qt::Key_0:
1200 if (event->modifiers() & Qt::ControlModifier) {
1201 zoomReset();
1202 event->accept();
1203 }
1204 break;
1205
1206 case Qt::Key_M:
1207 if (event->modifiers() & Qt::ControlModifier) {
1208 page()->setAudioMuted(!page()->isAudioMuted());
1209 event->accept();
1210 }
1211 break;
1212
1213 default:
1214 break;
1215 }
1216}
1217
1218void WebView::_keyReleaseEvent(QKeyEvent *event)
1219{
1220 if (mApp->plugins()->processKeyRelease(Qz::ON_WebView, this, event)) {
1221 event->accept();
1222 }
1223
1224 switch (event->key()) {
1225 case Qt::Key_Escape:
1226 if (isFullScreen()) {
1227 triggerPageAction(QWebEnginePage::ExitFullScreen);
1228 event->accept();
1229 }
1230 break;
1231
1232 default:
1233 break;
1234 }
1235}
1236
1237void WebView::_contextMenuEvent(QContextMenuEvent *event)
1238{
1239 Q_UNUSED(event)
1240}
1241
1242void WebView::resizeEvent(QResizeEvent *event)
1243{
1244 QWebEngineView::resizeEvent(event);
1245 Q_EMIT viewportResized(size());
1246}
1247
1248void WebView::contextMenuEvent(QContextMenuEvent *event)
1249{
1250 // Context menu is created in mouseReleaseEvent
1251 if (s_forceContextMenuOnMouseRelease)
1252 return;
1253
1254 const QPoint pos = event->pos();
1255 const QPoint globalPos = event->globalPos();
1256 const QContextMenuEvent::Reason reason = event->reason();
1257
1258 QTimer::singleShot(0, this, [this, pos, globalPos, reason]() {
1259 QContextMenuEvent ev(reason, pos, globalPos);
1260 _contextMenuEvent(&ev);
1261 });
1262}
1263
1265{
1266 return QWebEngineView::focusNextPrevChild(next);
1267}
1268
1270{
1271 QWebEngineView::load(req.webRequest());
1272}
1273
1274bool WebView::eventFilter(QObject *obj, QEvent *event)
1275{
1276 // Keyboard events are sent to parent widget
1277 if (obj == this && event->type() == QEvent::ParentChange && parentWidget()) {
1278 parentWidget()->installEventFilter(this);
1279 }
1280
1281 // Hack to find widget that receives input events
1282 if (obj == this && event->type() == QEvent::ChildAdded) {
1283 QPointer<QWidget> child = qobject_cast<QWidget*>(static_cast<QChildEvent*>(event)->child());
1284 QTimer::singleShot(0, this, [=]() {
1285 if (child) {
1286 m_rwhvqt = child;
1287 m_rwhvqt->installEventFilter(this);
1288 if (auto *w = qobject_cast<QQuickWidget*>(m_rwhvqt)) {
1289 w->setClearColor(palette().color(QPalette::Window));
1290 }
1291 }
1292 });
1293 }
1294
1295 // Forward events to WebView
1296#define HANDLE_EVENT(f, t) \
1297 { \
1298 bool wasAccepted = event->isAccepted(); \
1299 event->setAccepted(false); \
1300 f(static_cast<t*>(event)); \
1301 bool ret = event->isAccepted(); \
1302 event->setAccepted(wasAccepted); \
1303 return ret; \
1304 }
1305
1306 if (obj == m_rwhvqt) {
1307 switch (event->type()) {
1308 case QEvent::MouseButtonPress:
1309 HANDLE_EVENT(_mousePressEvent, QMouseEvent);
1310
1311 case QEvent::MouseButtonRelease:
1312 HANDLE_EVENT(_mouseReleaseEvent, QMouseEvent);
1313
1314 case QEvent::MouseMove:
1315 HANDLE_EVENT(_mouseMoveEvent, QMouseEvent);
1316
1317 case QEvent::Wheel:
1318 HANDLE_EVENT(_wheelEvent, QWheelEvent);
1319
1320 default:
1321 break;
1322 }
1323 }
1324
1325 if (obj == parentWidget()) {
1326 switch (event->type()) {
1327 case QEvent::KeyPress:
1328 HANDLE_EVENT(_keyPressEvent, QKeyEvent);
1329
1330 case QEvent::KeyRelease:
1331 HANDLE_EVENT(_keyReleaseEvent, QKeyEvent);
1332
1333 default:
1334 break;
1335 }
1336 }
1337#undef HANDLE_EVENT
1338
1339 // Block already handled events
1340 if (obj == this) {
1341 switch (event->type()) {
1342 case QEvent::KeyPress:
1343 case QEvent::KeyRelease:
1344 case QEvent::MouseButtonPress:
1345 case QEvent::MouseButtonRelease:
1346 case QEvent::MouseMove:
1347 case QEvent::Wheel:
1348 return true;
1349
1350 case QEvent::Hide:
1351 if (isFullScreen()) {
1352 triggerPageAction(QWebEnginePage::ExitFullScreen);
1353 }
1354 break;
1355
1356 default:
1357 break;
1358 }
1359 }
1360
1361 const bool res = QWebEngineView::eventFilter(obj, event);
1362
1363 if (obj == m_rwhvqt) {
1364 switch (event->type()) {
1365 case QEvent::FocusIn:
1366 case QEvent::FocusOut:
1367 Q_EMIT focusChanged(hasFocus());
1368 break;
1369
1370 default:
1371 break;
1372 }
1373 }
1374
1375 return res;
1376}
void ctrlTriggered()
static bool addBookmarkDialog(QWidget *parent, const QUrl &url, const QString &title, BookmarkItem *folder=nullptr)
void saveIcon(WebView *view)
static QIcon settingsIcon()
static QIcon iconForUrl(const QUrl &url, bool allowNull=false)
static QIcon privateBrowsingIcon()
static IconProvider * instance()
static QIcon newWindowIcon()
static QIcon newTabIcon()
static QIcon standardIcon(QStyle::StandardPixmap icon)
QUrl url() const
Definition: loadrequest.cpp:44
QWebEngineHttpRequest webRequest() const
Definition: loadrequest.cpp:79
void setCloseOnMiddleClick(bool close)
static QString filterCharsFromFilename(const QString &name)
Definition: qztools.cpp:309
static QString getFormData(const QPointF &pos)
Definition: scripts.cpp:338
QVector< Engine > allEngines()
static bool canShowSiteInfo(const QUrl &url)
Definition: siteinfo.cpp:162
QString linkTitle() const
void updateWithContextMenuData(const QWebEngineContextMenuRequest &data)
QPoint pos() const
bool mediaPaused() const
bool mediaMuted() const
QString tagName() const
bool isContentEditable() const
static void pushView(QWebEngineView *view)
static void unregisterView(QWebEngineView *view)
static void registerView(QWebEngineView *view)
void privacyChanged(bool status)
static QStringList internalSchemes()
Definition: webpage.cpp:216
void printRequested()
bool isLoading() const
Definition: webpage.cpp:210
@ SafeJsWorld
Definition: webpage.h:45
WebHitTestResult hitTestContent(const QPoint &pos) const
Definition: webpage.cpp:189
QPointF mapToViewport(const QPointF &pos) const
Definition: webpage.cpp:184
static WebScrollBarManager * instance()
void removeWebView(WebView *view)
QScrollBar * scrollBar(Qt::Orientation orientation, WebView *view) const
void addWebView(WebView *view)
void createContextMenu(QMenu *menu, WebHitTestResult &hitTest)
Definition: webview.cpp:672
bool backgroundActivity() const
Definition: webview.cpp:224
void editPaste()
Definition: webview.cpp:342
void downloadMediaToDisk()
Definition: webview.cpp:531
void openActionUrl()
Definition: webview.cpp:541
void showNotification(QWidget *)
static bool isUrlValid(const QUrl &url)
Definition: webview.cpp:257
static QList< int > zoomLevels()
Definition: webview.cpp:264
void editDelete()
Definition: webview.cpp:352
void downloadLinkToDisk()
Definition: webview.cpp:521
int loadingProgress() const
Definition: webview.cpp:219
void backgroundActivityChanged(bool)
WebPage * page() const
Definition: webview.cpp:132
void slotLoadStarted()
Definition: webview.cpp:413
virtual bool isFullScreen()=0
static bool forceContextMenuOnMouseRelease()
Definition: webview.cpp:272
void printPage()
Definition: webview.cpp:385
void openUrlInNewWindow()
Definition: webview.cpp:468
WebView(QWidget *parent=nullptr)
Definition: webview.cpp:57
void copyImageToClipboard()
Definition: webview.cpp:516
void slotLoadFinished(bool ok)
Definition: webview.cpp:434
void zoomReset()
Definition: webview.cpp:314
void editRedo()
Definition: webview.cpp:327
QIcon icon(bool allowNull=false) const
Definition: webview.cpp:90
void contextMenuEvent(QContextMenuEvent *event) override
Definition: webview.cpp:1248
void focusChanged(bool)
~WebView() override
Definition: webview.cpp:82
void sendPageByMail()
Definition: webview.cpp:485
void userDefinedOpenUrlInNewTab(const QUrl &url=QUrl(), bool invert=false)
Definition: webview.cpp:622
bool focusNextPrevChild(bool next) override
Definition: webview.cpp:1264
int zoomLevel() const
Definition: webview.cpp:229
void zoomIn()
Definition: webview.cpp:298
void createSearchEngine()
Definition: webview.cpp:945
void pageChanged(WebPage *page)
void createLinkContextMenu(QMenu *menu, const WebHitTestResult &hitTest)
Definition: webview.cpp:801
virtual void _wheelEvent(QWheelEvent *event)
Definition: webview.cpp:1032
void editSelectAll()
Definition: webview.cpp:347
virtual void _mousePressEvent(QMouseEvent *event)
Definition: webview.cpp:1076
void slotIconChanged()
Definition: webview.cpp:442
void savePageAs()
Definition: webview.cpp:501
void reloadBypassCache()
Definition: webview.cpp:358
void privacyChanged(bool)
void setPage(WebPage *page)
Definition: webview.cpp:137
void checkForForm(QAction *action, const QPoint &pos)
Definition: webview.cpp:923
void zoomOut()
Definition: webview.cpp:306
void searchSelectedText()
Definition: webview.cpp:567
bool isLoading() const
Definition: webview.cpp:214
virtual void _keyPressEvent(QKeyEvent *event)
Definition: webview.cpp:1167
void load(const QUrl &url)
Definition: webview.cpp:177
virtual void _contextMenuEvent(QContextMenuEvent *event)
Definition: webview.cpp:1237
void createImageContextMenu(QMenu *menu, const WebHitTestResult &hitTest)
Definition: webview.cpp:828
void editCopy()
Definition: webview.cpp:337
void editUndo()
Definition: webview.cpp:322
void addNotification(QWidget *notif)
Definition: webview.cpp:286
void resizeEvent(QResizeEvent *event) override
Definition: webview.cpp:1242
void slotTitleChanged(const QString &title)
Definition: webview.cpp:458
void openUrlInNewTab(const QUrl &url, Qz::NewTabPositionFlags position)
Definition: webview.cpp:536
void bookmarkLink()
Definition: webview.cpp:593
virtual void _keyReleaseEvent(QKeyEvent *event)
Definition: webview.cpp:1218
void zoomLevelChanged(int)
void loadRequest(const LoadRequest &req)
Definition: webview.cpp:1269
static void setForceContextMenuOnMouseRelease(bool force)
Definition: webview.cpp:278
void userDefinedOpenUrlInBgTab(const QUrl &url=QUrl())
Definition: webview.cpp:648
QPointF mapToViewport(const QPointF &pos) const
Definition: webview.cpp:240
QString title(bool allowEmpty=false) const
Definition: webview.cpp:107
void openUrlInSelectedTab()
Definition: webview.cpp:608
void createMediaContextMenu(QMenu *menu, const WebHitTestResult &hitTest)
Definition: webview.cpp:909
void showSiteInfo()
Definition: webview.cpp:561
void editCut()
Definition: webview.cpp:332
void applyZoom()
Definition: webview.cpp:291
void openUrlInBackgroundTab()
Definition: webview.cpp:615
void sendTextByMail()
Definition: webview.cpp:475
void searchSelectedTextInBackgroundTab()
Definition: webview.cpp:580
void setZoomLevel(int level)
Definition: webview.cpp:234
void downloadImageToDisk()
Definition: webview.cpp:526
virtual void _mouseMoveEvent(QMouseEvent *event)
Definition: webview.cpp:1160
void showEvent(QShowEvent *event) override
Definition: webview.cpp:662
void viewportResized(QSize)
void forward()
Definition: webview.cpp:374
void createPageContextMenu(QMenu *menu)
Definition: webview.cpp:748
QRect scrollBarGeometry(Qt::Orientation orientation) const
Definition: webview.cpp:245
void back()
Definition: webview.cpp:363
void slotUrlChanged(const QUrl &url)
Definition: webview.cpp:447
QWidget * inputWidget() const
Definition: webview.cpp:251
void copyLinkToClipboard()
Definition: webview.cpp:494
void showSource()
Definition: webview.cpp:548
bool eventFilter(QObject *obj, QEvent *event) override
Definition: webview.cpp:1274
void createSelectedTextContextMenu(QMenu *menu, const WebHitTestResult &hitTest)
Definition: webview.cpp:851
virtual void loadInNewTab(const LoadRequest &req, Qz::NewTabPositionFlags position)=0
virtual void _mouseReleaseEvent(QMouseEvent *event)
Definition: webview.cpp:1112
void slotLoadProgress(int progress)
Definition: webview.cpp:422
Direction takeDirection()
Definition: wheelhelper.cpp:74
void reset()
Definition: wheelhelper.cpp:25
void processEvent(QWheelEvent *event)
Definition: wheelhelper.cpp:31
#define mApp
Definition: qzcommon.cpp:22
@ ON_WebView
Definition: qzcommon.h:90
FALKON_EXPORT const char * VERSION
Definition: qzcommon.cpp:26
FALKON_EXPORT const char * WWWADDRESS
Definition: qzcommon.cpp:29
@ BW_NewWindow
Definition: qzcommon.h:67
@ NT_CleanSelectedTab
Definition: qzcommon.h:107
@ NT_SelectedTab
Definition: qzcommon.h:97
@ NT_CleanNotSelectedTab
Definition: qzcommon.h:108
@ NT_NotSelectedTab
Definition: qzcommon.h:98
#define QL1S(x)
Definition: qzcommon.h:44
#define QL1C(x)
Definition: qzcommon.h:48
#define QSL(x)
Definition: qzcommon.h:40
#define qzSettings
Definition: qzsettings.h:69
#define HANDLE_EVENT(f, t)