File indexing completed on 2024-03-24 04:45:15
0001 /* 0002 SPDX-FileCopyrightText: 2007 Trolltech ASA 0003 SPDX-FileCopyrightText: 2008-2010 Urs Wolfer <uwolfer@kde.org> 0004 SPDX-FileCopyrightText: 2008 Laurent Montel <montel@kde.org> 0005 SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org> 0006 SPDX-FileCopyrightText: 2013 Allan Sandfeld Jensen <sandfeld@kde.org> 0007 0008 SPDX-License-Identifier: LGPL-2.1-or-later 0009 */ 0010 0011 #include "kwebkitpart.h" 0012 0013 #include <QWebElement> 0014 #include <QWebHistoryItem> 0015 0016 #include "kwebkitpart_debug.h" 0017 #include "kwebkitpart_ext.h" 0018 #include "webview.h" 0019 #include "webpage.h" 0020 #include "websslinfo.h" 0021 #include "webhistoryinterface.h" 0022 0023 #include "ui/searchbar.h" 0024 #include "ui/passwordbar.h" 0025 #include "ui/featurepermissionbar.h" 0026 #include "settings/webkitsettings.h" 0027 0028 #include <KCodecAction> 0029 #include <KSslInfoDialog> 0030 0031 #include <KActionCollection> 0032 #include <KUrlLabel> 0033 #include <KIconLoader> 0034 #include <KLocalizedString> 0035 #include <KMessageBox> 0036 #include <KStringHandler> 0037 #include <KWebWallet> 0038 #include <KToolInvocation> 0039 #include <KAcceleratorManager> 0040 #include <KFileItem> 0041 #include <KProtocolInfo> 0042 #include <KParts/StatusBarExtension> 0043 #include <KParts/GUIActivateEvent> 0044 #include <KSharedConfig> 0045 #include <KConfigGroup> 0046 #include <KParts/BrowserRun> 0047 0048 #include <QUrl> 0049 #include <QUrlQuery> 0050 #include <QIcon> 0051 #include <QMenu> 0052 #include <QTextCodec> 0053 #include <QCoreApplication> 0054 #include <QVBoxLayout> 0055 #include <QDBusInterface> 0056 #include <QStatusBar> 0057 0058 #define QL1S(x) QLatin1String(x) 0059 #define QL1C(x) QLatin1Char(x) 0060 0061 Q_GLOBAL_STATIC_WITH_ARGS(QUrl, globalBlankUrl, ("about:blank")) 0062 0063 0064 KWebKitPart::KWebKitPart(QWidget *parentWidget, QObject *parent, 0065 const KPluginMetaData& metaData, 0066 const QByteArray& cachedHistory, const QStringList& /*args*/) 0067 :KParts::ReadOnlyPart(parent), 0068 m_emitOpenUrlNotify(true), 0069 m_hasCachedFormData(false), 0070 m_doLoadFinishedActions(false), 0071 m_statusBarWalletLabel(nullptr), 0072 m_searchBar(nullptr), 0073 m_passwordBar(nullptr), 0074 m_featurePermissionBar(nullptr) 0075 { 0076 setMetaData(metaData); 0077 0078 setXMLFile(QL1S("kwebkitpart.rc")); 0079 0080 // Create this KPart's widget 0081 QWidget *mainWidget = new QWidget (parentWidget); 0082 mainWidget->setObjectName("kwebkitpart"); 0083 0084 // Create the WebView... 0085 m_webView = new WebView (this, parentWidget); 0086 0087 // Create the browser extension. 0088 m_browserExtension = new WebKitBrowserExtension(this, cachedHistory); 0089 0090 // Add status bar extension... 0091 m_statusBarExtension = new KParts::StatusBarExtension(this); 0092 0093 // Add a web history interface for storing visited links. 0094 if (!QWebHistoryInterface::defaultInterface()) 0095 QWebHistoryInterface::setDefaultInterface(new WebHistoryInterface(this)); 0096 0097 // Add text and html extensions... 0098 new KWebKitTextExtension(this); 0099 new KWebKitHtmlExtension(this); 0100 new KWebKitScriptableExtension(this); 0101 0102 0103 // Layout the GUI... 0104 QVBoxLayout* l = new QVBoxLayout(mainWidget); 0105 l->setContentsMargins(0, 0, 0, 0); 0106 l->setSpacing(0); 0107 l->addWidget(m_webView); 0108 mainWidget->setLayout(l); 0109 0110 // Set the part's widget 0111 setWidget(mainWidget); 0112 0113 // Set the web view as the focus object 0114 mainWidget->setFocusProxy(m_webView); 0115 0116 // Connect the signals from the webview 0117 connect(m_webView, SIGNAL(titleChanged(QString)), 0118 this, SIGNAL(setWindowCaption(QString))); 0119 connect(m_webView, SIGNAL(urlChanged(QUrl)), 0120 this, SLOT(slotUrlChanged(QUrl))); 0121 connect(m_webView, SIGNAL(linkMiddleOrCtrlClicked(QUrl)), 0122 this, SLOT(slotLinkMiddleOrCtrlClicked(QUrl))); 0123 connect(m_webView, SIGNAL(selectionClipboardUrlPasted(QUrl,QString)), 0124 this, SLOT(slotSelectionClipboardUrlPasted(QUrl,QString))); 0125 connect(m_webView, SIGNAL(loadFinished(bool)), 0126 this, SLOT(slotLoadFinished(bool))); 0127 0128 // Connect the signals from the page... 0129 connectWebPageSignals(page()); 0130 0131 // Init the QAction we are going to use... 0132 initActions(); 0133 0134 // Load plugins once we are fully ready 0135 loadPlugins(); 0136 } 0137 0138 KWebKitPart::~KWebKitPart() 0139 { 0140 } 0141 0142 WebPage* KWebKitPart::page() 0143 { 0144 if (m_webView) 0145 return qobject_cast<WebPage*>(m_webView->page()); 0146 return nullptr; 0147 } 0148 0149 const WebPage* KWebKitPart::page() const 0150 { 0151 if (m_webView) 0152 return qobject_cast<const WebPage*>(m_webView->page()); 0153 return nullptr; 0154 } 0155 0156 void KWebKitPart::initActions() 0157 { 0158 actionCollection()->addAction(KStandardAction::SaveAs, "saveDocument", 0159 m_browserExtension, SLOT(slotSaveDocument())); 0160 0161 QAction* action = new QAction(i18n("Save &Frame As..."), this); 0162 actionCollection()->addAction("saveFrame", action); 0163 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotSaveFrame())); 0164 0165 action = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18n("Print Preview"), this); 0166 actionCollection()->addAction("printPreview", action); 0167 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotPrintPreview())); 0168 0169 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18nc("zoom in action", "Zoom In"), this); 0170 actionCollection()->addAction("zoomIn", action); 0171 actionCollection()->setDefaultShortcuts(action, 0172 QList<QKeySequence>() << QKeySequence(Qt::CTRL+Qt::Key_Plus) 0173 << QKeySequence(Qt::CTRL+Qt::Key_Equal)); 0174 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomIn())); 0175 0176 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18nc("zoom out action", "Zoom Out"), this); 0177 actionCollection()->addAction("zoomOut", action); 0178 actionCollection()->setDefaultShortcuts(action, 0179 QList<QKeySequence>() << QKeySequence(Qt::CTRL+Qt::Key_Minus) 0180 << QKeySequence(Qt::CTRL+Qt::Key_Underscore)); 0181 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomOut())); 0182 0183 action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18nc("reset zoom action", "Actual Size"), this); 0184 actionCollection()->addAction("zoomNormal", action); 0185 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+Qt::Key_0)); 0186 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomNormal())); 0187 0188 action = new QAction(i18n("Zoom Text Only"), this); 0189 action->setCheckable(true); 0190 KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings"); 0191 bool zoomTextOnly = cgHtml.readEntry("ZoomTextOnly", false); 0192 action->setChecked(zoomTextOnly); 0193 actionCollection()->addAction("zoomTextOnly", action); 0194 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(toogleZoomTextOnly())); 0195 0196 action = new QAction(i18n("Zoom To DPI"), this); 0197 action->setCheckable(true); 0198 bool zoomToDPI = cgHtml.readEntry("ZoomToDPI", false); 0199 action->setChecked(zoomToDPI); 0200 actionCollection()->addAction("zoomToDPI", action); 0201 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(toogleZoomToDPI())); 0202 0203 action = actionCollection()->addAction(KStandardAction::SelectAll, "selectAll", 0204 m_browserExtension, SLOT(slotSelectAll())); 0205 action->setShortcutContext(Qt::WidgetShortcut); 0206 m_webView->addAction(action); 0207 0208 KCodecAction *codecAction = new KCodecAction( QIcon::fromTheme(QStringLiteral("character-set")), i18n( "Set &Encoding" ), this, true ); 0209 actionCollection()->addAction( "setEncoding", codecAction ); 0210 connect(codecAction, &KCodecAction::codecTriggered, this, &KWebKitPart::slotSetTextEncoding); 0211 0212 action = new QAction(i18n("View Do&cument Source"), this); 0213 actionCollection()->addAction("viewDocumentSource", action); 0214 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+Qt::Key_U)); 0215 connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotViewDocumentSource())); 0216 0217 action = new QAction(i18nc("Secure Sockets Layer", "View SSL Information"), this); 0218 actionCollection()->addAction("security", action); 0219 connect(action, SIGNAL(triggered(bool)), SLOT(slotShowSecurity())); 0220 0221 action = new KToggleAction(i18n("Toggle Caret Mode"), this); 0222 actionCollection()->addAction("caretMode", action); 0223 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_F7)); 0224 action->setChecked(isCaretMode()); 0225 connect(action, SIGNAL(triggered(bool)), SLOT(slotToggleCaretMode())); 0226 0227 action = actionCollection()->addAction(KStandardAction::Find, "find", this, SLOT(slotShowSearchBar())); 0228 action->setWhatsThis(i18nc("find action \"whats this\" text", "<h3>Find text</h3>" 0229 "Shows a dialog that allows you to find text on the displayed page.")); 0230 } 0231 0232 void KWebKitPart::updateActions() 0233 { 0234 m_browserExtension->updateActions(); 0235 0236 QAction* action = actionCollection()->action(QL1S("saveDocument")); 0237 if (action) { 0238 const QString protocol (url().scheme()); 0239 action->setEnabled(protocol != QL1S("about") && protocol != QL1S("error")); 0240 } 0241 0242 action = actionCollection()->action(QL1S("printPreview")); 0243 if (action) { 0244 action->setEnabled(m_browserExtension->isActionEnabled("print")); 0245 } 0246 0247 action = actionCollection()->action(QL1S("saveFrame")); 0248 if (action) { 0249 action->setEnabled((view()->page()->currentFrame() != view()->page()->mainFrame())); 0250 } 0251 } 0252 0253 void KWebKitPart::connectWebPageSignals(WebPage* page) 0254 { 0255 if (!page) 0256 return; 0257 0258 connect(page, SIGNAL(loadStarted()), 0259 this, SLOT(slotLoadStarted())); 0260 connect(page, SIGNAL(loadAborted(QUrl)), 0261 this, SLOT(slotLoadAborted(QUrl))); 0262 connect(page, SIGNAL(linkHovered(QString,QString,QString)), 0263 this, SLOT(slotLinkHovered(QString,QString,QString))); 0264 connect(page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)), 0265 this, SLOT(slotSaveFrameState(QWebFrame*,QWebHistoryItem*))); 0266 connect(page, SIGNAL(restoreFrameStateRequested(QWebFrame*)), 0267 this, SLOT(slotRestoreFrameState(QWebFrame*))); 0268 connect(page, SIGNAL(statusBarMessage(QString)), 0269 this, SLOT(slotSetStatusBarText(QString))); 0270 connect(page, SIGNAL(windowCloseRequested()), 0271 this, SLOT(slotWindowCloseRequested())); 0272 connect(page, SIGNAL(printRequested(QWebFrame*)), 0273 m_browserExtension, SLOT(slotPrintRequested(QWebFrame*))); 0274 connect(page, SIGNAL(frameCreated(QWebFrame*)), 0275 this, SLOT(slotFrameCreated(QWebFrame*))); 0276 0277 connect(m_webView, SIGNAL(linkShiftClicked(QUrl)), 0278 page, SLOT(downloadUrl(QUrl))); 0279 0280 connect(page, SIGNAL(loadProgress(int)), 0281 m_browserExtension, SIGNAL(loadingProgress(int))); 0282 connect(page, SIGNAL(selectionChanged()), 0283 m_browserExtension, SLOT(updateEditActions())); 0284 connect(m_browserExtension, SIGNAL(saveUrl(QUrl)), 0285 page, SLOT(downloadUrl(QUrl))); 0286 0287 connect(page->mainFrame(), SIGNAL(loadFinished(bool)), 0288 this, SLOT(slotMainFrameLoadFinished(bool))); 0289 0290 0291 KWebWallet *wallet = page->wallet(); 0292 if (wallet) { 0293 connect(wallet, SIGNAL(saveFormDataRequested(QString,QUrl)), 0294 this, SLOT(slotSaveFormDataRequested(QString,QUrl))); 0295 connect(wallet, SIGNAL(fillFormRequestCompleted(bool)), 0296 this, SLOT(slotFillFormRequestCompleted(bool))); 0297 connect(wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); 0298 } 0299 } 0300 0301 bool KWebKitPart::openUrl(const QUrl &_u) 0302 { 0303 QUrl u (_u); 0304 0305 qCDebug(KWEBKITPART_LOG) << u; 0306 0307 // Ignore empty requests... 0308 if (u.isEmpty()) 0309 return false; 0310 0311 // If the URL given is a supported local protocol, e.g. "bookmark" but lacks 0312 // a path component, we set the path to "/" here so that the security context 0313 // will properly allow access to local resources. 0314 if (u.host().isEmpty() && u.path().isEmpty() 0315 && KProtocolInfo::protocolClass(u.scheme()) == QL1S(":local")) { 0316 u.setPath(QL1S("/")); 0317 } 0318 0319 // Do not emit update history when url is typed in since the embedding part 0320 // should handle that automatically itself. At least Konqueror does that. 0321 m_emitOpenUrlNotify = false; 0322 0323 // Pointer to the page object... 0324 WebPage* p = page(); 0325 Q_ASSERT(p); 0326 0327 //The new konq protocol used by Konqueror is not implemented using an ioslave 0328 //and it isn't (currently) supported by kwebkitpart. 0329 //If support for the konq protocol is added to kwebkitpart, remove the following 0330 //if statement 0331 if (u.scheme() == "konq") { 0332 u = KParts::BrowserRun::makeErrorUrl(KIO::ERR_UNSUPPORTED_PROTOCOL, u.url(), u); 0333 } 0334 0335 // Handle error conditions... 0336 if (u.scheme() == QL1S("error")) { 0337 /** 0338 * The format of the error url is that two variables are passed in the query: 0339 * error = int kio error code, errText = QString error text from kio 0340 * and the URL where the error happened is passed as a sub URL. 0341 */ 0342 const QUrl mainUrl(u.fragment()); 0343 0344 if (mainUrl.isValid()) { 0345 QString query = u.query(QUrl::FullyDecoded); 0346 QRegularExpression pattern("error=(\\d+)&errText=(.*)"); 0347 QRegularExpressionMatch match = pattern.match(query); 0348 int error = match.captured(1).toInt(); 0349 // error=0 isn't a valid error code, so 0 means it's missing from the URL 0350 if (error == 0) { 0351 error = KIO::ERR_UNKNOWN; 0352 } 0353 const QString errorText = match.captured(2); 0354 0355 emit m_browserExtension->setLocationBarUrl(mainUrl.toDisplayString()); 0356 if (p) { 0357 m_webView->setHtml(p->errorPage(error, errorText, mainUrl)); 0358 return true; 0359 } 0360 } 0361 0362 return false; 0363 } 0364 0365 KParts::BrowserArguments bargs (m_browserExtension->browserArguments()); 0366 KParts::OpenUrlArguments args (arguments()); 0367 0368 if (u != *globalBlankUrl) { 0369 // Get the SSL information sent, if any... 0370 if (args.metaData().contains(QL1S("ssl_in_use"))) { 0371 WebSslInfo sslInfo; 0372 sslInfo.restoreFrom(KIO::MetaData(args.metaData()).toVariant()); 0373 sslInfo.setUrl(u); 0374 p->setSslInfo(sslInfo); 0375 } 0376 } 0377 0378 // Set URL in KParts before emitting started; konq plugins rely on that. 0379 setUrl(u); 0380 m_doLoadFinishedActions = true; 0381 m_webView->loadUrl(u, args, bargs); 0382 return true; 0383 } 0384 0385 bool KWebKitPart::isCaretMode() const 0386 { 0387 return page()->settings()->testAttribute(QWebSettings::CaretBrowsingEnabled); 0388 } 0389 0390 void KWebKitPart::slotToggleCaretMode() 0391 { 0392 page()->settings()->setAttribute(QWebSettings::CaretBrowsingEnabled, !isCaretMode()); 0393 } 0394 0395 bool KWebKitPart::closeUrl() 0396 { 0397 m_webView->triggerPageAction(QWebPage::StopScheduledPageRefresh); 0398 m_webView->stop(); 0399 return true; 0400 } 0401 0402 QWebView* KWebKitPart::view() const 0403 { 0404 return m_webView; 0405 } 0406 0407 bool KWebKitPart::isModified() const 0408 { 0409 return m_webView->isModified(); 0410 } 0411 0412 void KWebKitPart::guiActivateEvent(KParts::GUIActivateEvent *event) 0413 { 0414 if (event && event->activated() && m_webView) { 0415 emit setWindowCaption(m_webView->title()); 0416 } 0417 } 0418 0419 bool KWebKitPart::openFile() 0420 { 0421 // never reached 0422 return false; 0423 } 0424 0425 0426 /// slots... 0427 0428 void KWebKitPart::slotLoadStarted() 0429 { 0430 emit started(nullptr); 0431 updateActions(); 0432 } 0433 0434 void KWebKitPart::slotFrameLoadFinished(bool ok) 0435 { 0436 QWebFrame* frame = (sender() ? qobject_cast<QWebFrame*>(sender()) : page()->mainFrame()); 0437 0438 if (ok) { 0439 const QUrl currentUrl (frame->baseUrl().resolved(frame->url())); 0440 // qCDebug(KWEBKITPART_LOG) << "mainframe:" << m_webView->page()->mainFrame() << "frame:" << sender(); 0441 // qCDebug(KWEBKITPART_LOG) << "url:" << frame->url() << "base url:" << frame->baseUrl() << "request url:" << frame->requestedUrl(); 0442 if (currentUrl != *globalBlankUrl) { 0443 m_hasCachedFormData = false; 0444 0445 if (WebKitSettings::self()->isNonPasswordStorableSite(currentUrl.host())) { 0446 addWalletStatusBarIcon(); 0447 } else { 0448 // Attempt to fill the web form... 0449 KWebWallet *webWallet = page() ? page()->wallet() : nullptr; 0450 if (webWallet) { 0451 webWallet->fillFormData(frame, false); 0452 } 0453 } 0454 } 0455 } 0456 } 0457 0458 void KWebKitPart::slotMainFrameLoadFinished (bool ok) 0459 { 0460 if (!ok || !m_doLoadFinishedActions) 0461 return; 0462 0463 m_doLoadFinishedActions = false; 0464 0465 if (!m_emitOpenUrlNotify) { 0466 m_emitOpenUrlNotify = true; // Save history once page loading is done. 0467 } 0468 0469 // If the document contains no <title> tag, then set it to the current url. 0470 if (m_webView->title().trimmed().isEmpty()) { 0471 // If the document title is empty, then set it to the current url 0472 const QUrl url (m_webView->url()); 0473 const QString caption (url.toString((QUrl::RemoveQuery|QUrl::RemoveFragment))); 0474 emit setWindowCaption(caption); 0475 0476 // The urlChanged signal is emitted if and only if the main frame 0477 // receives the title of the page so we manually invoke the slot as a 0478 // work around here for pages that do not contain it, such as text 0479 // documents... 0480 slotUrlChanged(url); 0481 } 0482 0483 QWebFrame* frame = page()->mainFrame(); 0484 0485 if (!frame || frame->url() == *globalBlankUrl) 0486 return; 0487 0488 // Set the favicon specified through the <link> tag... 0489 if (WebKitSettings::self()->favIconsEnabled() 0490 && !frame->page()->settings()->testAttribute(QWebSettings::PrivateBrowsingEnabled)) { 0491 const QWebElement element = frame->findFirstElement(QL1S("head>link[rel=icon], " 0492 "head>link[rel=\"shortcut icon\"]")); 0493 QUrl shortcutIconUrl; 0494 if (!element.isNull()) { 0495 shortcutIconUrl = frame->baseUrl().resolved(QUrl(element.attribute("href"))); 0496 //qCDebug(KWEBKITPART_LOG) << "setting favicon to" << shortcutIconUrl; 0497 m_browserExtension->setIconUrl(shortcutIconUrl); 0498 } 0499 } 0500 0501 slotFrameLoadFinished(ok); 0502 } 0503 0504 void KWebKitPart::slotLoadFinished(bool ok) 0505 { 0506 bool pending = false; 0507 0508 if (m_doLoadFinishedActions) { 0509 updateActions(); 0510 QWebFrame* frame = (page() ? page()->currentFrame() : nullptr); 0511 if (ok && 0512 frame == page()->mainFrame() && 0513 !frame->findFirstElement(QL1S("head>meta[http-equiv=refresh]")).isNull()) { 0514 if (WebKitSettings::self()->autoPageRefresh()) { 0515 pending = true; 0516 } else { 0517 frame->page()->triggerAction(QWebPage::StopScheduledPageRefresh); 0518 } 0519 } 0520 } 0521 0522 emit completed ((ok && pending)); 0523 } 0524 0525 void KWebKitPart::slotLoadAborted(const QUrl & url) 0526 { 0527 closeUrl(); 0528 m_doLoadFinishedActions = false; 0529 if (url.isValid()) 0530 emit m_browserExtension->openUrlRequest(url); 0531 else 0532 setUrl(m_webView->url()); 0533 } 0534 0535 void KWebKitPart::slotUrlChanged(const QUrl& url) 0536 { 0537 // Ignore if empty 0538 if (url.isEmpty()) 0539 return; 0540 0541 // Ignore if error url 0542 if (url.scheme().compare(QL1S("error"), Qt::CaseInsensitive) == 0) 0543 return; 0544 0545 const QUrl u (url); 0546 0547 // Ignore if url has not changed! 0548 if (this->url() == u) 0549 return; 0550 0551 m_doLoadFinishedActions = true; 0552 setUrl(u); 0553 0554 // Do not update the location bar with about:blank 0555 if (url != *globalBlankUrl) { 0556 //qCDebug(KWEBKITPART_LOG) << "Setting location bar to" << u.prettyUrl() << "current URL:" << this->url(); 0557 emit m_browserExtension->setLocationBarUrl(u.toDisplayString()); 0558 } 0559 } 0560 0561 void KWebKitPart::slotShowSecurity() 0562 { 0563 if (!page()) 0564 return; 0565 0566 const WebSslInfo& sslInfo = page()->sslInfo(); 0567 if (!sslInfo.isValid()) { 0568 KMessageBox::information(nullptr, i18n("This site is not secured with SSL, or its SSL information is not valid."), 0569 i18nc("Secure Sockets Layer", "SSL")); 0570 return; 0571 } 0572 0573 KSslInfoDialog *dlg = new KSslInfoDialog (widget()); 0574 dlg->setSslInfo(sslInfo.certificateChain(), 0575 sslInfo.peerAddress().toString(), 0576 url().host(), 0577 sslInfo.protocol(), 0578 sslInfo.ciphers(), 0579 sslInfo.usedChiperBits(), 0580 sslInfo.supportedChiperBits(), 0581 KSslInfoDialog::certificateErrorsFromString(sslInfo.certificateErrors())); 0582 dlg->open(); 0583 } 0584 0585 void KWebKitPart::slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item) 0586 { 0587 if (!frame || !item) { 0588 return; 0589 } 0590 0591 // Handle actions that apply only to the mainframe... 0592 if (frame == view()->page()->mainFrame()) { 0593 slotWalletClosed(); 0594 0595 // If "NoEmitOpenUrlNotification" property is set to true, do not 0596 // emit the open url notification. Property is set by this part's 0597 // extension to prevent openUrl notification being sent when 0598 // handling history navigation requests. 0599 const bool doNotEmitOpenUrl = property("NoEmitOpenUrlNotification").toBool(); 0600 if (doNotEmitOpenUrl) { 0601 setProperty("NoEmitOpenUrlNotification", QVariant()); 0602 } 0603 0604 // Only emit open url notify for the main frame. Do not 0605 if (m_emitOpenUrlNotify && !doNotEmitOpenUrl) { 0606 // qCDebug(KWEBKITPART_LOG) << "***** EMITTING openUrlNotify" << item->url(); 0607 emit m_browserExtension->openUrlNotify(); 0608 } 0609 } 0610 0611 // For some reason, QtWebKit does not restore scroll position when 0612 // QWebHistory is restored from persistent storage. Therefore, we 0613 // preserve that information and restore it as needed. See 0614 // slotRestoreFrameState. 0615 const QPoint scrollPos (frame->scrollPosition()); 0616 if (!scrollPos.isNull()) { 0617 // qCDebug(KWEBKITPART_LOG) << "Saving scroll position:" << scrollPos; 0618 item->setUserData(scrollPos); 0619 } 0620 } 0621 0622 void KWebKitPart::slotRestoreFrameState(QWebFrame *frame) 0623 { 0624 QWebPage* page = (frame ? frame->page() : nullptr); 0625 QWebHistory* history = (page ? page->history() : nullptr); 0626 0627 // No history item... 0628 if (!history || history->count() < 1) 0629 return; 0630 0631 QWebHistoryItem currentHistoryItem (history->currentItem()); 0632 0633 // Update the scroll position if needed. See comment in slotSaveFrameState above. 0634 if (frame->baseUrl().resolved(frame->url()) == currentHistoryItem.url()) { 0635 const QPoint currentPos (frame->scrollPosition()); 0636 const QPoint desiredPos (currentHistoryItem.userData().toPoint()); 0637 if (currentPos.isNull() && !desiredPos.isNull()) { 0638 frame->setScrollPosition(desiredPos); 0639 } 0640 } 0641 } 0642 0643 void KWebKitPart::slotLinkHovered(const QString& _link, const QString& /*title*/, const QString& /*content*/) 0644 { 0645 QString message; 0646 0647 if (_link.isEmpty()) { 0648 message = QL1S(""); 0649 emit m_browserExtension->mouseOverInfo(KFileItem()); 0650 } else { 0651 QUrl linkUrl (_link); 0652 const QString scheme = linkUrl.scheme(); 0653 0654 // Protect the user against URL spoofing! 0655 linkUrl.setUserName(QString()); 0656 const QString link (linkUrl.toString()); 0657 0658 if (scheme == QL1S("mailto")) { 0659 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", "Email: "); 0660 0661 // Workaround: for QUrl's parsing deficiencies of "mailto:foo@bar.com". 0662 if (!linkUrl.hasQuery()) 0663 linkUrl = QUrl(scheme + '?' + linkUrl.path()); 0664 0665 QMap<QString, QStringList> fields; 0666 QList<QPair<QString, QString> > queryItems = QUrlQuery(linkUrl).queryItems(); 0667 const int count = queryItems.count(); 0668 0669 for(int i = 0; i < count; ++i) { 0670 const QPair<QString, QString> queryItem (queryItems.at(i)); 0671 //qCDebug(KWEBKITPART_LOG) << "query: " << queryItem.first << queryItem.second; 0672 if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) 0673 fields["to"] << queryItem.first; 0674 if (QString::compare(queryItem.first, QL1S("to"), Qt::CaseInsensitive) == 0) 0675 fields["to"] << queryItem.second; 0676 if (QString::compare(queryItem.first, QL1S("cc"), Qt::CaseInsensitive) == 0) 0677 fields["cc"] << queryItem.second; 0678 if (QString::compare(queryItem.first, QL1S("bcc"), Qt::CaseInsensitive) == 0) 0679 fields["bcc"] << queryItem.second; 0680 if (QString::compare(queryItem.first, QL1S("subject"), Qt::CaseInsensitive) == 0) 0681 fields["subject"] << queryItem.second; 0682 } 0683 0684 if (fields.contains(QL1S("to"))) 0685 message += fields.value(QL1S("to")).join(QL1S(", ")); 0686 if (fields.contains(QL1S("cc"))) 0687 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - CC: ") + fields.value(QL1S("cc")).join(QL1S(", ")); 0688 if (fields.contains(QL1S("bcc"))) 0689 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - BCC: ") + fields.value(QL1S("bcc")).join(QL1S(", ")); 0690 if (fields.contains(QL1S("subject"))) 0691 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - Subject: ") + fields.value(QL1S("subject")).join(QL1S(" ")); 0692 } else if (scheme == QL1S("javascript")) { 0693 message = KStringHandler::rsqueeze(link, 150); 0694 if (link.startsWith(QL1S("javascript:window.open"))) 0695 message += i18n(" (In new window)"); 0696 } else { 0697 message = link; 0698 QWebFrame* frame = page() ? page()->currentFrame() : nullptr; 0699 if (frame) { 0700 QWebHitTestResult result = frame->hitTestContent(page()->view()->mapFromGlobal(QCursor::pos())); 0701 QWebFrame* target = result.linkTargetFrame(); 0702 if (frame->parentFrame() && target == frame->parentFrame()) { 0703 message += i18n(" (In parent frame)"); 0704 } else if (!target || target != frame) { 0705 message += i18n(" (In new window)"); 0706 } 0707 } 0708 KFileItem item (linkUrl, QString(), KFileItem::Unknown); 0709 emit m_browserExtension->mouseOverInfo(item); 0710 } 0711 } 0712 0713 emit setStatusBarText(message); 0714 } 0715 0716 void KWebKitPart::slotSearchForText(const QString &text, bool backward) 0717 { 0718 QWebPage::FindFlags flags = QWebPage::FindWrapsAroundDocument; 0719 0720 if (backward) 0721 flags |= QWebPage::FindBackward; 0722 0723 if (m_searchBar->caseSensitive()) 0724 flags |= QWebPage::FindCaseSensitively; 0725 0726 if (m_searchBar->highlightMatches()) 0727 flags |= QWebPage::HighlightAllOccurrences; 0728 0729 //qCDebug(KWEBKITPART_LOG) << "search for text:" << text << ", backward ?" << backward; 0730 m_searchBar->setFoundMatch(page()->findText(text, flags)); 0731 } 0732 0733 void KWebKitPart::slotShowSearchBar() 0734 { 0735 if (!m_searchBar) { 0736 // Create the search bar... 0737 m_searchBar = new SearchBar(widget()); 0738 connect(m_searchBar, SIGNAL(searchTextChanged(QString,bool)), 0739 this, SLOT(slotSearchForText(QString,bool))); 0740 0741 actionCollection()->addAction(KStandardAction::FindNext, "findnext", 0742 m_searchBar, SLOT(findNext())); 0743 actionCollection()->addAction(KStandardAction::FindPrev, "findprev", 0744 m_searchBar, SLOT(findPrevious())); 0745 0746 QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); 0747 if (lay) { 0748 lay->addWidget(m_searchBar); 0749 } 0750 } 0751 const QString text = m_webView->selectedText(); 0752 m_searchBar->setSearchText(text.left(150)); 0753 } 0754 0755 void KWebKitPart::slotLinkMiddleOrCtrlClicked(const QUrl& linkUrl) 0756 { 0757 emit m_browserExtension->createNewWindow(linkUrl); 0758 } 0759 0760 void KWebKitPart::slotSelectionClipboardUrlPasted(const QUrl& selectedUrl, const QString& searchText) 0761 { 0762 if (!WebKitSettings::self()->isOpenMiddleClickEnabled()) 0763 return; 0764 0765 if (!searchText.isEmpty() && 0766 KMessageBox::questionYesNo(m_webView, 0767 i18n("<qt>Do you want to search for <b>%1</b>?</qt>", searchText), 0768 i18n("Internet Search"), KGuiItem(i18n("&Search"), "edit-find"), 0769 KStandardGuiItem::cancel(), "MiddleClickSearch") != KMessageBox::Yes) 0770 return; 0771 0772 emit m_browserExtension->openUrlRequest(selectedUrl); 0773 } 0774 0775 void KWebKitPart::slotWalletClosed() 0776 { 0777 if (!m_statusBarWalletLabel) 0778 return; 0779 0780 m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); 0781 delete m_statusBarWalletLabel; 0782 m_statusBarWalletLabel = nullptr; 0783 m_hasCachedFormData = false; 0784 } 0785 0786 void KWebKitPart::slotShowWalletMenu() 0787 { 0788 QMenu *menu = new QMenu; 0789 0790 if (m_webView && WebKitSettings::self()->isNonPasswordStorableSite(m_webView->url().host())) 0791 menu->addAction(i18n("&Allow password caching for this site"), this, SLOT(slotDeleteNonPasswordStorableSite())); 0792 0793 if (m_hasCachedFormData) 0794 menu->addAction(i18n("Remove all cached passwords for this site"), this, SLOT(slotRemoveCachedPasswords())); 0795 0796 menu->addSeparator(); 0797 menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed())); 0798 0799 KAcceleratorManager::manage(menu); 0800 menu->popup(QCursor::pos()); 0801 } 0802 0803 void KWebKitPart::slotLaunchWalletManager() 0804 { 0805 QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1"); 0806 if (r.isValid()) 0807 r.call(QDBus::NoBlock, "show"); 0808 else 0809 KToolInvocation::startServiceByDesktopName("kwalletmanager_show"); 0810 } 0811 0812 void KWebKitPart::slotDeleteNonPasswordStorableSite() 0813 { 0814 if (m_webView) 0815 WebKitSettings::self()->removeNonPasswordStorableSite(m_webView->url().host()); 0816 } 0817 0818 void KWebKitPart::slotRemoveCachedPasswords() 0819 { 0820 if (!page() || !page()->wallet()) 0821 return; 0822 0823 page()->wallet()->removeFormData(page()->mainFrame(), true); 0824 m_hasCachedFormData = false; 0825 } 0826 0827 void KWebKitPart::slotSetTextEncoding(QTextCodec * codec) 0828 { 0829 // FIXME: The code below that sets the text encoding has been reported not to work. 0830 if (!page()) 0831 return; 0832 0833 QWebSettings *localSettings = page()->settings(); 0834 if (!localSettings) 0835 return; 0836 0837 qCDebug(KWEBKITPART_LOG) << "Encoding: new=>" << localSettings->defaultTextEncoding() << ", old=>" << codec->name(); 0838 0839 localSettings->setDefaultTextEncoding(codec->name()); 0840 page()->triggerAction(QWebPage::Reload); 0841 } 0842 0843 void KWebKitPart::slotSetStatusBarText(const QString& text) 0844 { 0845 const QString host (page() ? page()->currentFrame()->url().host() : QString()); 0846 if (WebKitSettings::self()->windowStatusPolicy(host) == KParts::HtmlSettingsInterface::JSWindowStatusAllow) 0847 emit setStatusBarText(text); 0848 } 0849 0850 void KWebKitPart::slotWindowCloseRequested() 0851 { 0852 emit m_browserExtension->requestFocus(this); 0853 #if 0 0854 if (KMessageBox::questionYesNo(m_webView, 0855 i18n("Close window?"), i18n("Confirmation Required"), 0856 KStandardGuiItem::close(), KStandardGuiItem::cancel()) 0857 != KMessageBox::Yes) 0858 return; 0859 #endif 0860 this->deleteLater(); 0861 } 0862 0863 void KWebKitPart::slotShowFeaturePermissionBar(QWebPage::Feature feature) 0864 { 0865 // FIXME: Allow multiple concurrent feature permission requests. 0866 if (m_featurePermissionBar && m_featurePermissionBar->isVisible()) 0867 return; 0868 0869 if (!m_featurePermissionBar) { 0870 m_featurePermissionBar = new FeaturePermissionBar(widget()); 0871 0872 connect(m_featurePermissionBar, SIGNAL(permissionGranted(QWebPage::Feature)), 0873 this, SLOT(slotFeaturePermissionGranted(QWebPage::Feature))); 0874 connect(m_featurePermissionBar, SIGNAL(permissionDenied(QWebPage::Feature)), 0875 this, SLOT(slotFeaturePermissionDenied(QWebPage::Feature))); 0876 // connect(m_passwordBar, SIGNAL(done()), 0877 // this, SLOT(slotSaveFormDataDone())); 0878 QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); 0879 if (lay) 0880 lay->insertWidget(0, m_featurePermissionBar); 0881 } 0882 m_featurePermissionBar->setFeature(feature); 0883 // m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site <b>%1</b> " 0884 // "access to information about your current physical location?", 0885 // url.host())); 0886 m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site " 0887 "access to information about your current physical location?")); 0888 m_featurePermissionBar->animatedShow(); 0889 } 0890 0891 void KWebKitPart::slotFeaturePermissionGranted(QWebPage::Feature feature) 0892 { 0893 Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); 0894 page()->setFeaturePermission(page()->mainFrame(), feature, QWebPage::PermissionGrantedByUser); 0895 } 0896 0897 void KWebKitPart::slotFeaturePermissionDenied(QWebPage::Feature feature) 0898 { 0899 Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); 0900 page()->setFeaturePermission(page()->mainFrame(), feature, QWebPage::PermissionDeniedByUser); 0901 } 0902 0903 void KWebKitPart::slotSaveFormDataRequested (const QString& key, const QUrl& url) 0904 { 0905 if (WebKitSettings::self()->isNonPasswordStorableSite(url.host())) 0906 return; 0907 0908 if (!WebKitSettings::self()->askToSaveSitePassword()) 0909 return; 0910 0911 if (m_passwordBar && m_passwordBar->isVisible()) 0912 return; 0913 0914 if (!m_passwordBar) { 0915 m_passwordBar = new PasswordBar(widget()); 0916 KWebWallet* wallet = page()->wallet(); 0917 if (!wallet) { 0918 qCWarning(KWEBKITPART_LOG) << "No wallet instance found! This should never happen!"; 0919 return; 0920 } 0921 connect(m_passwordBar, SIGNAL(saveFormDataAccepted(QString)), 0922 wallet, SLOT(acceptSaveFormDataRequest(QString))); 0923 connect(m_passwordBar, SIGNAL(saveFormDataRejected(QString)), 0924 wallet, SLOT(rejectSaveFormDataRequest(QString))); 0925 connect(m_passwordBar, SIGNAL(done()), 0926 this, SLOT(slotSaveFormDataDone())); 0927 } 0928 0929 Q_ASSERT(m_passwordBar); 0930 0931 m_passwordBar->setUrl(url); 0932 m_passwordBar->setRequestKey(key); 0933 m_passwordBar->setText(i18n("<html>Do you want %1 to remember the login " 0934 "information for <b>%2</b>?</html>", 0935 QCoreApplication::applicationName(), 0936 url.host())); 0937 0938 QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); 0939 if (lay) 0940 lay->insertWidget(0, m_passwordBar); 0941 0942 m_passwordBar->animatedShow(); 0943 } 0944 0945 void KWebKitPart::slotSaveFormDataDone() 0946 { 0947 if (!m_passwordBar) 0948 return; 0949 0950 QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); 0951 if (lay) 0952 lay->removeWidget(m_passwordBar); 0953 } 0954 0955 void KWebKitPart::addWalletStatusBarIcon () 0956 { 0957 if (m_statusBarWalletLabel) { 0958 m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); 0959 } else { 0960 m_statusBarWalletLabel = new KUrlLabel(m_statusBarExtension->statusBar()); 0961 m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 0962 m_statusBarWalletLabel->setUseCursor(false); 0963 m_statusBarWalletLabel->setPixmap(QIcon::fromTheme("wallet-open").pixmap(KIconLoader::SizeSmall)); 0964 connect(m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(slotLaunchWalletManager())); 0965 connect(m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(slotShowWalletMenu())); 0966 } 0967 m_statusBarExtension->addStatusBarItem(m_statusBarWalletLabel, 0, false); 0968 } 0969 0970 void KWebKitPart::slotFillFormRequestCompleted (bool ok) 0971 { 0972 if ((m_hasCachedFormData = ok)) 0973 addWalletStatusBarIcon(); 0974 } 0975 0976 void KWebKitPart::slotFrameCreated (QWebFrame* frame) 0977 { 0978 if (frame != page()->mainFrame()) { 0979 connect(frame, SIGNAL(loadFinished(bool)), this, SLOT(slotFrameLoadFinished(bool)), Qt::UniqueConnection); 0980 } 0981 }