File indexing completed on 2024-05-19 05:01:23
0001 /* 0002 This file is part of the KDE project. 0003 0004 SPDX-FileCopyrightText: 2007 Trolltech ASA 0005 SPDX-FileCopyrightText: 2008-2010 Urs Wolfer <uwolfer @ kde.org> 0006 SPDX-FileCopyrightText: 2008 Laurent Montel <montel@kde.org> 0007 SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org> 0008 0009 SPDX-License-Identifier: LGPL-2.1-or-later 0010 */ 0011 0012 #include "webengineview.h" 0013 #include "webenginepage.h" 0014 #include "webenginepart.h" 0015 #include "webenginepart_ext.h" 0016 #include "settings/webenginesettings.h" 0017 #include "webenginepart_ext.h" 0018 #include "spellcheckermanager.h" 0019 #include "browserinterface.h" 0020 0021 #include <KIO/Global> 0022 #include <KAboutData> 0023 #include <KActionCollection> 0024 #include <KConfigGroup> 0025 #include <KService> 0026 #include <KUriFilter> 0027 #include <KActionMenu> 0028 #include <KStringHandler> 0029 #include <KLocalizedString> 0030 #include <KIO/CommandLauncherJob> 0031 0032 #include <QTimer> 0033 #include <QMimeData> 0034 #include <QDropEvent> 0035 #include <QLabel> 0036 #include <QNetworkRequest> 0037 #include <QToolTip> 0038 #include <QCoreApplication> 0039 #include <QMimeType> 0040 #include <QMimeDatabase> 0041 #include <QMenu> 0042 #include <QActionGroup> 0043 0044 #define QL1S(x) QLatin1String(x) 0045 #define QL1C(x) QLatin1Char(x) 0046 0047 #define ALTERNATE_DEFAULT_WEB_SHORTCUT QL1S("google") 0048 #define ALTERNATE_WEB_SHORTCUTS QStringList() << QL1S("google") << QL1S("wikipedia") << QL1S("webster") << QL1S("dmoz") 0049 0050 WebEngineView::WebEngineView(WebEnginePart* part, QWidget* parent) 0051 :QWebEngineView(parent), 0052 m_actionCollection(new KActionCollection(this)), 0053 m_part(part), 0054 m_autoScrollTimerId(-1), 0055 m_verticalAutoScrollSpeed(0), 0056 m_horizontalAutoScrollSpeed(0), 0057 m_spellCheckMenu(nullptr) 0058 { 0059 setAcceptDrops(true); 0060 0061 // Create the custom page... 0062 setPage(new WebEnginePage(part, this)); 0063 0064 connect(this, &QWebEngineView::loadStarted, this, &WebEngineView::slotStopAutoScroll); 0065 0066 if (WebEngineSettings::self()->zoomToDPI()) 0067 setZoomFactor(logicalDpiY() / 96.0f); 0068 } 0069 0070 WebEngineView::~WebEngineView() 0071 { 0072 //qCDebug(WEBENGINEPART_LOG); 0073 } 0074 0075 void WebEngineView::loadUrl(const QUrl& url, const KParts::OpenUrlArguments& args, const BrowserArguments& bargs) 0076 { 0077 WebEnginePage *pg = qobject_cast<WebEnginePage*>(page()); 0078 if (!pg) { 0079 return; 0080 } 0081 0082 page()->setProperty("NavigationTypeUrlEntered", true); 0083 0084 if (args.reload() && url == this->url()) { 0085 reload(); 0086 return; 0087 } 0088 0089 // QNetworkRequest request(url); 0090 // if (args.reload()) { 0091 // request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); 0092 // } 0093 0094 if (bargs.postData.isEmpty()) { 0095 QWebEngineView::load(url); 0096 } else { 0097 // QWebEngineView::load(url, QNetworkAccessManager::PostOperation, bargs.postData); 0098 } 0099 } 0100 0101 const QWebEngineContextMenuRequest* WebEngineView::contextMenuResult() const 0102 { 0103 return result(); 0104 } 0105 0106 static void extractMimeTypeFor(const QUrl& url, QString& mimeType) 0107 { 0108 const QString fname(url.fileName()); 0109 0110 if (fname.isEmpty() || url.hasFragment() || url.hasQuery()) 0111 return; 0112 0113 QMimeType pmt = QMimeDatabase().mimeTypeForFile(fname); 0114 0115 // Further check for mime types guessed from the extension which, 0116 // on a web page, are more likely to be a script delivering content 0117 // of undecidable type. If the mime type from the extension is one 0118 // of these, don't use it. Retain the original type 'text/html'. 0119 if (pmt.isDefault() || 0120 pmt.inherits(QL1S("application/x-perl")) || 0121 pmt.inherits(QL1S("application/x-perl-module")) || 0122 pmt.inherits(QL1S("application/x-php")) || 0123 pmt.inherits(QL1S("application/x-python-bytecode")) || 0124 pmt.inherits(QL1S("application/x-python")) || 0125 pmt.inherits(QL1S("application/x-shellscript"))) 0126 return; 0127 0128 mimeType = pmt.name(); 0129 } 0130 0131 void WebEngineView::contextMenuEvent(QContextMenuEvent* e) 0132 { 0133 #if QT_VERSION_MAJOR < 6 0134 m_result = page()->contextMenuData(); 0135 #else 0136 m_result = lastContextMenuRequest(); 0137 #endif 0138 0139 // Clear the previous collection entries first... 0140 m_actionCollection->clear(); 0141 0142 KParts::NavigationExtension::PopupFlags flags = KParts::NavigationExtension::DefaultPopupItems; 0143 KParts::NavigationExtension::ActionGroupMap mapAction; 0144 QString mimeType (QL1S("text/html")); 0145 bool forcesNewWindow = false; 0146 0147 QUrl emitUrl; 0148 0149 if (result()->isContentEditable()) { 0150 flags |= KParts::NavigationExtension::ShowTextSelectionItems; 0151 editableContentActionPopupMenu(mapAction); 0152 } else if (result()->mediaType() == QWebEngineContextMenuRequest::MediaTypeVideo || result()->mediaType() == QWebEngineContextMenuRequest::MediaTypeAudio) { 0153 multimediaActionPopupMenu(mapAction); 0154 } else if (!result()->linkUrl().isValid()) { 0155 if (result()->mediaType() == QWebEngineContextMenuRequest::MediaTypeImage) { 0156 emitUrl = result()->mediaUrl(); 0157 extractMimeTypeFor(emitUrl, mimeType); 0158 } else { 0159 flags |= KParts::NavigationExtension::ShowBookmark; 0160 emitUrl = m_part->url(); 0161 0162 if (!result()->selectedText().isEmpty()) { 0163 flags |= KParts::NavigationExtension::ShowTextSelectionItems; 0164 selectActionPopupMenu(mapAction); 0165 } 0166 } 0167 partActionPopupMenu(mapAction); 0168 } else { 0169 flags |= KParts::NavigationExtension::ShowBookmark; 0170 flags |= KParts::NavigationExtension::IsLink; 0171 emitUrl = result()->linkUrl(); 0172 linkActionPopupMenu(mapAction); 0173 if (emitUrl.isLocalFile()) 0174 mimeType = QMimeDatabase().mimeTypeForUrl(emitUrl).name(); 0175 else 0176 extractMimeTypeFor(emitUrl, mimeType); 0177 partActionPopupMenu(mapAction); 0178 0179 // Show the OpenInThisWindow context menu item 0180 // forcesNewWindow = (page()->currentFrame() != result()->linkTargetFrame()); 0181 } 0182 0183 if (!mapAction.isEmpty()) { 0184 KParts::OpenUrlArguments args; 0185 BrowserArguments bargs; 0186 args.setMimeType(mimeType); 0187 bargs.setForcesNewWindow(forcesNewWindow); 0188 e->accept(); 0189 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0190 emit m_part->browserExtension()->popupMenu(e->globalPos(), emitUrl, static_cast<mode_t>(-1), args, bargs, flags, mapAction); 0191 #else 0192 emit m_part->browserExtension()->browserPopupMenuFromUrl(e->globalPos(), emitUrl, static_cast<mode_t>(-1), args, bargs, flags, mapAction); 0193 #endif 0194 return; 0195 } 0196 0197 QWebEngineView::contextMenuEvent(e); 0198 } 0199 0200 void WebEngineView::keyPressEvent(QKeyEvent* e) 0201 { 0202 if (e && hasFocus()) { 0203 const int key = e->key(); 0204 if (e->modifiers() & Qt::ShiftModifier) { 0205 switch (key) { 0206 case Qt::Key_Up: 0207 /* if (!isEditableElement(page()))*/ { 0208 m_verticalAutoScrollSpeed--; 0209 if (m_autoScrollTimerId == -1) 0210 m_autoScrollTimerId = startTimer(100); 0211 e->accept(); 0212 return; 0213 } 0214 break; 0215 case Qt::Key_Down: 0216 /*if (!isEditableElement(page()))*/ { 0217 m_verticalAutoScrollSpeed++; 0218 if (m_autoScrollTimerId == -1) 0219 m_autoScrollTimerId = startTimer(100); 0220 e->accept(); 0221 return; 0222 } 0223 break; 0224 case Qt::Key_Left: 0225 /*if (!isEditableElement(page()))*/ { 0226 m_horizontalAutoScrollSpeed--; 0227 if (m_autoScrollTimerId == -1) 0228 m_autoScrollTimerId = startTimer(100); 0229 e->accept(); 0230 return; 0231 } 0232 break; 0233 case Qt::Key_Right: 0234 /*if (!isEditableElement(page()))*/ { 0235 m_horizontalAutoScrollSpeed--; 0236 if (m_autoScrollTimerId == -1) 0237 m_autoScrollTimerId = startTimer(100); 0238 e->accept(); 0239 return; 0240 } 0241 break; 0242 default: 0243 break; 0244 } 0245 } else if (m_autoScrollTimerId != -1) { 0246 // qCDebug(WEBENGINEPART_LOG) << "scroll timer id:" << m_autoScrollTimerId; 0247 slotStopAutoScroll(); 0248 e->accept(); 0249 return; 0250 } 0251 } 0252 QWebEngineView::keyPressEvent(e); 0253 } 0254 0255 void WebEngineView::keyReleaseEvent(QKeyEvent *e) 0256 { 0257 QWebEngineView::keyReleaseEvent(e); 0258 } 0259 0260 void WebEngineView::mouseReleaseEvent(QMouseEvent* e) 0261 { 0262 QWebEngineView::mouseReleaseEvent(e); 0263 } 0264 0265 void WebEngineView::wheelEvent (QWheelEvent* e) 0266 { 0267 QWebEngineView::wheelEvent(e); 0268 } 0269 0270 0271 void WebEngineView::timerEvent(QTimerEvent* e) 0272 { 0273 #if 0 0274 if (e && e->timerId() == m_autoScrollTimerId) { 0275 // do the scrolling 0276 scroll(m_horizontalAutoScrollSpeed, m_verticalAutoScrollSpeed); 0277 // check if we reached the end 0278 const int y = page()->scrollPosition().y(); 0279 if (y == page()->currentFrame()->scrollBarMinimum(Qt::Vertical) || 0280 y == page()->currentFrame()->scrollBarMaximum(Qt::Vertical)) { 0281 m_verticalAutoScrollSpeed = 0; 0282 } 0283 0284 const int x = page()->scrollPosition().x(); 0285 if (x == page()->currentFrame()->scrollBarMinimum(Qt::Horizontal) || 0286 x == page()->currentFrame()->scrollBarMaximum(Qt::Horizontal)) { 0287 m_horizontalAutoScrollSpeed = 0; 0288 } 0289 0290 // Kill the timer once the max/min scroll limit is reached. 0291 if (m_horizontalAutoScrollSpeed == 0 && m_verticalAutoScrollSpeed == 0) { 0292 killTimer(m_autoScrollTimerId); 0293 m_autoScrollTimerId = -1; 0294 } 0295 e->accept(); 0296 return; 0297 } 0298 #endif 0299 QWebEngineView::timerEvent(e); 0300 } 0301 0302 void WebEngineView::editableContentActionPopupMenu(KParts::NavigationExtension::ActionGroupMap& partGroupMap) 0303 { 0304 if (m_spellCheckMenu) { 0305 m_spellCheckMenu->deleteLater(); 0306 m_spellCheckMenu = nullptr; 0307 } 0308 QList<QAction*> editableContentActions; 0309 0310 QActionGroup* group = new QActionGroup(this); 0311 group->setExclusive(true); 0312 0313 QAction* action = new QAction(m_actionCollection); 0314 action->setSeparator(true); 0315 editableContentActions.append(action); 0316 0317 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0318 Q_ASSERT(ext!=nullptr); 0319 0320 action = KStandardAction::create(KStandardAction::Copy, ext, &WebEngineNavigationExtension::copy, m_actionCollection); 0321 action->setEnabled(pageAction(QWebEnginePage::Copy)->isEnabled()); 0322 editableContentActions.append(action); 0323 0324 action = KStandardAction::create(KStandardAction::Cut, ext, &WebEngineNavigationExtension::cut, m_actionCollection); 0325 action->setEnabled(pageAction(QWebEnginePage::Cut)->isEnabled()); 0326 editableContentActions.append(action); 0327 0328 action = KStandardAction::create(KStandardAction::Paste, ext, &WebEngineNavigationExtension::paste, m_actionCollection); 0329 action->setEnabled(pageAction(QWebEnginePage::Paste)->isEnabled()); 0330 editableContentActions.append(action); 0331 0332 action = new QAction(m_actionCollection); 0333 action->setSeparator(true); 0334 editableContentActions.append(action); 0335 0336 editableContentActions.append(pageAction(QWebEnginePage::SelectAll)); 0337 editableContentActions.append(pageAction(QWebEnginePage::InspectElement)); 0338 0339 0340 #if QT_VERSION_MAJOR < 6 0341 const QWebEngineContextMenuRequest *req = &page()->contextMenuData(); 0342 #else 0343 QWebEngineContextMenuRequest *req = lastContextMenuRequest(); 0344 #endif 0345 SpellCheckerManager *manager = m_part->spellCheckerManager(); 0346 m_spellCheckMenu = manager->spellCheckingMenu(req->spellCheckerSuggestions(), m_actionCollection, dynamic_cast<WebEnginePage*>(page())); 0347 if (m_spellCheckMenu) { 0348 editableContentActions.append(m_spellCheckMenu->menuAction()); 0349 } 0350 0351 partGroupMap.insert(QStringLiteral("editactions") , editableContentActions); 0352 } 0353 0354 void WebEngineView::partActionPopupMenu(KParts::NavigationExtension::ActionGroupMap& partGroupMap) 0355 { 0356 QList<QAction*> partActions; 0357 0358 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0359 Q_ASSERT(ext!=nullptr); 0360 if (result()->mediaUrl().isValid()) { 0361 QAction *action; 0362 action = new QAction(i18n("Save Image As..."), this); 0363 m_actionCollection->addAction(QL1S("saveimageas"), action); 0364 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotSaveImageAs); 0365 partActions.append(action); 0366 0367 action = new QAction(i18n("Send Image..."), this); 0368 m_actionCollection->addAction(QL1S("sendimage"), action); 0369 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotSendImage); 0370 partActions.append(action); 0371 0372 action = new QAction(i18n("Copy Image URL"), this); 0373 m_actionCollection->addAction(QL1S("copyimageurl"), action); 0374 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyImageURL); 0375 partActions.append(action); 0376 0377 #if 0 0378 action = new QAction(i18n("Copy Image"), this); 0379 m_actionCollection->addAction(QL1S("copyimage"), action); 0380 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyImage); 0381 action->setEnabled(!result()->pixmap().isNull()); 0382 partActions.append(action); 0383 #endif 0384 0385 action = new QAction(i18n("View Image (%1)", QUrl(result()->mediaUrl()).fileName()), this); 0386 m_actionCollection->addAction(QL1S("viewimage"), action); 0387 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotViewImage); 0388 partActions.append(action); 0389 0390 if (WebEngineSettings::self()->isAdFilterEnabled()) { 0391 action = new QAction(i18n("Block Image..."), this); 0392 m_actionCollection->addAction(QL1S("blockimage"), action); 0393 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotBlockImage); 0394 partActions.append(action); 0395 0396 if (!result()->mediaUrl().host().isEmpty() && 0397 !result()->mediaUrl().scheme().isEmpty()) 0398 { 0399 action = new QAction(i18n("Block Images From %1" , result()->mediaUrl().host()), this); 0400 m_actionCollection->addAction(QL1S("blockhost"), action); 0401 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotBlockHost); 0402 partActions.append(action); 0403 } 0404 } 0405 } 0406 0407 { 0408 QAction *separatorAction = new QAction(m_actionCollection); 0409 separatorAction->setSeparator(true); 0410 partActions.append(separatorAction); 0411 } 0412 0413 partActions.append(m_part->actionCollection()->action(QStringLiteral("viewDocumentSource"))); 0414 0415 partActions.append(pageAction(QWebEnginePage::InspectElement)); 0416 0417 partGroupMap.insert(QStringLiteral("partactions"), partActions); 0418 } 0419 0420 void WebEngineView::selectActionPopupMenu(KParts::NavigationExtension::ActionGroupMap& selectGroupMap) 0421 { 0422 QList<QAction*> selectActions; 0423 0424 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0425 Q_ASSERT(ext!=nullptr); 0426 0427 QAction* copyAction = KStandardAction::create(KStandardAction::Copy, 0428 ext, &WebEngineNavigationExtension::copy, m_actionCollection); 0429 copyAction->setText(i18n("&Copy Text")); 0430 copyAction->setEnabled(ext->isActionEnabled("copy")); 0431 selectActions.append(copyAction); 0432 0433 addSearchActions(selectActions, this); 0434 0435 KUriFilterData data (selectedText().simplified().left(256)); 0436 data.setCheckForExecutables(false); 0437 if (KUriFilter::self()->filterUri(data, QStringList() << QStringLiteral("kshorturifilter") << QStringLiteral("fixhosturifilter")) && 0438 data.uri().isValid() && data.uriType() == KUriFilterData::NetProtocol) { 0439 QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("open selected url", "Open '%1'", 0440 KStringHandler::rsqueeze(data.uri().url(), 18)), this); 0441 m_actionCollection->addAction(QL1S("openSelection"), action); 0442 action->setData(QUrl(data.uri())); 0443 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotOpenSelection); 0444 selectActions.append(action); 0445 } 0446 0447 selectGroupMap.insert(QStringLiteral("editactions"), selectActions); 0448 } 0449 0450 void WebEngineView::linkActionPopupMenu(KParts::NavigationExtension::ActionGroupMap& linkGroupMap) 0451 { 0452 Q_ASSERT(!result()->linkUrl().isEmpty()); 0453 0454 const QUrl url(result()->linkUrl()); 0455 0456 QList<QAction*> linkActions; 0457 0458 QAction* action; 0459 0460 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0461 Q_ASSERT(ext!=nullptr); 0462 0463 if (!result()->selectedText().isEmpty()) { 0464 action = KStandardAction::create(KStandardAction::Copy, ext, &WebEngineNavigationExtension::copy, 0465 m_actionCollection); 0466 action->setText(i18n("&Copy Text")); 0467 action->setEnabled(ext->isActionEnabled("copy")); 0468 linkActions.append(action); 0469 } 0470 0471 if (url.scheme() == QLatin1String("mailto")) { 0472 action = new QAction(i18n("&Copy Email Address"), this); 0473 m_actionCollection->addAction(QL1S("copylinklocation"), action); 0474 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyEmailAddress); 0475 linkActions.append(action); 0476 } else { 0477 if (!result()->linkText().isEmpty()) { 0478 action = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Link &Text"), this); 0479 m_actionCollection->addAction(QL1S("copylinktext"), action); 0480 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyLinkText); 0481 linkActions.append(action); 0482 } 0483 0484 action = new QAction(i18n("Copy Link &URL"), this); 0485 m_actionCollection->addAction(QL1S("copylinkurl"), action); 0486 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyLinkURL); 0487 linkActions.append(action); 0488 0489 action = new QAction(i18n("&Save Link As..."), this); 0490 m_actionCollection->addAction(QL1S("savelinkas"), action); 0491 auto saveLinkAsLambda = [this, url](bool){qobject_cast<WebEngineNavigationExtension*>(m_part->navigationExtension())->slotSaveLinkAs(url);}; 0492 connect(action, &QAction::triggered, m_part->navigationExtension(), saveLinkAsLambda); 0493 linkActions.append(action); 0494 } 0495 0496 linkGroupMap.insert(QStringLiteral("linkactions"), linkActions); 0497 } 0498 0499 void WebEngineView::multimediaActionPopupMenu(KParts::NavigationExtension::ActionGroupMap& mmGroupMap) 0500 { 0501 QList<QAction*> multimediaActions; 0502 0503 const bool isVideoElement = result()->mediaType() == QWebEngineContextMenuRequest::MediaTypeVideo; 0504 const bool isAudioElement = result()->mediaType() == QWebEngineContextMenuRequest::MediaTypeAudio; 0505 0506 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0507 Q_ASSERT(ext!=nullptr); 0508 0509 QAction* action = new QAction(i18n("&Play/Pause"), this); 0510 m_actionCollection->addAction(QL1S("playmultimedia"), action); 0511 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotPlayMedia); 0512 multimediaActions.append(action); 0513 0514 action = new QAction(i18n("Un&mute/&Mute"), this); 0515 m_actionCollection->addAction(QL1S("mutemultimedia"), action); 0516 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotMuteMedia); 0517 multimediaActions.append(action); 0518 0519 action = new QAction(i18n("Toggle &Loop"), this); 0520 m_actionCollection->addAction(QL1S("loopmultimedia"), action); 0521 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotLoopMedia); 0522 multimediaActions.append(action); 0523 0524 action = new QAction(i18n("Toggle &Controls"), this); 0525 m_actionCollection->addAction(QL1S("showmultimediacontrols"), action); 0526 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotShowMediaControls); 0527 multimediaActions.append(action); 0528 0529 action = new QAction(m_actionCollection); 0530 action->setSeparator(true); 0531 multimediaActions.append(action); 0532 0533 QString saveMediaText, copyMediaText; 0534 if (isVideoElement) { 0535 saveMediaText = i18n("Sa&ve Video As..."); 0536 copyMediaText = i18n("C&opy Video URL"); 0537 } else if (isAudioElement) { 0538 saveMediaText = i18n("Sa&ve Audio As..."); 0539 copyMediaText = i18n("C&opy Audio URL"); 0540 } else { 0541 saveMediaText = i18n("Sa&ve Media As..."); 0542 copyMediaText = i18n("C&opy Media URL"); 0543 } 0544 0545 action = new QAction(saveMediaText, this); 0546 m_actionCollection->addAction(QL1S("savemultimedia"), action); 0547 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotSaveMedia); 0548 multimediaActions.append(action); 0549 0550 action = new QAction(copyMediaText, this); 0551 m_actionCollection->addAction(QL1S("copymultimediaurl"), action); 0552 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::slotCopyMedia); 0553 multimediaActions.append(action); 0554 0555 mmGroupMap.insert(QStringLiteral("partactions"), multimediaActions); 0556 } 0557 0558 void WebEngineView::slotConfigureWebShortcuts() 0559 { 0560 auto job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell5"), {QStringLiteral("webshortcuts")}); 0561 job->start(); 0562 } 0563 0564 void WebEngineView::slotStopAutoScroll() 0565 { 0566 if (m_autoScrollTimerId == -1) { 0567 return; 0568 } 0569 0570 killTimer(m_autoScrollTimerId); 0571 m_autoScrollTimerId = -1; 0572 m_verticalAutoScrollSpeed = 0; 0573 m_horizontalAutoScrollSpeed = 0; 0574 0575 } 0576 0577 void WebEngineView::addSearchActions(QList<QAction*>& selectActions, QWebEngineView* view) 0578 { 0579 // search text 0580 const QString selectedText = view->selectedText().simplified(); 0581 if (selectedText.isEmpty()) 0582 return; 0583 0584 WebEngineNavigationExtension *ext = qobject_cast<WebEngineNavigationExtension *>(m_part->navigationExtension()); 0585 Q_ASSERT(ext!=nullptr); 0586 0587 KUriFilterData data; 0588 data.setData(selectedText); 0589 data.setAlternateDefaultSearchProvider(ALTERNATE_DEFAULT_WEB_SHORTCUT); 0590 data.setAlternateSearchProviders(ALTERNATE_WEB_SHORTCUTS); 0591 0592 if (KUriFilter::self()->filterSearchUri(data, KUriFilter::NormalTextFilter)) { 0593 const QString squeezedText = KStringHandler::rsqueeze(selectedText, 20); 0594 QAction *action = new QAction(QIcon::fromTheme(data.iconName()), 0595 i18nc("Search \"search provider\" for \"text\"", "Search %1 for '%2'", 0596 data.searchProvider(), squeezedText), view); 0597 action->setData(QUrl(data.uri())); 0598 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::searchProvider); 0599 m_actionCollection->addAction(QL1S("defaultSearchProvider"), action); 0600 selectActions.append(action); 0601 0602 0603 const QStringList preferredSearchProviders = data.preferredSearchProviders(); 0604 if (!preferredSearchProviders.isEmpty()) { 0605 KActionMenu* providerList = new KActionMenu(i18nc("Search for \"text\" with", 0606 "Search for '%1' with", squeezedText), view); 0607 for (const QString &searchProvider: preferredSearchProviders) { 0608 if (searchProvider == data.searchProvider()) 0609 continue; 0610 0611 QAction *action = new QAction(QIcon::fromTheme(data.iconNameForPreferredSearchProvider(searchProvider)), searchProvider, view); 0612 action->setData(data.queryForPreferredSearchProvider(searchProvider)); 0613 m_actionCollection->addAction(searchProvider, action); 0614 connect(action, &QAction::triggered, ext, &WebEngineNavigationExtension::searchProvider); 0615 0616 providerList->addAction(action); 0617 } 0618 0619 QAction *action = new QAction(i18n("Configure Web Shortcuts..."), view); 0620 action->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); 0621 connect(action, &QAction::triggered, this, &WebEngineView::slotConfigureWebShortcuts); 0622 providerList->addAction(action); 0623 0624 m_actionCollection->addAction(QL1S("searchProviderList"), providerList); 0625 selectActions.append(providerList); 0626 } 0627 } 0628 } 0629 0630 #ifndef REMOTE_DND_NOT_HANDLED_BY_WEBENGINE 0631 void WebEngineView::dropEvent(QDropEvent* e) 0632 { 0633 WebEnginePage *pg = qobject_cast<WebEnginePage*>(page()); 0634 if (pg) { 0635 pg->setDropOperationStarted(); 0636 } 0637 QWebEngineView::dropEvent(e); 0638 } 0639 0640 #else 0641 void WebEngineView::dropEvent(QDropEvent* e) 0642 { 0643 QWebEngineView::dropEvent(e); 0644 //Unlike in acceptProposedDragEventIfPossible, we don't check !e->isAccepted because it seems that it's always true 0645 //(if the move event was accepted, this is accepted automatically; if the move event was rejected, this function 0646 //isn't called at all) 0647 if (!m_dragAndDropHandledBySuperclass && e->mimeData()->hasUrls()) { 0648 m_dragAndDropHandledBySuperclass = true; 0649 emit m_part->navigationExtension()->openUrlRequest(e->mimeData()->urls().first()); 0650 e->acceptProposedAction(); 0651 } 0652 } 0653 0654 void WebEngineView::acceptDragMoveEventIfPossible(QDragMoveEvent* e) 0655 { 0656 if (!e->isAccepted() && e->mimeData()->hasUrls()) { 0657 e->acceptProposedAction(); 0658 m_dragAndDropHandledBySuperclass = false; 0659 } else { 0660 m_dragAndDropHandledBySuperclass = true; 0661 } 0662 } 0663 0664 void WebEngineView::dragEnterEvent(QDragEnterEvent* e) 0665 { 0666 QWebEngineView::dragEnterEvent(e); 0667 acceptDragMoveEventIfPossible(e); 0668 } 0669 0670 void WebEngineView::dragMoveEvent(QDragMoveEvent* e) 0671 { 0672 QWebEngineView::dragMoveEvent(e); 0673 acceptDragMoveEventIfPossible(e); 0674 } 0675 #endif 0676 0677 QWebEngineContextMenuRequest* WebEngineView::result() 0678 { 0679 #if QT_VERSION_MAJOR < 6 0680 return &m_result; 0681 #else 0682 return m_result; 0683 #endif 0684 } 0685 0686 const QWebEngineContextMenuRequest* WebEngineView::result() const 0687 { 0688 #if QT_VERSION_MAJOR < 6 0689 return &m_result; 0690 #else 0691 return m_result; 0692 #endif 0693 }