webenginepart.cpp 38.2 KB
Newer Older
1 2 3 4
/*
 * This file is part of the KDE project.
 *
 * Copyright (C) 2007 Trolltech ASA
5
 * Copyright (C) 2008 - 2010 Urs Wolfer <uwolfer @ kde.org>
6
 * Copyright (C) 2008 Laurent Montel <montel@kde.org>
7
 * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org>
8
 * Copyright (C) 2013 Allan Sandfeld Jensen <sandfeld@kde.org>
9
 *
10 11 12 13
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
14
 *
15 16 17 18
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
19
 *
20 21
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
22 23 24
 *
 */

25
#include "webenginepart.h"
26
#include "webenginepartkiohandler.h"
27
#include "about/konq_aboutpage.h"
Urs Wolfer's avatar
Urs Wolfer committed
28

29 30
#include <webenginepart_debug.h>

31
//#include <QWebHistoryItem>
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
32 33
#include <QWebEngineSettings>
#include <QWebEngineProfile>
34
#include <QUrlQuery>
35

36
#include "webenginepart_ext.h"
37
#include "webengineview.h"
38
#include "webenginepage.h"
39
#include "websslinfo.h"
40
#include "webhistoryinterface.h"
41
#include "webenginewallet.h"
42
#include "webengineparterrorschemehandler.h"
43
#include "webenginepartcookiejar.h"
44

45
#include "ui/searchbar.h"
46
#include "ui/passwordbar.h"
47
#include "ui/featurepermissionbar.h"
48
#include "settings/webenginesettings.h"
49

50 51
#include <KCodecAction>
#include <KIO/Global>
52 53 54 55 56 57 58 59 60 61 62

#include <KActionCollection>
#include <KAboutData>
#include <KUrlLabel>
#include <KMessageBox>
#include <KStringHandler>
#include <KAcceleratorManager>
#include <KFileItem>
#include <KMessageWidget>
#include <KProtocolInfo>
#include <KToggleAction>
63
#include <KParts/StatusBarExtension>
Daniel Grosz's avatar
Daniel Grosz committed
64
#include <KParts/GUIActivateEvent>
65 66 67
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
68
#include <KSslInfoDialog>
69
#include <KProtocolManager>
70
#include <KProtocolInfo>
71 72
#include <KParts/PartActivateEvent>
#include <KParts/BrowserInterface>
Nicolas Fella's avatar
Nicolas Fella committed
73
#include <KIO/ApplicationLauncherJob>
74

Dawit Alemayehu's avatar
Dawit Alemayehu committed
75 76 77
#include <QUrl>
#include <QFile>
#include <QTextCodec>
78
#include <QCoreApplication>
Dawit Alemayehu's avatar
Dawit Alemayehu committed
79 80
#include <QVBoxLayout>
#include <QDBusInterface>
81 82
#include <QMenu>
#include <QStatusBar>
83 84 85
#ifdef USE_QWEBENGINE_URL_SCHEME
#include <QWebEngineUrlScheme>
#endif
86
#include "utils.h"
87 88 89 90 91 92 93 94
#include <kio_version.h>

void WebEnginePart::initWebEngineUrlSchemes()
{
#ifdef USE_QWEBENGINE_URL_SCHEME
    static bool needToInitUrlSchemes = true;
    if (needToInitUrlSchemes) {
        needToInitUrlSchemes = false;
95
        QVector<QByteArray> localSchemes = {"error", "konq"};
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
        const QStringList protocols = KProtocolInfo::protocols();
        for(const QString &prot : protocols){
#if KIO_VERSION >= QT_VERSION_CHECK(5,60,0)
            if (KProtocolInfo::defaultMimetype(prot) == "text/html") {
                localSchemes.append(QByteArray(prot.toLatin1()));
            }
#else
            QUrl fakeUrl;
            fakeUrl.setScheme(prot);
            fakeUrl.setPath("fake");
            if (KProtocolManager::defaultMimetype(fakeUrl) == "text/html"){
                localSchemes.append(QByteArray(prot.toLatin1()));
            }
#endif
        }
        for (const QByteArray &name : qAsConst(localSchemes)){
            QWebEngineUrlScheme scheme(name);
            scheme.setFlags(QWebEngineUrlScheme::LocalScheme|QWebEngineUrlScheme::LocalAccessAllowed);
            scheme.setSyntax(QWebEngineUrlScheme::Syntax::Path);
            QWebEngineUrlScheme::registerScheme(scheme);
        }
    }
#endif
}
120

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
121
WebEnginePart::WebEnginePart(QWidget *parentWidget, QObject *parent,
122
                         const QByteArray& cachedHistory, const QStringList& /*args*/)
123 124 125
            :KParts::ReadOnlyPart(parent),
             m_emitOpenUrlNotify(true),
             m_hasCachedFormData(false),
126
             m_doLoadFinishedActions(false),
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
127 128 129 130 131
             m_statusBarWalletLabel(nullptr),
             m_searchBar(nullptr),
             m_passwordBar(nullptr),
             m_featurePermissionBar(nullptr),
             m_wallet(nullptr)
132
{
133
    initWebEngineUrlSchemes();
134 135 136
    QWebEngineProfile *prof = QWebEngineProfile::defaultProfile();
    if (!prof->urlSchemeHandler("error")) {
        prof->installUrlSchemeHandler("error", new WebEnginePartErrorSchemeHandler(prof));
137
        prof->installUrlSchemeHandler("konq", new KonqUrlSchemeHandler(prof));
138
        prof->installUrlSchemeHandler("help", new WebEnginePartKIOHandler(prof));
139
    }
140
    static WebEnginePartCookieJar s_cookieJar(prof, nullptr);
141
    KAboutData about = KAboutData(QStringLiteral("webenginepart"),
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
142
                                  i18nc("Program Name", "WebEnginePart"),
143
                                  /*version*/ QStringLiteral("1.3.0"),
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
144
                                  i18nc("Short Description", "QtWebEngine Browser Engine Component"),
Daniel Grosz's avatar
Daniel Grosz committed
145 146
                                  KAboutLicense::LGPL,
                                  i18n("(C) 2009-2010 Dawit Alemayehu\n"
147 148
                                        "(C) 2008-2010 Urs Wolfer\n"
                                        "(C) 2007 Trolltech ASA"));
149

150 151 152 153 154 155
    about.addAuthor(i18n("Sune Vuorela"), i18n("Maintainer, Developer"), QStringLiteral("sune@kde.org"));
    about.addAuthor(i18n("Dawit Alemayehu"), i18n("Developer"), QStringLiteral("adawit@kde.org"));
    about.addAuthor(i18n("Urs Wolfer"), i18n("Maintainer, Developer"), QStringLiteral("uwolfer@kde.org"));
    about.addAuthor(i18n("Michael Howell"), i18n("Developer"), QStringLiteral("mhowell123@gmail.com"));
    about.addAuthor(i18n("Laurent Montel"), i18n("Developer"), QStringLiteral("montel@kde.org"));
    about.addAuthor(i18n("Dirk Mueller"), i18n("Developer"), QStringLiteral("mueller@kde.org"));
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
156
    about.setProductName("webenginepart/general");
Daniel Grosz's avatar
Daniel Grosz committed
157 158
//    KComponentData componentData(&about);
    setComponentData(about, false /*don't load plugins yet*/);
159

160
#if 0
161 162
    // NOTE: If the application does not set its version number, we automatically
    // set it to KDE's version number so that the default user-agent string contains
163
    // proper application version number information. See QWebEnginePage::userAgentForUrl...
164
    if (QCoreApplication::applicationVersion().isEmpty())
165 166 167 168
        QCoreApplication::setApplicationVersion(QString("%1.%2.%3")
                                                .arg(KDE::versionMajor())
                                                .arg(KDE::versionMinor())
                                                .arg(KDE::versionRelease()));
169
#endif
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
170
    setXMLFile(QL1S("webenginepart.rc"));
171 172

    // Create this KPart's widget
173
    QWidget *mainWidget = new QWidget (parentWidget);
174
    mainWidget->setObjectName(QStringLiteral("webenginepart"));
175

176 177
    // Create the WebEngineView...
    m_webView = new WebEngineView (this, parentWidget);
178

179
    // Create the browser extension.
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
180
    m_browserExtension = new WebEngineBrowserExtension(this, cachedHistory);
181 182 183 184

    // Add status bar extension...
    m_statusBarExtension = new KParts::StatusBarExtension(this);

185
    // Add a web history interface for storing visited links.
186 187
//    if (!QWebEngineHistoryInterface::defaultInterface())
//        QWebHistoryInterface::setDefaultInterface(new WebHistoryInterface(this));
188

189
    // Add text and html extensions...
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
190 191 192
    new WebEngineTextExtension(this);
    new WebEngineHtmlExtension(this);
    new WebEngineScriptableExtension(this);
193

194 195 196 197

    // Layout the GUI...
    QVBoxLayout* l = new QVBoxLayout(mainWidget);
    l->setContentsMargins(0, 0, 0, 0);
198
    l->setSpacing(0);
199 200 201 202 203
    l->addWidget(m_webView);

    // Set the part's widget
    setWidget(mainWidget);

Yuri Chornoivan's avatar
Yuri Chornoivan committed
204
    // Set the web view as the focus object
205 206 207
    mainWidget->setFocusProxy(m_webView);

    // Connect the signals from the webview
Laurent Montel's avatar
Laurent Montel committed
208 209 210 211
    connect(m_webView, &QWebEngineView::titleChanged,
            this, &Part::setWindowCaption);
    connect(m_webView, &QWebEngineView::urlChanged,
            this, &WebEnginePart::slotUrlChanged);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
212 213 214 215
//    connect(m_webView, SIGNAL(linkMiddleOrCtrlClicked(QUrl)),
//            this, SLOT(slotLinkMiddleOrCtrlClicked(QUrl)));
//    connect(m_webView, SIGNAL(selectionClipboardUrlPasted(QUrl,QString)),
//            this, SLOT(slotSelectionClipboardUrlPasted(QUrl,QString)));
Laurent Montel's avatar
Laurent Montel committed
216 217
    connect(m_webView, &QWebEngineView::loadFinished,
            this, &WebEnginePart::slotLoadFinished);
218 219

    // Connect the signals from the page...
220
    connectWebEnginePageSignals(page());
221 222 223

    // Init the QAction we are going to use...
    initActions();
224 225 226

    // Load plugins once we are fully ready
    loadPlugins();
227
    setWallet(page()->wallet());
228 229
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
230
WebEnginePart::~WebEnginePart()
231 232 233
{
}

234
WebEnginePage* WebEnginePart::page()
235
{
236
    if (m_webView)
237
        return qobject_cast<WebEnginePage*>(m_webView->page());
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
238
    return nullptr;
239 240
}

241
const WebEnginePage* WebEnginePart::page() const
242 243
{
    if (m_webView)
244
        return qobject_cast<const WebEnginePage*>(m_webView->page());
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
245
    return nullptr;
246 247
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
248
void WebEnginePart::initActions()
249
{
250 251
    KStandardAction::create(KStandardAction::SaveAs, m_browserExtension, &WebEngineBrowserExtension::slotSaveDocument,
                            actionCollection());
252

Daniel Grosz's avatar
Daniel Grosz committed
253
    QAction* action = new QAction(i18n("Save &Frame As..."), this);
254
    actionCollection()->addAction(QStringLiteral("saveFrame"), action);
Laurent Montel's avatar
Laurent Montel committed
255
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotSaveFrame);
256

257 258
    action = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18n("Print Preview"), this);
    actionCollection()->addAction(QStringLiteral("printPreview"), action);
Laurent Montel's avatar
Laurent Montel committed
259
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotPrintPreview);
260

261 262 263
    action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18nc("zoom in action", "Zoom In"), this);
    actionCollection()->addAction(QStringLiteral("zoomIn"), action);
    actionCollection()->setDefaultShortcuts(action, QList<QKeySequence> () << QKeySequence(QStringLiteral("CTRL++")) << QKeySequence(QStringLiteral("CTRL+=")));
Laurent Montel's avatar
Laurent Montel committed
264
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomIn);
265

266 267 268
    action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18nc("zoom out action", "Zoom Out"), this);
    actionCollection()->addAction(QStringLiteral("zoomOut"), action);
    actionCollection()->setDefaultShortcuts(action, QList<QKeySequence> () << QKeySequence(QStringLiteral("CTRL+-")) << QKeySequence(QStringLiteral("CTRL+_")));
Laurent Montel's avatar
Laurent Montel committed
269
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomOut);
270

271 272 273
    action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18nc("reset zoom action", "Actual Size"), this);
    actionCollection()->addAction(QStringLiteral("zoomNormal"), action);
    actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("CTRL+0")));
Laurent Montel's avatar
Laurent Montel committed
274
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomNormal);
275

Daniel Grosz's avatar
Daniel Grosz committed
276
    action = new QAction(i18n("Zoom Text Only"), this);
277
    action->setCheckable(true);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
278
    KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings");
279 280
    bool zoomTextOnly = cgHtml.readEntry("ZoomTextOnly", false);
    action->setChecked(zoomTextOnly);
281
    actionCollection()->addAction(QStringLiteral("zoomTextOnly"), action);
Laurent Montel's avatar
Laurent Montel committed
282
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::toogleZoomTextOnly);
283

Daniel Grosz's avatar
Daniel Grosz committed
284
    action = new QAction(i18n("Zoom To DPI"), this);
285 286 287
    action->setCheckable(true);
    bool zoomToDPI = cgHtml.readEntry("ZoomToDPI", false);
    action->setChecked(zoomToDPI);
288
    actionCollection()->addAction(QStringLiteral("zoomToDPI"), action);
Laurent Montel's avatar
Laurent Montel committed
289
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::toogleZoomToDPI);
290

291 292 293

    action = KStandardAction::create(KStandardAction::SelectAll, m_browserExtension, &WebEngineBrowserExtension::slotSelectAll,
                                     actionCollection());
294
    action->setShortcutContext(Qt::WidgetShortcut);
295
    m_webView->addAction(action);
296

297 298
    KCodecAction *codecAction = new KCodecAction( QIcon::fromTheme(QStringLiteral("character-set")), i18n( "Set &Encoding" ), this, true );
    actionCollection()->addAction( QStringLiteral("setEncoding"), codecAction );
299
    connect(codecAction, QOverload<QTextCodec *>::of(&KCodecAction::triggered), this, &WebEnginePart::slotSetTextEncoding);
300

Daniel Grosz's avatar
Daniel Grosz committed
301
    action = new QAction(i18n("View Do&cument Source"), this);
302
    actionCollection()->addAction(QStringLiteral("viewDocumentSource"), action);
303
    actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_U));
Laurent Montel's avatar
Laurent Montel committed
304
    connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotViewDocumentSource);
305

Daniel Grosz's avatar
Daniel Grosz committed
306
    action = new QAction(i18nc("Secure Sockets Layer", "SSL"), this);
307
    actionCollection()->addAction(QStringLiteral("security"), action);
Laurent Montel's avatar
Laurent Montel committed
308
    connect(action, &QAction::triggered, this, &WebEnginePart::slotShowSecurity);
309

310 311
    action = KStandardAction::create(KStandardAction::Find, this,
                                     &WebEnginePart::slotShowSearchBar, actionCollection());
312 313 314 315
    action->setWhatsThis(i18nc("find action \"whats this\" text", "<h3>Find text</h3>"
                              "Shows a dialog that allows you to find text on the displayed page."));
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
316
void WebEnginePart::updateActions()
317
{
318 319
    m_browserExtension->updateActions();

320 321
    QAction* action = actionCollection()->action(QL1S("saveDocument"));
    if (action) {
Daniel Grosz's avatar
Daniel Grosz committed
322
        const QString protocol (url().scheme());
323 324 325
        action->setEnabled(protocol != QL1S("about") && protocol != QL1S("error"));
    }

326
    action = actionCollection()->action(QL1S("printPreview"));
327
    if (action) {
328
        action->setEnabled(m_browserExtension->isActionEnabled("print"));
329 330 331 332
    }

}

333
void WebEnginePart::connectWebEnginePageSignals(WebEnginePage* page)
334 335 336 337
{
    if (!page)
        return;

338 339 340
    connect(page, &QWebEnginePage::loadStarted, this, &WebEnginePart::slotLoadStarted);
    connect(page, &WebEnginePage::loadAborted, this, &WebEnginePart::slotLoadAborted);
    connect(page, &QWebEnginePage::linkHovered, this, &WebEnginePart::slotLinkHovered);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
341 342 343 344 345 346
//    connect(page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)),
//            this, SLOT(slotSaveFrameState(QWebFrame*,QWebHistoryItem*)));
//    connect(page, SIGNAL(restoreFrameStateRequested(QWebFrame*)),
//            this, SLOT(slotRestoreFrameState(QWebFrame*)));
//    connect(page, SIGNAL(statusBarMessage(QString)),
//            this, SLOT(slotSetStatusBarText(QString)));
347
    connect(page, &QWebEnginePage::windowCloseRequested, this, &WebEnginePart::slotWindowCloseRequested);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
348 349 350 351
//    connect(page, SIGNAL(printRequested(QWebFrame*)),
//            m_browserExtension, SLOT(slotPrintRequested(QWebFrame*)));
 //   connect(page, SIGNAL(frameCreated(QWebFrame*)),
 //           this, SLOT(slotFrameCreated(QWebFrame*)));
352

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
353 354
//    connect(m_webView, SIGNAL(linkShiftClicked(QUrl)),
//            page, SLOT(downloadUrl(QUrl)));
355

356 357
    connect(page, &QWebEnginePage::loadProgress, m_browserExtension, &KParts::BrowserExtension::loadingProgress);
    connect(page, &QWebEnginePage::selectionChanged, m_browserExtension, &WebEngineBrowserExtension::updateEditActions);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
358 359
//    connect(m_browserExtension, SIGNAL(saveUrl(QUrl)),
//            page, SLOT(downloadUrl(QUrl)));
360

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
361
    connect(page, &QWebEnginePage::iconUrlChanged, [page, this](const QUrl& url) {
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
362
        if (WebEngineSettings::self()->favIconsEnabled()
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
363
            && !page->profile()->isOffTheRecord()){
364
                emit m_browserExtension->setIconUrl(url);
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
365 366
        }
    });
367
}
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
368

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
void WebEnginePart::setWallet(WebEngineWallet* wallet)
{
    if(m_wallet){
        disconnect(m_wallet, &WebEngineWallet::saveFormDataRequested,
                this, &WebEnginePart::slotSaveFormDataRequested);
        disconnect(m_wallet, &WebEngineWallet::fillFormRequestCompleted,
                this, &WebEnginePart::slotFillFormRequestCompleted);
        disconnect(m_wallet, &WebEngineWallet::walletClosed, this, &WebEnginePart::slotWalletClosed);
    }
    m_wallet = wallet;
    if (m_wallet) {
        connect(m_wallet, &WebEngineWallet::saveFormDataRequested,
                this, &WebEnginePart::slotSaveFormDataRequested);
        connect(m_wallet, &WebEngineWallet::fillFormRequestCompleted,
                this, &WebEnginePart::slotFillFormRequestCompleted);
        connect(m_wallet, &WebEngineWallet::walletClosed, this, &WebEnginePart::slotWalletClosed);
385 386 387
    }
}

388 389 390 391 392
void WebEnginePart::attemptInstallKIOSchemeHandler(const QUrl& url)
{
     if (KProtocolManager::defaultMimetype(url) == "text/html") { // man:, info:, etc.
        QWebEngineProfile *prof = QWebEngineProfile::defaultProfile();
        QByteArray scheme = url.scheme().toUtf8();
393 394
        //Qt complains about installing a scheme handler overriding the internal "about" scheme
        if (scheme != "about" && !prof->urlSchemeHandler(scheme)) {
395
            prof->installUrlSchemeHandler(scheme, new WebEnginePartKIOHandler(prof));
396 397 398 399 400
        }
    }

}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
401
bool WebEnginePart::openUrl(const QUrl &_u)
402
{
Daniel Grosz's avatar
Daniel Grosz committed
403
    QUrl u (_u);
404

405 406 407 408
    // Ignore empty requests...
    if (u.isEmpty())
        return false;

409 410 411 412
    // If the URL given is a supported local protocol, e.g. "bookmark" but lacks
    // a path component, we set the path to "/" here so that the security context
    // will properly allow access to local resources.
    if (u.host().isEmpty() && u.path().isEmpty()
Daniel Grosz's avatar
Daniel Grosz committed
413
        && KProtocolInfo::protocolClass(u.scheme()) == QL1S(":local")) {
414 415 416
        u.setPath(QL1S("/"));
    }

417 418
    // Do not emit update history when url is typed in since the host
    // should handle that automatically itself.
419
    m_emitOpenUrlNotify = false;
420

421
    // Pointer to the page object...
422
    WebEnginePage* p = page();
423 424
    Q_ASSERT(p);

425
    KParts::BrowserArguments bargs (m_browserExtension->browserArguments());
426 427
    KParts::OpenUrlArguments args (arguments());

428
    if (!Utils::isBlankUrl(u)) {
429 430 431 432 433
        // Get the SSL information sent, if any...
        if (args.metaData().contains(QL1S("ssl_in_use"))) {
            WebSslInfo sslInfo;
            sslInfo.restoreFrom(KIO::MetaData(args.metaData()).toVariant());
            sslInfo.setUrl(u);
434
            p->setSslInfo(sslInfo);
435
        }
436
    }
437

438
    attemptInstallKIOSchemeHandler(u);
439

440 441
    // Set URL in KParts before emitting started; konq plugins rely on that.
    setUrl(u);
442
    m_doLoadFinishedActions = true;
443
    page()->setLoadUrlCalledByPart(u);
444
    m_webView->loadUrl(u, args, bargs);
445 446 447
    return true;
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
448
bool WebEnginePart::closeUrl()
449
{
450
    m_webView->triggerPageAction(QWebEnginePage::Stop);
451
    m_webView->stop();
452 453 454
    return true;
}

455
QWebEngineView* WebEnginePart::view() const
456
{
457
    return m_webView;
458 459
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
460
bool WebEnginePart::isModified() const
461
{
462 463
    //return m_webView->isModified();
    return false;
464 465
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
466
void WebEnginePart::guiActivateEvent(KParts::GUIActivateEvent *event)
467
{
468 469 470
    if (event && event->activated() && m_webView) {
        emit setWindowCaption(m_webView->title());
    }
471 472
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
473
bool WebEnginePart::openFile()
474 475 476 477
{
    // never reached
    return false;
}
478 479 480 481


/// slots...

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
482
void WebEnginePart::slotLoadStarted()
483
{
484
    if(!Utils::isBlankUrl(url()) && url() != QUrl("konq:konqueror"))
485
    {
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
486
        emit started(nullptr);
487
    }
488
    updateActions();
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

    // If "NoEmitOpenUrlNotification" property is set to true, do not
    // emit the open url notification. Property is set by this part's
    // extension to prevent openUrl notification being sent when
    // handling history navigation requests (back/forward).
    const bool doNotEmitOpenUrl = property("NoEmitOpenUrlNotification").toBool();
    if (doNotEmitOpenUrl) {
        setProperty("NoEmitOpenUrlNotification", QVariant());
    } else {
        if (m_emitOpenUrlNotify) {
            emit m_browserExtension->openUrlNotify();
        }
    }
    // Unless we go via openUrl again, the next time we are here we emit (e.g. after clicking on a link)
    m_emitOpenUrlNotify = true;
504 505
}

506
void WebEnginePart::slotLoadFinished (bool ok)
507
{
508
    if (!ok || !m_doLoadFinishedActions)
509
        return;
510

511
    slotWalletClosed();
512 513
    m_doLoadFinishedActions = false;

514 515 516 517 518 519 520 521 522 523 524 525 526
    // If the document contains no <title> tag, then set it to the current url.
    if (m_webView->title().trimmed().isEmpty()) {
        // If the document title is empty, then set it to the current url
        const QUrl url (m_webView->url());
        const QString caption (url.toString((QUrl::RemoveQuery|QUrl::RemoveFragment)));
        emit setWindowCaption(caption);

        // The urlChanged signal is emitted if and only if the main frame
        // receives the title of the page so we manually invoke the slot as a
        // work around here for pages that do not contain it, such as text
        // documents...
        slotUrlChanged(url);
    }
527
    if (!Utils::isBlankUrl(url())) {
528
        m_hasCachedFormData = false;
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
529
        if (WebEngineSettings::self()->isNonPasswordStorableSite(url().host())) {
530
            addWalletStatusBarIcon();
531
        }
532
        else {
533
// Attempt to fill the web form...
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
534
            WebEngineWallet *wallet = page() ? page()->wallet() : nullptr;
535 536 537
            if (wallet){
                wallet->fillFormData(page());
            }
538 539
        }
    }
540

541
    bool pending = false;
542 543 544 545
       // QWebFrame* frame = (page() ? page()->currentFrame() : 0);
       // if (ok &&
       //     frame == page()->mainFrame() &&
       //     !frame->findFirstElement(QL1S("head>meta[http-equiv=refresh]")).isNull()) {
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
546
       //     if (WebEngineSettings::self()->autoPageRefresh()) {
547 548 549 550 551
       //         pending = true;
       //     } else {
       //         frame->page()->triggerAction(QWebEnginePage::Stop);
       //     }
       // }
552
    emit completed ((ok && pending));
553 554

    updateActions();
555 556
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
557
void WebEnginePart::slotLoadAborted(const QUrl & url)
558 559
{
    closeUrl();
560
    m_doLoadFinishedActions = false;
561
    if (url.isValid())
562
        emit m_browserExtension->openUrlRequest(url);
563
    else
564
        setUrl(m_webView->url());
565 566
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
567
void WebEnginePart::slotUrlChanged(const QUrl& url)
568
{
569 570 571 572 573
    // Ignore if empty
    if (url.isEmpty())
        return;

    // Ignore if error url
574
    if (url.scheme() == QL1S("error"))
575 576
        return;

Daniel Grosz's avatar
Daniel Grosz committed
577
    const QUrl u (url);
578

579 580 581
    // Ignore if url has not changed!
    if (this->url() == u)
      return;
582

583
    m_doLoadFinishedActions = true;
584 585 586
    setUrl(u);

    // Do not update the location bar with about:blank
587
    if (!Utils::isBlankUrl(url)) {
588
        //qCDebug(WEBENGINEPART_LOG) << "Setting location bar to" << u.prettyUrl() << "current URL:" << this->url();
Daniel Grosz's avatar
Daniel Grosz committed
589
        emit m_browserExtension->setLocationBarUrl(u.toDisplayString());
590
    }
591 592
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
593
void WebEnginePart::slotShowSecurity()
594
{
595 596
    if (!page())
        return;
597 598

    const WebSslInfo& sslInfo = page()->sslInfo();
599
    if (!sslInfo.isValid()) {
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
600
        KMessageBox::information(nullptr, i18n("The SSL information for this site "
601 602 603
                                    "appears to be corrupt."),
                            i18nc("Secure Sockets Layer", "SSL"));
        return;
604
    }
605 606 607 608 609 610 611 612 613

    KSslInfoDialog *dlg = new KSslInfoDialog (widget());
    dlg->setSslInfo(sslInfo.certificateChain(),
                    sslInfo.peerAddress().toString(),
                    url().host(),
                    sslInfo.protocol(),
                    sslInfo.ciphers(),
                    sslInfo.usedChiperBits(),
                    sslInfo.supportedChiperBits(),
614
                    KSslInfoDialog::certificateErrorsFromString(sslInfo.certificateErrors()));
615 616

    dlg->open();
617 618
}

619
#if 0
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
620
void WebEnginePart::slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item)
621
{
622
    if (!frame || !item) {
623
        return;
624
    }
625

626 627
    // Handle actions that apply only to the mainframe...
    if (frame == view()->page()->mainFrame()) {
628
    }
629

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
630
    // For some reason, QtWebEngine PORTING_TODO does not restore scroll position when
631 632 633 634 635
    // QWebHistory is restored from persistent storage. Therefore, we
    // preserve that information and restore it as needed. See
    // slotRestoreFrameState.
    const QPoint scrollPos (frame->scrollPosition());
    if (!scrollPos.isNull()) {
636
        // qCDebug(WEBENGINEPART_LOG) << "Saving scroll position:" << scrollPos;
637 638
        item->setUserData(scrollPos);
    }
639
}
640
#endif
641

642
#if 0
Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
643
void WebEnginePart::slotRestoreFrameState(QWebFrame *frame)
644
{
645
    QWebEnginePage* page = (frame ? frame->page() : 0);
646
    QWebHistory* history = (page ? page->history() : 0);
647

648 649
    // No history item...
    if (!history || history->count() < 1)
650 651
        return;

652
    QWebHistoryItem currentHistoryItem (history->currentItem());
653

654 655 656 657 658 659 660 661
    // Update the scroll position if needed. See comment in slotSaveFrameState above.
    if (frame->baseUrl().resolved(frame->url()) == currentHistoryItem.url()) {
        const QPoint currentPos (frame->scrollPosition());
        const QPoint desiredPos (currentHistoryItem.userData().toPoint());
        if (currentPos.isNull() && !desiredPos.isNull()) {
            frame->setScrollPosition(desiredPos);
        }
    }
662
}
663
#endif
664

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
665
void WebEnginePart::slotLinkHovered(const QString& _link)
666 667 668
{
    QString message;

669
    if (_link.isEmpty()) {
670 671 672
        message = QL1S("");
        emit m_browserExtension->mouseOverInfo(KFileItem());
    } else {
673
        QUrl linkUrl (_link);
674 675
        const QString scheme = linkUrl.scheme();

676 677 678 679
        // Protect the user against URL spoofing!
        linkUrl.setUserName(QString());
        const QString link (linkUrl.toString());

680 681 682 683 684 685 686 687
        if (QString::compare(scheme, QL1S("mailto"), Qt::CaseInsensitive) == 0) {
            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: ");

            // Workaround: for QUrl's parsing deficiencies of "mailto:foo@bar.com".
            if (!linkUrl.hasQuery())
              linkUrl = QUrl(scheme + '?' + linkUrl.path());

            QMap<QString, QStringList> fields;
688 689
            QUrlQuery query(linkUrl);
            QList<QPair<QString, QString> > queryItems = query.queryItems();
Dawit Alemayehu's avatar
Dawit Alemayehu committed
690
            const int count = queryItems.count();
691

Dawit Alemayehu's avatar
Dawit Alemayehu committed
692 693
            for(int i = 0; i < count; ++i) {
                const QPair<QString, QString> queryItem (queryItems.at(i));
694
                //qCDebug(WEBENGINEPART_LOG) << "query: " << queryItem.first << queryItem.second;
695
                if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty())
696
                    fields[QStringLiteral("to")] << queryItem.first;
697
                if (QString::compare(queryItem.first, QL1S("to"), Qt::CaseInsensitive) == 0)
698
                    fields[QStringLiteral("to")] << queryItem.second;
699
                if (QString::compare(queryItem.first, QL1S("cc"), Qt::CaseInsensitive) == 0)
700
                    fields[QStringLiteral("cc")] << queryItem.second;
701
                if (QString::compare(queryItem.first, QL1S("bcc"), Qt::CaseInsensitive) == 0)
702
                    fields[QStringLiteral("bcc")] << queryItem.second;
703
                if (QString::compare(queryItem.first, QL1S("subject"), Qt::CaseInsensitive) == 0)
704
                    fields[QStringLiteral("subject")] << queryItem.second;
705 706 707 708 709 710 711 712 713 714
            }

            if (fields.contains(QL1S("to")))
                message += fields.value(QL1S("to")).join(QL1S(", "));
            if (fields.contains(QL1S("cc")))
                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(", "));
            if (fields.contains(QL1S("bcc")))
                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(", "));
            if (fields.contains(QL1S("subject")))
                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(" "));
715
        } else if (scheme == QL1S("javascript")) {
716
            message = KStringHandler::rsqueeze(link, 150);
717 718
            if (link.startsWith(QL1S("javascript:window.open")))
                message += i18n(" (In new window)");
719 720
        } else {
            message = link;
721
#if 0
722 723 724
            QWebFrame* frame = page() ? page()->currentFrame() : 0;
            if (frame) {
                QWebHitTestResult result = frame->hitTestContent(page()->view()->mapFromGlobal(QCursor::pos()));
725 726
                QWebFrame* target = result.linkTargetFrame();
                if (frame->parentFrame() && target == frame->parentFrame()) {
727
                    message += i18n(" (In parent frame)");
728 729
                } else if (!target || target != frame) {
                    message += i18n(" (In new window)");
730 731
                }
            }
732
#endif
733 734 735 736 737 738 739 740
            KFileItem item (linkUrl, QString(), KFileItem::Unknown);
            emit m_browserExtension->mouseOverInfo(item);
        }
    }

    emit setStatusBarText(message);
}

Sune Stolborg Vuorela's avatar
Sune Stolborg Vuorela committed
741
void WebEnginePart::slotSearchForText(const QString &text, bool backward)
742
{
743
    QWebEnginePage::FindFlags flags; // = QWebEnginePage::FindWrapsAroundDocument;
Dawit Alemayehu's avatar