Astyle kdelibs
[kdepim.git] / akregator / src / articleviewer-ng / webengine / articleviewerwebengine.cpp
bloba23af02f7b8c1140bd2b38b974528bdeb8404451
1 /*
2 Copyright (c) 2015-2016 Montel Laurent <montel@kde.org>
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "articleviewerwebengine.h"
19 #include "akregator_debug.h"
20 #include "articleviewerwebenginepage.h"
21 #include "webengine/urlhandlerwebenginemanager.h"
22 #include "actionmanager.h"
23 #include "akregatorconfig.h"
24 #include "actions/actions.h"
25 #include "urlhandler/webengine/urlhandlerwebengine.h"
27 #include <MessageViewer/NetworkAccessManagerWebEngine>
28 #include <KPIMTextEdit/TextToSpeech>
29 #include <KActionMenu>
31 #include <KParts/BrowserRun>
32 #include <grantleethememanager.h>
33 #include <KActionCollection>
34 #include <KLocalizedString>
35 #include <KAboutData>
36 #include <KGuiItem>
37 #include <openurlrequest.h>
38 #include <KPimPrintPreviewDialog>
39 #include <KMessageBox>
40 #include <QPrinter>
41 #include <QWebEngineSettings>
42 #include <QMouseEvent>
43 #include <QPrintDialog>
44 #include <QApplication>
45 #include <QClipboard>
46 #include <QMenu>
47 #include <viewerplugintoolmanager.h>
48 #include <MessageViewer/WebHitTestResult>
49 #include <MessageViewer/WebHitTest>
50 #include <MessageViewer/ScamCheckShortUrlManager>
51 #include <MessageViewer/ScamCheckShortUrl>
53 #include <KIO/KUriFilterSearchProviderActions>
55 using namespace Akregator;
57 ArticleViewerWebEngine::ArticleViewerWebEngine(KActionCollection *ac, QWidget *parent)
58 : QWebEngineView(parent),
59 mActionCollection(ac),
60 mLastButtonClicked(LeftButton),
61 mViewerPluginToolManager(Q_NULLPTR)
63 new MessageViewer::NetworkAccessManagerWebEngine(ac, this);
64 mPageEngine = new ArticleViewerWebEnginePage(this);
65 setPage(mPageEngine);
67 connect(this, &ArticleViewerWebEngine::showContextMenu, this, &ArticleViewerWebEngine::slotShowContextMenu);
69 setFocusPolicy(Qt::WheelFocus);
70 connect(mPageEngine, &ArticleViewerWebEnginePage::urlClicked, this, &ArticleViewerWebEngine::slotLinkClicked);
72 //mWebViewAccessKey = new MessageViewer::WebViewAccessKey(this, this);
73 //mWebViewAccessKey->setActionCollection(mActionCollection);
75 connect(this, &ArticleViewerWebEngine::loadStarted, this, &ArticleViewerWebEngine::slotLoadStarted);
76 connect(this, &ArticleViewerWebEngine::loadFinished, this, &ArticleViewerWebEngine::slotLoadFinished);
77 //connect(page(), &QWebEnginePage::scrollRequested, mWebViewAccessKey, &MessageViewer::WebViewAccessKey::hideAccessKeys);
78 connect(page(), &QWebEnginePage::linkHovered, this, &ArticleViewerWebEngine::slotLinkHovered);
80 setContextMenuPolicy(Qt::DefaultContextMenu);
81 mWebShortcutMenuManager = new KIO::KUriFilterSearchProviderActions(this);
82 mShareServiceManager = new PimCommon::ShareServiceUrlManager(this);
83 connect(mShareServiceManager, &PimCommon::ShareServiceUrlManager::serviceUrlSelected, this, &ArticleViewerWebEngine::slotServiceUrlSelected);
86 ArticleViewerWebEngine::~ArticleViewerWebEngine()
91 QVariantHash ArticleViewerWebEngine::introductionData() const
93 QVariantHash data;
94 data[QStringLiteral("icon")] = QStringLiteral("akregator");
95 data[QStringLiteral("name")] = i18n("Akregator");
96 data[QStringLiteral("subtitle")] = i18n("Akregator is a KDE news feed reader.");
97 data[QStringLiteral("version")] = KAboutData::applicationData().version();
98 return data;
101 void ArticleViewerWebEngine::showAboutPage()
103 paintAboutScreen(QStringLiteral("introduction_akregator.html"), introductionData());
106 void ArticleViewerWebEngine::paintAboutScreen(const QString &templateName, const QVariantHash &data)
108 GrantleeTheme::ThemeManager manager(QStringLiteral("splashPage"),
109 QStringLiteral("splash.theme"),
110 Q_NULLPTR,
111 QStringLiteral("messageviewer/about/"));
112 GrantleeTheme::Theme theme = manager.theme(QStringLiteral("default"));
113 if (theme.isValid()) {
114 setHtml(theme.render(templateName, data),
115 QUrl::fromLocalFile(theme.absolutePath() + QLatin1Char('/')));
116 } else {
117 qCDebug(AKREGATOR_LOG) << "Theme error: failed to find splash theme";
121 void ArticleViewerWebEngine::slotServiceUrlSelected(PimCommon::ShareServiceUrlManager::ServiceType type)
123 const QUrl url = mShareServiceManager->generateServiceUrl(mCurrentUrl.url(), QString(), type);
124 mShareServiceManager->openUrl(url);
127 void ArticleViewerWebEngine::slotSaveLinkAs()
129 QUrl tmp(mCurrentUrl);
131 if (tmp.fileName().isEmpty()) {
132 tmp = tmp.adjusted(QUrl::RemoveFilename);
133 tmp.setPath(tmp.path() + QLatin1String("index.html"));
135 KParts::BrowserRun::simpleSave(tmp, tmp.fileName());
138 void ArticleViewerWebEngine::slotSaveImageOnDiskInFrame()
140 slotSaveLinkAs();
143 void ArticleViewerWebEngine::slotCopyImageLocationInFrame()
145 slotCopyLinkAddress();
148 void ArticleViewerWebEngine::slotCopyLinkAddress()
150 if (mCurrentUrl.isEmpty()) {
151 return;
153 QClipboard *cb = QApplication::clipboard();
154 cb->setText(mCurrentUrl.toString(), QClipboard::Clipboard);
155 // don't set url to selection as it's a no-no according to a fd.o spec
156 // 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
157 // a good reason to remove it again (bug 183022) --Frank
158 cb->setText(mCurrentUrl.toString(), QClipboard::Selection);
161 void ArticleViewerWebEngine::contextMenuEvent(QContextMenuEvent *e)
163 displayContextMenu(e->pos());
166 void ArticleViewerWebEngine::slotShowContextMenu(const QPoint &pos)
168 displayContextMenu(pos);
171 void ArticleViewerWebEngine::slotPrintPreview()
173 PimCommon::KPimPrintPreviewDialog previewdlg(this);
174 connect(&previewdlg, &QPrintPreviewDialog::paintRequested, this, [this](QPrinter * printer) {
175 render(printer);
177 previewdlg.exec();
180 void ArticleViewerWebEngine::slotPrint()
182 QPrinter printer;
184 QScopedPointer<QPrintDialog> dlg(new QPrintDialog(&printer));
186 if (dlg && dlg->exec() == QDialog::Accepted) {
187 render(&printer);
191 void ArticleViewerWebEngine::slotCopy()
193 triggerPageAction(QWebEnginePage::Copy);
196 void ArticleViewerWebEngine::slotLoadFinished()
198 unsetCursor();
201 void ArticleViewerWebEngine::slotLoadStarted()
203 //mWebViewAccessKey->hideAccessKeys();
204 setCursor(Qt::WaitCursor);
207 void ArticleViewerWebEngine::slotWebHitFinished(const MessageViewer::WebHitTestResult &result)
209 mCurrentUrl = result.linkUrl();
210 if (URLHandlerWebEngineManager::instance()->handleContextMenuRequest(mCurrentUrl, mapToGlobal(result.pos()), this)) {
211 return;
214 QMenu popup(this);
215 const bool contentSelected = !selectedText().isEmpty();
216 if (!contentSelected) {
217 if (!mCurrentUrl.isEmpty()) {
218 popup.addAction(createOpenLinkInNewTabAction(mCurrentUrl, this, SLOT(slotOpenLinkInForegroundTab()), &popup));
219 popup.addAction(createOpenLinkInExternalBrowserAction(mCurrentUrl, this, SLOT(slotOpenLinkInBrowser()), &popup));
220 popup.addSeparator();
221 popup.addAction(mActionCollection->action(QStringLiteral("savelinkas")));
222 popup.addAction(mActionCollection->action(QStringLiteral("copylinkaddress")));
224 if (!result.imageUrl().isEmpty()) {
225 popup.addSeparator();
226 popup.addAction(mActionCollection->action(QStringLiteral("copy_image_location")));
227 popup.addAction(mActionCollection->action(QStringLiteral("saveas_imageurl")));
228 if (adblockEnabled()) {
229 popup.addSeparator();
230 popup.addAction(mActionCollection->action(QStringLiteral("adblock_image")));
233 if (MessageViewer::ScamCheckShortUrlManager::self()->scamCheckShortUrl()->isShortUrl(mCurrentUrl)) {
234 popup.addSeparator();
235 popup.addAction(mActionCollection->action(QStringLiteral("expand_short_url")));
237 popup.addSeparator();
238 popup.addAction(mShareServiceManager->menu());
239 } else {
240 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_copy")));
241 popup.addSeparator();
242 mWebShortcutMenuManager->setSelectedText(page()->selectedText());
243 mWebShortcutMenuManager->addWebShortcutsToMenu(&popup);
244 popup.addSeparator();
245 popup.addActions(viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection));
247 #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
248 popup.addSeparator();
249 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_print")));
250 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_printpreview")));
251 #endif
252 popup.addSeparator();
253 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("find_in_messages")));
254 if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
255 popup.addSeparator();
256 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("speak_text")));
258 popup.exec(mapToGlobal(result.pos()));
261 void ArticleViewerWebEngine::displayContextMenu(const QPoint &pos)
263 MessageViewer::WebHitTest *webHit = mPageEngine->hitTestContent(pos);
264 connect(webHit, &MessageViewer::WebHitTest::finished, this, &ArticleViewerWebEngine::slotWebHitFinished);
267 void ArticleViewerWebEngine::slotLinkHovered(const QString &link)
269 QString msg = URLHandlerWebEngineManager::instance()->statusBarMessage(QUrl(link), this);
270 if (msg.isEmpty()) {
271 msg = link;
274 Q_EMIT showStatusBarMessage(msg);
277 void ArticleViewerWebEngine::keyReleaseEvent(QKeyEvent *e)
279 if (Settings::self()->accessKeyEnabled()) {
280 //mWebViewAccessKey->keyReleaseEvent(e);
282 QWebEngineView::keyReleaseEvent(e);
285 void ArticleViewerWebEngine::keyPressEvent(QKeyEvent *e)
287 if (e && hasFocus()) {
288 if (Settings::self()->accessKeyEnabled()) {
289 //mWebViewAccessKey->keyPressEvent(e);
292 QWebEngineView::keyPressEvent(e);
295 void ArticleViewerWebEngine::wheelEvent(QWheelEvent *e)
297 if (Settings::self()->accessKeyEnabled()) {
298 //mWebViewAccessKey->wheelEvent(e);
300 QWebEngineView::wheelEvent(e);
303 void ArticleViewerWebEngine::resizeEvent(QResizeEvent *e)
305 if (Settings::self()->accessKeyEnabled()) {
306 //mWebViewAccessKey->resizeEvent(e);
308 QWebEngineView::resizeEvent(e);
311 void ArticleViewerWebEngine::disableIntroduction()
313 KGuiItem yesButton(KStandardGuiItem::yes());
314 yesButton.setText(i18n("Disable"));
315 KGuiItem noButton(KStandardGuiItem::no());
316 noButton.setText(i18n("Keep Enabled"));
317 if (KMessageBox::questionYesNo(this, i18n("Are you sure you want to disable this introduction page?"),
318 i18n("Disable Introduction Page"), yesButton, noButton) == KMessageBox::Yes) {
319 Settings::self()->setDisableIntroduction(true);
320 Settings::self()->save();
324 void ArticleViewerWebEngine::setArticleAction(ArticleViewerWebEngine::ArticleAction type, const QString &articleId, const QString &feed)
326 Q_EMIT articleAction(type, articleId, feed);
329 void ArticleViewerWebEngine::mouseReleaseEvent(QMouseEvent *event)
331 if (event->button() & Qt::RightButton) {
332 Q_EMIT showContextMenu(event->pos());
333 mLastButtonClicked = RightButton;
334 } else if (event->button() & Qt::MiddleButton) {
335 mLastButtonClicked = MiddleButton;
336 } else if (event->button() & Qt::LeftButton) {
337 mLastButtonClicked = LeftButton;
339 QWebEngineView::mouseReleaseEvent(event);
342 void ArticleViewerWebEngine::slotLinkClicked(const QUrl &url)
344 if (URLHandlerWebEngineManager::instance()->handleClick(url, this)) {
345 return;
347 mCurrentUrl = url;
348 OpenUrlRequest req(mCurrentUrl);
349 if (mLastButtonClicked == LeftButton) {
350 switch (Settings::lMBBehaviour()) {
351 case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
352 req.setOptions(OpenUrlRequest::ExternalBrowser);
353 break;
354 case Settings::EnumLMBBehaviour::OpenInBackground:
355 req.setOpenInBackground(true);
356 req.setOptions(OpenUrlRequest::NewTab);
357 break;
358 default:
359 break;
361 } else if (mLastButtonClicked == MiddleButton) {
362 switch (Settings::mMBBehaviour()) {
363 case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
364 req.setOptions(OpenUrlRequest::ExternalBrowser);
365 break;
366 case Settings::EnumMMBBehaviour::OpenInBackground:
367 req.setOpenInBackground(true);
368 req.setOptions(OpenUrlRequest::NewTab);
369 break;
370 default:
371 break;
374 Q_EMIT signalOpenUrlRequest(req);
377 void ArticleViewerWebEngine::slotOpenLinkInForegroundTab()
379 OpenUrlRequest req(mCurrentUrl);
380 req.setOptions(OpenUrlRequest::NewTab);
381 Q_EMIT signalOpenUrlRequest(req);
384 void ArticleViewerWebEngine::slotOpenLinkInBackgroundTab()
386 OpenUrlRequest req(mCurrentUrl);
387 req.setOptions(OpenUrlRequest::NewTab);
388 req.setOpenInBackground(true);
389 Q_EMIT signalOpenUrlRequest(req);
392 void ArticleViewerWebEngine::slotOpenLinkInBrowser()
394 OpenUrlRequest req(mCurrentUrl);
395 req.setOptions(OpenUrlRequest::ExternalBrowser);
396 Q_EMIT signalOpenUrlRequest(req);
399 bool ArticleViewerWebEngine::zoomTextOnlyInFrame() const
401 return false;
402 //return settings()->testAttribute(QWebEngineSettings::ZoomTextOnly);
405 void ArticleViewerWebEngine::createViewerPluginToolManager(KActionCollection *ac, QWidget *parent)
407 mViewerPluginToolManager = new MessageViewer::ViewerPluginToolManager(parent, this);
408 mViewerPluginToolManager->setActionCollection(ac);
409 mViewerPluginToolManager->setPluginName(QStringLiteral("akregator"));
410 mViewerPluginToolManager->setServiceTypeName(QStringLiteral("Akregator/ViewerPlugin"));
411 if (!mViewerPluginToolManager->initializePluginList()) {
412 qDebug() << " Impossible to initialize plugins";
414 mViewerPluginToolManager->createView();
415 connect(mViewerPluginToolManager, &MessageViewer::ViewerPluginToolManager::activatePlugin, this, &ArticleViewerWebEngine::slotActivatePlugin);
418 QList<QAction *> ArticleViewerWebEngine::viewerPluginActionList(MessageViewer::ViewerPluginInterface::SpecificFeatureTypes features)
420 if (mViewerPluginToolManager) {
421 return mViewerPluginToolManager->viewerPluginActionList(features);
423 return QList<QAction *>();
426 void ArticleViewerWebEngine::slotActivatePlugin(MessageViewer::ViewerPluginInterface *interface)
428 const QString text = selectedText();
429 if (!text.isEmpty()) {
430 interface->setText(text);
432 interface->execute();
435 void ArticleViewerWebEngine::slotZoomTextOnlyInFrame(bool textOnlyInFrame)
437 //settings()->setAttribute(QWebEngineSettings::ZoomTextOnly, textOnlyInFrame);
440 void ArticleViewerWebEngine::slotBlockImage()
442 if (mCurrentUrl.isEmpty()) {
443 return;
445 //MessageViewer::AdBlockManager::self()->addCustomRule(mCurrentUrl.url(), true);
448 bool ArticleViewerWebEngine::adblockEnabled() const
450 return false;
451 //return MessageViewer::AdBlockManager::self()->isEnabled();
454 void Akregator::ArticleViewerWebEngine::slotExpandUrl()
456 //TODO