articleviewerwebengine.cpp 19.5 KB
Newer Older
Laurent Montel's avatar
Laurent Montel committed
1
/*
Laurent Montel's avatar
Laurent Montel committed
2
   SPDX-FileCopyrightText: 2015-2021 Laurent Montel <montel@kde.org>
Laurent Montel's avatar
Laurent Montel committed
3

4
   SPDX-License-Identifier: GPL-2.0-or-later
Laurent Montel's avatar
Laurent Montel committed
5
6
7
*/

#include "articleviewerwebengine.h"
Laurent Montel's avatar
Laurent Montel committed
8
9
#include "actionmanager.h"
#include "actions/actions.h"
Laurent Montel's avatar
Laurent Montel committed
10
11
12
#include "akregator_debug.h"
#include "akregatorconfig.h"
#include "articleviewerwebenginepage.h"
Laurent Montel's avatar
Laurent Montel committed
13
#include "urlhandler/webengine/urlhandlerwebengine.h"
Laurent Montel's avatar
Laurent Montel committed
14
15
#include "webengine/urlhandlerwebenginemanager.h"
#include <KPIMTextEdit/TextToSpeech>
Laurent Montel's avatar
Laurent Montel committed
16
#include <WebEngineViewer/InterceptorManager>
17
#include <WebEngineViewer/WebEngineAccessKey>
18
#include <WebEngineViewer/WebEngineManageScript>
Laurent Montel's avatar
Laurent Montel committed
19
#include <WebEngineViewer/ZoomActionMenu>
Laurent Montel's avatar
Laurent Montel committed
20

21
#include <GrantleeTheme/GrantleeThemeManager>
Laurent Montel's avatar
Laurent Montel committed
22
#include <KAboutData>
Laurent Montel's avatar
Laurent Montel committed
23
#include <KActionCollection>
Laurent Montel's avatar
Laurent Montel committed
24
#include <KGuiItem>
Laurent Montel's avatar
Laurent Montel committed
25
26
27
28
#include <KIO/FileCopyJob>
#include <KJobUiDelegate>
#include <KJobWidgets>
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
29
30
31
#include <KMessageBox>
#include <QApplication>
#include <QClipboard>
Laurent Montel's avatar
Laurent Montel committed
32
#include <QFileDialog>
Laurent Montel's avatar
Laurent Montel committed
33
#include <QMenu>
Laurent Montel's avatar
Laurent Montel committed
34
35
#include <QMouseEvent>
#include <QPrinter>
Laurent Montel's avatar
Laurent Montel committed
36
#include <QWebEngineProfile>
Andras Mantia's avatar
Andras Mantia committed
37
#include <QWebEngineUrlRequestInterceptor>
Laurent Montel's avatar
Laurent Montel committed
38
#include <viewerplugintoolmanager.h>
39

Laurent Montel's avatar
Laurent Montel committed
40
#include <WebEngineViewer/BlockTrackingUrlInterceptor>
41
#include <WebEngineViewer/LoadExternalReferencesUrlInterceptor>
Laurent Montel's avatar
Laurent Montel committed
42
#include <WebEngineViewer/WebEngineScript>
Laurent Montel's avatar
Laurent Montel committed
43
44
#include <WebEngineViewer/WebHitTest>
#include <WebEngineViewer/WebHitTestResult>
Laurent Montel's avatar
Laurent Montel committed
45

46
47
#include <WebEngineViewer/LocalDataBaseManager>

Laurent Montel's avatar
Laurent Montel committed
48
#include <KIO/KUriFilterSearchProviderActions>
Laurent Montel's avatar
Laurent Montel committed
49
50
51

using namespace Akregator;

Andras Mantia's avatar
Andras Mantia committed
52
53
54
55
56
class AkregatorRequestInterceptor : public QWebEngineUrlRequestInterceptor
{
    Q_OBJECT

public:
Laurent Montel's avatar
Laurent Montel committed
57
58
    explicit AkregatorRequestInterceptor(QObject *parent = nullptr)
        : QWebEngineUrlRequestInterceptor(parent)
Laurent Montel's avatar
Laurent Montel committed
59
    {
Andras Mantia's avatar
Andras Mantia committed
60
61
    }

Laurent Montel's avatar
Laurent Montel committed
62
63
    void interceptRequest(QWebEngineUrlRequestInfo &info) override
    {
Laurent Montel's avatar
Laurent Montel committed
64
        Q_UNUSED(info)
Andras Mantia's avatar
Andras Mantia committed
65
66
    }
};
Laurent Montel's avatar
Laurent Montel committed
67
// #define HAVE_BLOCK_SUPPORT 1
Laurent Montel's avatar
Laurent Montel committed
68
ArticleViewerWebEngine::ArticleViewerWebEngine(KActionCollection *ac, QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
69
70
    : WebEngineViewer::WebEngineView(parent)
    , mActionCollection(ac)
Laurent Montel's avatar
Laurent Montel committed
71
{
72
#ifndef HAVE_BLOCK_SUPPORT
Wolfgang Bauer's avatar
Wolfgang Bauer committed
73
    mNetworkAccessManager = new WebEngineViewer::InterceptorManager(this, ac, this);
74
#endif
75
76
    mPageEngine = new ArticleViewerWebEnginePage(this);
    QWebEngineProfile *profile = mPageEngine->profile();
Laurent Montel's avatar
Laurent Montel committed
77
    profile->setPersistentCookiesPolicy(QWebEngineProfile::ForcePersistentCookies);
78
#ifndef HAVE_BLOCK_SUPPORT
Andras Mantia's avatar
Andras Mantia committed
79
80
    // Needed to workaround crash in webengine, see https://bugreports.qt.io/browse/QTBUG-72260
    auto webEngineUrlInterceptor = new AkregatorRequestInterceptor();
81
    connect(profile, &QObject::destroyed, webEngineUrlInterceptor, &AkregatorRequestInterceptor::deleteLater);
82
    profile->setUrlRequestInterceptor(webEngineUrlInterceptor);
83
#endif
Laurent Montel's avatar
Laurent Montel committed
84
    setPage(mPageEngine);
85

86
#ifdef HAVE_BLOCK_SUPPORT
87
    mNetworkAccessManager = new WebEngineViewer::InterceptorManager(this, ac, this);
88
    mExternalReference = new WebEngineViewer::LoadExternalReferencesUrlInterceptor(this);
89
    // connect(externalReference, &MessageViewer::LoadExternalReferencesUrlInterceptor::urlBlocked, this, &MailWebEngineView::urlBlocked);
90
    mNetworkAccessManager->addInterceptor(mExternalReference);
Laurent Montel's avatar
Laurent Montel committed
91
    auto *blockTracking = new WebEngineViewer::BlockTrackingUrlInterceptor(this);
Laurent Montel's avatar
Laurent Montel committed
92
    connect(blockTracking, &WebEngineViewer::BlockTrackingUrlInterceptor::trackingFound, this, &ArticleViewerWebEngine::trackingFound);
93
    mNetworkAccessManager->addInterceptor(blockTracking);
94
#endif
Laurent Montel's avatar
Laurent Montel committed
95
96
    connect(this, &ArticleViewerWebEngine::showContextMenu, this, &ArticleViewerWebEngine::slotShowContextMenu);

Laurent Montel's avatar
Laurent Montel committed
97
    setFocusPolicy(Qt::WheelFocus);
Laurent Montel's avatar
Laurent Montel committed
98
    connect(mPageEngine, &ArticleViewerWebEnginePage::urlClicked, this, &ArticleViewerWebEngine::slotLinkClicked);
Laurent Montel's avatar
Laurent Montel committed
99

100
    mWebEngineViewAccessKey = new WebEngineViewer::WebEngineAccessKey(this, this);
Laurent Montel's avatar
Laurent Montel committed
101
    mWebEngineViewAccessKey->setActionCollection(mActionCollection);
102
    connect(mWebEngineViewAccessKey, &WebEngineViewer::WebEngineAccessKey::openUrl, this, &ArticleViewerWebEngine::slotLinkClicked);
Laurent Montel's avatar
Laurent Montel committed
103
104
105
106
107

    connect(this, &ArticleViewerWebEngine::loadStarted, this, &ArticleViewerWebEngine::slotLoadStarted);
    connect(this, &ArticleViewerWebEngine::loadFinished, this, &ArticleViewerWebEngine::slotLoadFinished);
    connect(page(), &QWebEnginePage::linkHovered, this, &ArticleViewerWebEngine::slotLinkHovered);

Laurent Montel's avatar
Laurent Montel committed
108
    setContextMenuPolicy(Qt::DefaultContextMenu);
Laurent Montel's avatar
Laurent Montel committed
109
110
111
    mWebShortcutMenuManager = new KIO::KUriFilterSearchProviderActions(this);
    mShareServiceManager = new PimCommon::ShareServiceUrlManager(this);
    connect(mShareServiceManager, &PimCommon::ShareServiceUrlManager::serviceUrlSelected, this, &ArticleViewerWebEngine::slotServiceUrlSelected);
Laurent Montel's avatar
Laurent Montel committed
112
113
    connect(page(), &QWebEnginePage::audioMutedChanged, this, &ArticleViewerWebEngine::slotWebPageMutedOrAudibleChanged);
    connect(page(), &QWebEnginePage::recentlyAudibleChanged, this, &ArticleViewerWebEngine::slotWebPageMutedOrAudibleChanged);
114

Laurent Montel's avatar
Laurent Montel committed
115
    connect(phishingDatabase(), &WebEngineViewer::LocalDataBaseManager::checkUrlFinished, this, &ArticleViewerWebEngine::slotCheckedUrlFinished);
Laurent Montel's avatar
Laurent Montel committed
116
117
118
119
120
}

ArticleViewerWebEngine::~ArticleViewerWebEngine()
{
}
Laurent Montel's avatar
Laurent Montel committed
121

Laurent Montel's avatar
Laurent Montel committed
122
123
void ArticleViewerWebEngine::execPrintPreviewPage(QPrinter *printer, int timeout)
{
Laurent Montel's avatar
Laurent Montel committed
124
125
126
    if (!mPageEngine->execPrintPreviewPage(printer, timeout)) {
        qCWarning(AKREGATOR_LOG) << "Impossible to print page";
    }
Laurent Montel's avatar
Laurent Montel committed
127
128
}

129
130
131
132
133
void ArticleViewerWebEngine::slotWebPageMutedOrAudibleChanged()
{
    Q_EMIT webPageMutedOrAudibleChanged(page()->isAudioMuted(), page()->recentlyAudible());
}

Laurent Montel's avatar
Laurent Montel committed
134
135
136
137
138
139
140
141
142
143
144
145
QVariantHash ArticleViewerWebEngine::introductionData() const
{
    QVariantHash data;
    data[QStringLiteral("icon")] = QStringLiteral("akregator");
    data[QStringLiteral("name")] = i18n("Akregator");
    data[QStringLiteral("subtitle")] = i18n("Akregator is a KDE news feed reader.");
    data[QStringLiteral("version")] = KAboutData::applicationData().version();
    return data;
}

void ArticleViewerWebEngine::showAboutPage()
{
Laurent Montel's avatar
Laurent Montel committed
146
    paintAboutScreen(QStringLiteral(":/about/introduction_akregator.html"), introductionData());
Laurent Montel's avatar
Laurent Montel committed
147
148
149
150
}

void ArticleViewerWebEngine::paintAboutScreen(const QString &templateName, const QVariantHash &data)
{
Laurent Montel's avatar
Laurent Montel committed
151
    GrantleeTheme::ThemeManager manager(QStringLiteral("splashPage"), QStringLiteral("splash.theme"), nullptr, QStringLiteral("messageviewer/about/"));
Laurent Montel's avatar
Laurent Montel committed
152
    GrantleeTheme::Theme theme = manager.theme(QStringLiteral("default"));
Laurent Montel's avatar
Laurent Montel committed
153
    if (theme.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
154
        setHtml(theme.render(templateName, data, QByteArrayLiteral("akregator")), QUrl::fromLocalFile(theme.absolutePath() + QLatin1Char('/')));
Laurent Montel's avatar
Laurent Montel committed
155
156
    } else {
        qCDebug(AKREGATOR_LOG) << "Theme error: failed to find splash theme";
Laurent Montel's avatar
Laurent Montel committed
157
158
159
    }
}

Laurent Montel's avatar
Laurent Montel committed
160
void ArticleViewerWebEngine::slotServiceUrlSelected(PimCommon::ShareServiceUrlManager::ServiceType type)
Laurent Montel's avatar
Laurent Montel committed
161
{
162
163
164
    if (mCurrentUrl.isEmpty()) {
        return;
    }
Laurent Montel's avatar
Laurent Montel committed
165
166
    const QUrl url = mShareServiceManager->generateServiceUrl(mCurrentUrl.url(), QString(), type);
    mShareServiceManager->openUrl(url);
Laurent Montel's avatar
Laurent Montel committed
167
168
}

Laurent Montel's avatar
Laurent Montel committed
169
void ArticleViewerWebEngine::slotSaveLinkAs()
Laurent Montel's avatar
Laurent Montel committed
170
{
171
172
173
174
    QUrl url(mCurrentUrl);
    if (url.fileName().isEmpty()) {
        url = url.adjusted(QUrl::StripTrailingSlash);
        url.setPath(url.path() + QLatin1String("/index.html"));
Laurent Montel's avatar
Laurent Montel committed
175
    }
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

    QFileDialog *dlg = new QFileDialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setAcceptMode(QFileDialog::AcceptSave);
    dlg->setWindowTitle(i18n("Save As"));
    dlg->setOption(QFileDialog::DontConfirmOverwrite, false);
    dlg->selectFile(url.fileName());
    dlg->show();
    connect(dlg, &QFileDialog::urlSelected, this, [this, url](const QUrl &destURL) {
        if (destURL.isValid()) {
            KIO::FileCopyJob *job = KIO::file_copy(url, destURL, -1, KIO::Overwrite);
            job->addMetaData(QStringLiteral("MaxCacheSize"), QStringLiteral("0")); // Don't store in http cache.
            job->addMetaData(QStringLiteral("cache"), QStringLiteral("cache")); // Use entry from cache if available.
            KJobWidgets::setWindow(job, this);
            job->uiDelegate()->setAutoErrorHandlingEnabled(true);
        }
    });
Laurent Montel's avatar
Laurent Montel committed
193
194
}

Laurent Montel's avatar
Laurent Montel committed
195
void ArticleViewerWebEngine::slotSaveImageOnDiskInFrame()
Laurent Montel's avatar
Laurent Montel committed
196
197
198
199
{
    slotSaveLinkAs();
}

Laurent Montel's avatar
Laurent Montel committed
200
void ArticleViewerWebEngine::slotCopyImageLocationInFrame()
Laurent Montel's avatar
Laurent Montel committed
201
202
203
204
{
    slotCopyLinkAddress();
}

Laurent Montel's avatar
Laurent Montel committed
205
206
207
208
209
void ArticleViewerWebEngine::slotMute(bool mute)
{
    page()->setAudioMuted(mute);
}

Laurent Montel's avatar
Laurent Montel committed
210
void ArticleViewerWebEngine::slotCopyLinkAddress()
Laurent Montel's avatar
Laurent Montel committed
211
212
213
214
215
216
217
218
219
220
221
222
{
    if (mCurrentUrl.isEmpty()) {
        return;
    }
    QClipboard *cb = QApplication::clipboard();
    cb->setText(mCurrentUrl.toString(), QClipboard::Clipboard);
    // don't set url to selection as it's a no-no according to a fd.o spec
    // which spec? Nobody seems to care (tested Firefox (3.5.10) Konqueror,and KMail (4.2.3)), so I re-enable the following line unless someone gives
    // a good reason to remove it again (bug 183022) --Frank
    cb->setText(mCurrentUrl.toString(), QClipboard::Selection);
}

Laurent Montel's avatar
Laurent Montel committed
223
224
225
226
227
void ArticleViewerWebEngine::contextMenuEvent(QContextMenuEvent *e)
{
    displayContextMenu(e->pos());
}

Laurent Montel's avatar
Laurent Montel committed
228
void ArticleViewerWebEngine::slotShowContextMenu(const QPoint &pos)
Laurent Montel's avatar
Laurent Montel committed
229
230
231
232
{
    displayContextMenu(pos);
}

Laurent Montel's avatar
Laurent Montel committed
233
void ArticleViewerWebEngine::slotCopy()
Laurent Montel's avatar
Laurent Montel committed
234
{
Laurent Montel's avatar
Laurent Montel committed
235
    triggerPageAction(QWebEnginePage::Copy);
Laurent Montel's avatar
Laurent Montel committed
236
237
}

Laurent Montel's avatar
Laurent Montel committed
238
void ArticleViewerWebEngine::slotLoadFinished()
Laurent Montel's avatar
Laurent Montel committed
239
{
240
    restoreCurrentPosition();
Laurent Montel's avatar
Laurent Montel committed
241
242
243
    unsetCursor();
}

Laurent Montel's avatar
Laurent Montel committed
244
void ArticleViewerWebEngine::slotLoadStarted()
Laurent Montel's avatar
Laurent Montel committed
245
{
Laurent Montel's avatar
Laurent Montel committed
246
    mWebEngineViewAccessKey->hideAccessKeys();
Laurent Montel's avatar
Laurent Montel committed
247
248
249
    setCursor(Qt::WaitCursor);
}

250
void ArticleViewerWebEngine::slotWebHitFinished(const WebEngineViewer::WebHitTestResult &result)
Laurent Montel's avatar
Laurent Montel committed
251
{
252
253
    mCurrentUrl = result.linkUrl();
    if (URLHandlerWebEngineManager::instance()->handleContextMenuRequest(mCurrentUrl, mapToGlobal(result.pos()), this)) {
Laurent Montel's avatar
Laurent Montel committed
254
255
256
257
        return;
    }

    QMenu popup(this);
Laurent Montel's avatar
Laurent Montel committed
258
259
    const bool noContentSelected = selectedText().isEmpty();
    if (noContentSelected) {
Laurent Montel's avatar
Laurent Montel committed
260
        if (!mCurrentUrl.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
261
262
            {
                QAction *act = createOpenLinkInNewTabAction(mCurrentUrl, &popup);
263
                connect(act, &QAction::triggered, this, &ArticleViewerWebEngine::slotOpenLinkInBackgroundTab);
Laurent Montel's avatar
Laurent Montel committed
264
265
266
267
268
269
270
                popup.addAction(act);
            }
            {
                QAction *act = createOpenLinkInExternalBrowserAction(mCurrentUrl, &popup);
                connect(act, &QAction::triggered, this, &ArticleViewerWebEngine::slotOpenLinkInBrowser);
                popup.addAction(act);
            }
Laurent Montel's avatar
Laurent Montel committed
271
272
273
274
            popup.addSeparator();
            popup.addAction(mActionCollection->action(QStringLiteral("savelinkas")));
            popup.addAction(mActionCollection->action(QStringLiteral("copylinkaddress")));
        }
275
        if (!result.imageUrl().isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
276
277
278
279
            popup.addSeparator();
            popup.addAction(mActionCollection->action(QStringLiteral("copy_image_location")));
            popup.addAction(mActionCollection->action(QStringLiteral("saveas_imageurl")));
        }
Laurent Montel's avatar
Laurent Montel committed
280
281
        popup.addSeparator();
        popup.addActions(viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedUrl));
Laurent Montel's avatar
Laurent Montel committed
282
283
284
        popup.addSeparator();
        popup.addAction(mShareServiceManager->menu());
    } else {
Laurent Montel's avatar
Laurent Montel committed
285
286
287
288
        popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_copy")));
        popup.addSeparator();
        mWebShortcutMenuManager->setSelectedText(page()->selectedText());
        mWebShortcutMenuManager->addWebShortcutsToMenu(&popup);
289
290
        popup.addSeparator();
        popup.addActions(viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection));
Laurent Montel's avatar
Laurent Montel committed
291
292
293
294
    }
    popup.addSeparator();
    popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_print")));
    popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_printpreview")));
Laurent Montel's avatar
Laurent Montel committed
295
    popup.addSeparator();
Laurent Montel's avatar
Laurent Montel committed
296
297
    popup.addAction(ActionManager::getInstance()->action(QStringLiteral("tab_mute")));
    popup.addAction(ActionManager::getInstance()->action(QStringLiteral("tab_unmute")));
Laurent Montel's avatar
Laurent Montel committed
298
299
300
301
302
303
    popup.addSeparator();
    popup.addAction(ActionManager::getInstance()->action(QStringLiteral("find_in_messages")));
    if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
        popup.addSeparator();
        popup.addAction(ActionManager::getInstance()->action(QStringLiteral("speak_text")));
    }
304
305
306
307
308
    popup.exec(mapToGlobal(result.pos()));
}

void ArticleViewerWebEngine::displayContextMenu(const QPoint &pos)
{
309
310
    WebEngineViewer::WebHitTest *webHit = mPageEngine->hitTestContent(pos);
    connect(webHit, &WebEngineViewer::WebHitTest::finished, this, &ArticleViewerWebEngine::slotWebHitFinished);
Laurent Montel's avatar
Laurent Montel committed
311
312
}

Laurent Montel's avatar
Laurent Montel committed
313
void ArticleViewerWebEngine::slotLinkHovered(const QString &link)
Laurent Montel's avatar
Laurent Montel committed
314
{
Laurent Montel's avatar
Laurent Montel committed
315
    QString msg = URLHandlerWebEngineManager::instance()->statusBarMessage(QUrl(link), this);
Laurent Montel's avatar
Laurent Montel committed
316
317
318
319
320
321
322
    if (msg.isEmpty()) {
        msg = link;
    }

    Q_EMIT showStatusBarMessage(msg);
}

Laurent Montel's avatar
Laurent Montel committed
323
void ArticleViewerWebEngine::forwardKeyReleaseEvent(QKeyEvent *e)
Laurent Montel's avatar
Laurent Montel committed
324
325
{
    if (Settings::self()->accessKeyEnabled()) {
Laurent Montel's avatar
Laurent Montel committed
326
        mWebEngineViewAccessKey->keyReleaseEvent(e);
Laurent Montel's avatar
Laurent Montel committed
327
328
329
    }
}

Laurent Montel's avatar
Laurent Montel committed
330
void ArticleViewerWebEngine::forwardKeyPressEvent(QKeyEvent *e)
Laurent Montel's avatar
Laurent Montel committed
331
332
333
{
    if (e && hasFocus()) {
        if (Settings::self()->accessKeyEnabled()) {
Laurent Montel's avatar
Laurent Montel committed
334
            mWebEngineViewAccessKey->keyPressEvent(e);
Laurent Montel's avatar
Laurent Montel committed
335
336
337
338
        }
    }
}

Laurent Montel's avatar
Laurent Montel committed
339
void ArticleViewerWebEngine::forwardWheelEvent(QWheelEvent *e)
Laurent Montel's avatar
Laurent Montel committed
340
341
{
    if (Settings::self()->accessKeyEnabled()) {
Laurent Montel's avatar
Laurent Montel committed
342
        mWebEngineViewAccessKey->wheelEvent(e);
Laurent Montel's avatar
Laurent Montel committed
343
    }
344
    if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
345
        const int numDegrees = e->angleDelta().y() / 8;
346
347
348
349
350
351
        const int numSteps = numDegrees / 15;
        const qreal factor = ActionManager::getInstance()->zoomActionMenu()->zoomFactor() + numSteps * 10;
        if (factor >= 10 && factor <= 300) {
            ActionManager::getInstance()->zoomActionMenu()->setZoomFactor(factor);
            ActionManager::getInstance()->zoomActionMenu()->setWebViewerZoomFactor(factor / 100.0);
        }
Laurent Montel's avatar
Laurent Montel committed
352
        e->accept();
353
    }
Laurent Montel's avatar
Laurent Montel committed
354
355
}

Laurent Montel's avatar
Laurent Montel committed
356
void ArticleViewerWebEngine::resizeEvent(QResizeEvent *e)
Laurent Montel's avatar
Laurent Montel committed
357
358
{
    if (Settings::self()->accessKeyEnabled()) {
Laurent Montel's avatar
Laurent Montel committed
359
        mWebEngineViewAccessKey->resizeEvent(e);
Laurent Montel's avatar
Laurent Montel committed
360
    }
Laurent Montel's avatar
Laurent Montel committed
361
    QWebEngineView::resizeEvent(e);
Laurent Montel's avatar
Laurent Montel committed
362
363
}

Laurent Montel's avatar
Laurent Montel committed
364
void ArticleViewerWebEngine::disableIntroduction()
Laurent Montel's avatar
Laurent Montel committed
365
366
367
368
369
{
    KGuiItem yesButton(KStandardGuiItem::yes());
    yesButton.setText(i18n("Disable"));
    KGuiItem noButton(KStandardGuiItem::no());
    noButton.setText(i18n("Keep Enabled"));
Laurent Montel's avatar
Laurent Montel committed
370
371
372
373
374
375
    if (KMessageBox::questionYesNo(this,
                                   i18n("Are you sure you want to disable this introduction page?"),
                                   i18n("Disable Introduction Page"),
                                   yesButton,
                                   noButton)
        == KMessageBox::Yes) {
Laurent Montel's avatar
Laurent Montel committed
376
377
378
379
380
        Settings::self()->setDisableIntroduction(true);
        Settings::self()->save();
    }
}

Laurent Montel's avatar
Laurent Montel committed
381
void ArticleViewerWebEngine::setArticleAction(ArticleViewerWebEngine::ArticleAction type, const QString &articleId, const QString &feed)
Laurent Montel's avatar
Laurent Montel committed
382
383
384
385
{
    Q_EMIT articleAction(type, articleId, feed);
}

386
387
void ArticleViewerWebEngine::restoreCurrentPosition()
{
388
    mPageEngine->runJavaScript(WebEngineViewer::WebEngineScript::scrollToRelativePosition(0), WebEngineViewer::WebEngineManageScript::scriptWordId());
389
390
}

Laurent Montel's avatar
Laurent Montel committed
391
void ArticleViewerWebEngine::forwardMouseReleaseEvent(QMouseEvent *event)
Laurent Montel's avatar
Laurent Montel committed
392
393
394
395
396
397
398
399
400
401
402
{
    if (event->button() & Qt::RightButton) {
        Q_EMIT showContextMenu(event->pos());
        mLastButtonClicked = RightButton;
    } else if (event->button() & Qt::MiddleButton) {
        mLastButtonClicked = MiddleButton;
    } else if (event->button() & Qt::LeftButton) {
        mLastButtonClicked = LeftButton;
    }
}

Laurent Montel's avatar
Laurent Montel committed
403
404
405
406
407
408
409
410
bool ArticleViewerWebEngine::urlIsAMalwareButContinue()
{
    if (KMessageBox::No == KMessageBox::warningYesNo(this, i18n("This web site is a malware, do you want to continue to show it?"), i18n("Malware"))) {
        return false;
    }
    return true;
}

411
void ArticleViewerWebEngine::slotCheckedUrlFinished(const QUrl &url, WebEngineViewer::CheckPhishingUrlUtil::UrlStatus status)
Laurent Montel's avatar
Laurent Montel committed
412
413
{
    switch (status) {
Laurent Montel's avatar
Laurent Montel committed
414
    case WebEngineViewer::CheckPhishingUrlUtil::BrokenNetwork:
Laurent Montel's avatar
Laurent Montel committed
415
416
        KMessageBox::error(this, i18n("The network is broken."), i18n("Check Phishing Url"));
        break;
Laurent Montel's avatar
Laurent Montel committed
417
    case WebEngineViewer::CheckPhishingUrlUtil::InvalidUrl:
Laurent Montel's avatar
Laurent Montel committed
418
419
        KMessageBox::error(this, i18n("The url %1 is not valid.", url.toString()), i18n("Check Phishing Url"));
        break;
Laurent Montel's avatar
Laurent Montel committed
420
    case WebEngineViewer::CheckPhishingUrlUtil::Ok:
Laurent Montel's avatar
Laurent Montel committed
421
        break;
Laurent Montel's avatar
Laurent Montel committed
422
    case WebEngineViewer::CheckPhishingUrlUtil::MalWare:
Laurent Montel's avatar
Laurent Montel committed
423
        if (!urlIsAMalwareButContinue()) {
Laurent Montel's avatar
Laurent Montel committed
424
425
426
            return;
        }
        break;
Laurent Montel's avatar
Laurent Montel committed
427
    case WebEngineViewer::CheckPhishingUrlUtil::Unknown:
428
        qCWarning(AKREGATOR_LOG) << "ArticleViewerWebEngine::slotCheckedUrlFinished unknown error ";
Laurent Montel's avatar
Laurent Montel committed
429
430
        break;
    }
Laurent Montel's avatar
Laurent Montel committed
431
    openSafeUrl(url);
Laurent Montel's avatar
Laurent Montel committed
432
433
}

Laurent Montel's avatar
Laurent Montel committed
434
void ArticleViewerWebEngine::slotLinkClicked(const QUrl &url)
Laurent Montel's avatar
Laurent Montel committed
435
{
Laurent Montel's avatar
Laurent Montel committed
436
    if (URLHandlerWebEngineManager::instance()->handleClick(url, this)) {
Laurent Montel's avatar
Laurent Montel committed
437
438
        return;
    }
439
    if (Settings::checkPhishingUrl()) {
440
        phishingDatabase()->checkUrl(url);
441
442
443
    } else {
        openSafeUrl(url);
    }
Laurent Montel's avatar
Laurent Montel committed
444
445
446
447
}

void ArticleViewerWebEngine::openSafeUrl(const QUrl &url)
{
Laurent Montel's avatar
Laurent Montel committed
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
    mCurrentUrl = url;
    OpenUrlRequest req(mCurrentUrl);
    if (mLastButtonClicked == LeftButton) {
        switch (Settings::lMBBehaviour()) {
        case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
            req.setOptions(OpenUrlRequest::ExternalBrowser);
            break;
        case Settings::EnumLMBBehaviour::OpenInBackground:
            req.setOpenInBackground(true);
            req.setOptions(OpenUrlRequest::NewTab);
            break;
        default:
            break;
        }
    } else if (mLastButtonClicked == MiddleButton) {
        switch (Settings::mMBBehaviour()) {
        case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
            req.setOptions(OpenUrlRequest::ExternalBrowser);
            break;
        case Settings::EnumMMBBehaviour::OpenInBackground:
            req.setOpenInBackground(true);
            req.setOptions(OpenUrlRequest::NewTab);
            break;
        default:
            break;
        }
    }
    Q_EMIT signalOpenUrlRequest(req);
}

Laurent Montel's avatar
Laurent Montel committed
478
void ArticleViewerWebEngine::slotOpenLinkInForegroundTab()
Laurent Montel's avatar
Laurent Montel committed
479
480
481
482
483
484
{
    OpenUrlRequest req(mCurrentUrl);
    req.setOptions(OpenUrlRequest::NewTab);
    Q_EMIT signalOpenUrlRequest(req);
}

Laurent Montel's avatar
Laurent Montel committed
485
void ArticleViewerWebEngine::slotOpenLinkInBackgroundTab()
Laurent Montel's avatar
Laurent Montel committed
486
487
488
489
490
491
492
{
    OpenUrlRequest req(mCurrentUrl);
    req.setOptions(OpenUrlRequest::NewTab);
    req.setOpenInBackground(true);
    Q_EMIT signalOpenUrlRequest(req);
}

Laurent Montel's avatar
Laurent Montel committed
493
void ArticleViewerWebEngine::slotOpenLinkInBrowser()
Laurent Montel's avatar
Laurent Montel committed
494
495
496
497
498
499
{
    OpenUrlRequest req(mCurrentUrl);
    req.setOptions(OpenUrlRequest::ExternalBrowser);
    Q_EMIT signalOpenUrlRequest(req);
}

500
501
502
503
504
void ArticleViewerWebEngine::createViewerPluginToolManager(KActionCollection *ac, QWidget *parent)
{
    mViewerPluginToolManager = new MessageViewer::ViewerPluginToolManager(parent, this);
    mViewerPluginToolManager->setActionCollection(ac);
    mViewerPluginToolManager->setPluginName(QStringLiteral("akregator"));
505
    mViewerPluginToolManager->setPluginDirectory(QStringLiteral("akregator/viewerplugin"));
506
    if (!mViewerPluginToolManager->initializePluginList()) {
Laurent Montel's avatar
Laurent Montel committed
507
        qCWarning(AKREGATOR_LOG) << " Impossible to initialize plugins";
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
    }
    mViewerPluginToolManager->createView();
    connect(mViewerPluginToolManager, &MessageViewer::ViewerPluginToolManager::activatePlugin, this, &ArticleViewerWebEngine::slotActivatePlugin);
}

QList<QAction *> ArticleViewerWebEngine::viewerPluginActionList(MessageViewer::ViewerPluginInterface::SpecificFeatureTypes features)
{
    if (mViewerPluginToolManager) {
        return mViewerPluginToolManager->viewerPluginActionList(features);
    }
    return QList<QAction *>();
}

void ArticleViewerWebEngine::slotActivatePlugin(MessageViewer::ViewerPluginInterface *interface)
{
    const QString text = selectedText();
    if (!text.isEmpty()) {
        interface->setText(text);
    }
Laurent Montel's avatar
Laurent Montel committed
527
    interface->setUrl(mCurrentUrl);
Laurent Montel's avatar
Laurent Montel committed
528
    interface->execute();
529
}
Andras Mantia's avatar
Andras Mantia committed
530
531

#include "articleviewerwebengine.moc"