Add code for expand url
[kdepim.git] / akregator / src / articleviewer-ng / webkit / articleviewerng.cpp
blobb52f52d41c913c385498ce3e3c5a866bf73f755c
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 "articleviewerng.h"
19 #include "akregator_debug.h"
20 #include "actionmanager.h"
21 #include "actions.h"
22 #include "webkit/urlhandlermanager.h"
23 #include "akregatorconfig.h"
24 #include <KActionCollection>
25 #include <KParts/BrowserRun>
26 #include <KMessageBox>
27 #include <KAboutData>
28 #include <KPIMTextEdit/TextToSpeech>
29 #include <KLocalizedString>
30 #include <MessageViewer/WebViewAccessKey>
31 #include <MessageViewer/WebPage>
32 #include <KActionMenu>
33 #include <QWebSettings>
34 #include <QClipboard>
35 #include <QApplication>
36 #include <MessageViewer/AdBlockManager>
38 #include <QMenu>
39 #include <QWebFrame>
40 #include <QMouseEvent>
41 #include <grantleethememanager.h>
42 #include <openurlrequest.h>
43 #include <QWebHistory>
44 #include <KConfigGroup>
45 #include <kpimprintpreviewdialog.h>
46 #include <QPrinter>
47 #include <QPrintDialog>
48 #include <QPrintPreviewDialog>
49 #include <viewerplugintoolmanager.h>
51 #include <KIO/KUriFilterSearchProviderActions>
52 using namespace Akregator;
54 ArticleViewerNg::ArticleViewerNg(KActionCollection *ac, QWidget *parent)
55 : KWebView(parent, false),
56 mActionCollection(ac),
57 mLastButtonClicked(LeftButton)
59 setContextMenuPolicy(Qt::CustomContextMenu);
60 setPage(new MessageViewer::WebPage(this));
61 mWebViewAccessKey = new MessageViewer::WebViewAccessKey(this, this);
62 mWebViewAccessKey->setActionCollection(mActionCollection);
64 settings()->setAttribute(QWebSettings::JavascriptEnabled, false);
65 settings()->setAttribute(QWebSettings::JavaEnabled, false);
66 settings()->setAttribute(QWebSettings::PluginsEnabled, false);
67 settings()->setAttribute(QWebSettings::DnsPrefetchEnabled, true);
68 settings()->setAttribute(QWebSettings::AutoLoadImages, true);
70 connect(this, &QWebView::loadStarted, this, &ArticleViewerNg::slotLoadStarted);
71 connect(this, &QWebView::loadFinished, this, &ArticleViewerNg::slotLoadFinished);
72 connect(page(), &QWebPage::scrollRequested, mWebViewAccessKey, &MessageViewer::WebViewAccessKey::hideAccessKeys);
73 page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
74 connect(page(), &QWebPage::linkHovered, this, &ArticleViewerNg::slotLinkHovered);
75 connect(this, &ArticleViewerNg::linkClicked, this, &ArticleViewerNg::slotLinkClicked);
76 connect(this, &ArticleViewerNg::showContextMenu, this, &ArticleViewerNg::slotShowContextMenu);
77 mShareServiceManager = new PimCommon::ShareServiceUrlManager(this);
78 connect(mShareServiceManager, &PimCommon::ShareServiceUrlManager::serviceUrlSelected, this, &ArticleViewerNg::slotServiceUrlSelected);
79 mWebShortcutMenuManager = new KIO::KUriFilterSearchProviderActions(this);
82 ArticleViewerNg::~ArticleViewerNg()
84 disconnect(this, &QWebView::loadFinished, this, &ArticleViewerNg::slotLoadFinished);
87 void ArticleViewerNg::createViewerPluginToolManager(KActionCollection *ac, QWidget *parent)
89 mViewerPluginToolManager = new MessageViewer::ViewerPluginToolManager(parent, this);
90 mViewerPluginToolManager->setActionCollection(ac);
91 mViewerPluginToolManager->setPluginName(QStringLiteral("akregator"));
92 mViewerPluginToolManager->setServiceTypeName(QStringLiteral("Akregator/ViewerPlugin"));
93 if (!mViewerPluginToolManager->initializePluginList()) {
94 qDebug() << " Impossible to initialize plugins";
96 mViewerPluginToolManager->createView();
97 connect(mViewerPluginToolManager, &MessageViewer::ViewerPluginToolManager::activatePlugin, this, &ArticleViewerNg::slotActivatePlugin);
100 QList<QAction *> ArticleViewerNg::viewerPluginActionList(MessageViewer::ViewerPluginInterface::SpecificFeatureTypes features)
102 if (mViewerPluginToolManager) {
103 return mViewerPluginToolManager->viewerPluginActionList(features);
105 return QList<QAction *>();
108 void ArticleViewerNg::slotActivatePlugin(MessageViewer::ViewerPluginInterface *interface)
110 const QString text = selectedText();
111 if (!text.isEmpty()) {
112 interface->setText(text);
114 interface->showWidget();
118 void ArticleViewerNg::slotSaveLinkAs()
120 QUrl tmp(mCurrentUrl);
122 if (tmp.fileName().isEmpty()) {
123 tmp = tmp.adjusted(QUrl::RemoveFilename);
124 tmp.setPath(tmp.path() + QLatin1String("index.html"));
126 KParts::BrowserRun::simpleSave(tmp, tmp.fileName());
129 void ArticleViewerNg::slotSaveImageOnDiskInFrame()
131 slotSaveLinkAs();
134 void ArticleViewerNg::slotCopyImageLocationInFrame()
136 slotCopyLinkAddress();
139 void ArticleViewerNg::slotCopyLinkAddress()
141 if (mCurrentUrl.isEmpty()) {
142 return;
144 QClipboard *cb = QApplication::clipboard();
145 cb->setText(mCurrentUrl.toString(), QClipboard::Clipboard);
146 // don't set url to selection as it's a no-no according to a fd.o spec
147 // 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
148 // a good reason to remove it again (bug 183022) --Frank
149 cb->setText(mCurrentUrl.toString(), QClipboard::Selection);
152 void ArticleViewerNg::slotShowContextMenu(const QPoint &pos)
154 displayContextMenu(pos);
157 void ArticleViewerNg::slotPrintPreview()
159 PimCommon::KPimPrintPreviewDialog previewdlg(this);
160 connect(&previewdlg, &QPrintPreviewDialog::paintRequested, this, [this](QPrinter * printer) {
161 print(printer);
163 previewdlg.exec();
166 void ArticleViewerNg::slotPrint()
168 QPrinter printer;
170 QScopedPointer<QPrintDialog> dlg(new QPrintDialog(&printer));
172 if (dlg && dlg->exec() == QDialog::Accepted) {
173 print(&printer);
177 void ArticleViewerNg::slotCopy()
179 triggerPageAction(QWebPage::Copy);
182 void ArticleViewerNg::slotLoadFinished()
184 unsetCursor();
187 void ArticleViewerNg::slotLoadStarted()
189 mWebViewAccessKey->hideAccessKeys();
190 setCursor(Qt::WaitCursor);
193 QVariantHash ArticleViewerNg::introductionData() const
195 QVariantHash data;
196 data[QStringLiteral("icon")] = QStringLiteral("akregator");
197 data[QStringLiteral("name")] = i18n("Akregator");
198 data[QStringLiteral("subtitle")] = i18n("Akregator is a KDE news feed reader.");
199 data[QStringLiteral("version")] = KAboutData::applicationData().version();
200 return data;
203 void ArticleViewerNg::showAboutPage()
205 paintAboutScreen(QStringLiteral("introduction_akregator.html"), introductionData());
208 void ArticleViewerNg::paintAboutScreen(const QString &templateName, const QVariantHash &data)
210 GrantleeTheme::ThemeManager manager(QStringLiteral("splashPage"),
211 QStringLiteral("splash.theme"),
212 Q_NULLPTR,
213 QStringLiteral("messageviewer/about/"));
214 GrantleeTheme::Theme theme = manager.theme(QStringLiteral("default"));
215 if (!theme.isValid()) {
216 qCDebug(AKREGATOR_LOG) << "Theme error: failed to find splash theme";
217 } else {
218 setHtml(theme.render(templateName, data),
219 QUrl::fromLocalFile(theme.absolutePath() + QLatin1Char('/')));
223 void ArticleViewerNg::displayContextMenu(const QPoint &pos)
225 mContextMenuHitResult = page()->mainFrame()->hitTestContent(pos);
226 mCurrentUrl = mContextMenuHitResult.linkUrl();
227 if (URLHandlerManager::instance()->handleContextMenuRequest(mCurrentUrl, mapToGlobal(pos), this)) {
228 return;
231 QMenu popup(this);
232 const bool contentSelected = mContextMenuHitResult.isContentSelected();
233 if (!mCurrentUrl.isEmpty() && !contentSelected) {
234 popup.addAction(createOpenLinkInNewTabAction(mCurrentUrl, this, SLOT(slotOpenLinkInForegroundTab()), &popup));
235 popup.addAction(createOpenLinkInExternalBrowserAction(mCurrentUrl, this, SLOT(slotOpenLinkInBrowser()), &popup));
236 popup.addSeparator();
237 popup.addAction(mActionCollection->action(QStringLiteral("savelinkas")));
238 popup.addAction(mActionCollection->action(QStringLiteral("copylinkaddress")));
239 if (!mContextMenuHitResult.imageUrl().isEmpty()) {
240 popup.addSeparator();
241 popup.addAction(mActionCollection->action(QStringLiteral("copy_image_location")));
242 popup.addAction(mActionCollection->action(QStringLiteral("saveas_imageurl")));
243 if (adblockEnabled()) {
244 popup.addSeparator();
245 popup.addAction(mActionCollection->action(QStringLiteral("adblock_image")));
247 #if 0
248 //popup.addAction(mMsgView->shareImage());
249 #endif
250 //TODO
252 popup.addSeparator();
253 popup.addAction(mShareServiceManager->menu());
254 } else {
255 if (contentSelected) {
256 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_copy")));
257 popup.addSeparator();
258 mWebShortcutMenuManager->setSelectedText(page()->selectedText());
259 mWebShortcutMenuManager->addWebShortcutsToMenu(&popup);
260 popup.addSeparator();
261 popup.addActions(viewerPluginActionList(MessageViewer::ViewerPluginInterface::NeedSelection));
262 popup.addSeparator();
264 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_print")));
265 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("viewer_printpreview")));
267 popup.addSeparator();
268 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("find_in_messages")));
269 if (KPIMTextEdit::TextToSpeech::self()->isReady()) {
270 popup.addSeparator();
271 popup.addAction(ActionManager::getInstance()->action(QStringLiteral("speak_text")));
273 popup.exec(mapToGlobal(pos));
276 void ArticleViewerNg::slotServiceUrlSelected(PimCommon::ShareServiceUrlManager::ServiceType type)
278 const QUrl url = mShareServiceManager->generateServiceUrl(mCurrentUrl.url(), QString(), type);
279 mShareServiceManager->openUrl(url);
282 void ArticleViewerNg::slotLinkHovered(const QString &link, const QString &title, const QString &textContent)
284 Q_UNUSED(title);
285 Q_UNUSED(textContent);
286 QUrl url(linkOrImageUrlAt(QCursor::pos()));
287 QString msg = URLHandlerManager::instance()->statusBarMessage(url, this);
288 if (msg.isEmpty()) {
289 msg = link;
292 Q_EMIT showStatusBarMessage(msg);
295 void ArticleViewerNg::keyReleaseEvent(QKeyEvent *e)
297 if (Settings::self()->accessKeyEnabled()) {
298 mWebViewAccessKey->keyReleaseEvent(e);
300 KWebView::keyReleaseEvent(e);
303 void ArticleViewerNg::keyPressEvent(QKeyEvent *e)
305 if (e && hasFocus()) {
306 if (Settings::self()->accessKeyEnabled()) {
307 mWebViewAccessKey->keyPressEvent(e);
310 KWebView::keyPressEvent(e);
313 void ArticleViewerNg::wheelEvent(QWheelEvent *e)
315 if (Settings::self()->accessKeyEnabled()) {
316 mWebViewAccessKey->wheelEvent(e);
318 KWebView::wheelEvent(e);
321 void ArticleViewerNg::resizeEvent(QResizeEvent *e)
323 if (Settings::self()->accessKeyEnabled()) {
324 mWebViewAccessKey->resizeEvent(e);
326 KWebView::resizeEvent(e);
329 void ArticleViewerNg::disableIntroduction()
331 KGuiItem yesButton(KStandardGuiItem::yes());
332 yesButton.setText(i18n("Disable"));
333 KGuiItem noButton(KStandardGuiItem::no());
334 noButton.setText(i18n("Keep Enabled"));
335 if (KMessageBox::questionYesNo(this, i18n("Are you sure you want to disable this introduction page?"),
336 i18n("Disable Introduction Page"), yesButton, noButton) == KMessageBox::Yes) {
337 Settings::self()->setDisableIntroduction(true);
338 Settings::self()->save();
342 void ArticleViewerNg::setArticleAction(ArticleViewerNg::ArticleAction type, const QString &articleId, const QString &feed)
344 Q_EMIT articleAction(type, articleId, feed);
347 void ArticleViewerNg::mouseReleaseEvent(QMouseEvent *event)
349 if (event->button() & Qt::RightButton) {
350 Q_EMIT showContextMenu(event->pos());
351 mLastButtonClicked = RightButton;
352 } else if (event->button() & Qt::MiddleButton) {
353 mLastButtonClicked = MiddleButton;
354 } else if (event->button() & Qt::LeftButton) {
355 mLastButtonClicked = LeftButton;
357 QWebView::mouseReleaseEvent(event);
360 void ArticleViewerNg::slotLinkClicked(const QUrl &url)
362 if (URLHandlerManager::instance()->handleClick(url, this)) {
363 return;
366 mCurrentUrl = url;
367 OpenUrlRequest req(mCurrentUrl);
368 if (mLastButtonClicked == LeftButton) {
369 switch (Settings::lMBBehaviour()) {
370 case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
371 req.setOptions(OpenUrlRequest::ExternalBrowser);
372 break;
373 case Settings::EnumLMBBehaviour::OpenInBackground:
374 req.setOpenInBackground(true);
375 req.setOptions(OpenUrlRequest::NewTab);
376 break;
377 default:
378 break;
380 } else if (mLastButtonClicked == MiddleButton) {
381 switch (Settings::mMBBehaviour()) {
382 case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
383 req.setOptions(OpenUrlRequest::ExternalBrowser);
384 break;
385 case Settings::EnumMMBBehaviour::OpenInBackground:
386 req.setOpenInBackground(true);
387 req.setOptions(OpenUrlRequest::NewTab);
388 break;
389 default:
390 break;
393 Q_EMIT signalOpenUrlRequest(req);
396 void ArticleViewerNg::slotOpenLinkInForegroundTab()
398 OpenUrlRequest req(mCurrentUrl);
399 req.setOptions(OpenUrlRequest::NewTab);
400 Q_EMIT signalOpenUrlRequest(req);
403 void ArticleViewerNg::slotOpenLinkInBackgroundTab()
405 OpenUrlRequest req(mCurrentUrl);
406 req.setOptions(OpenUrlRequest::NewTab);
407 req.setOpenInBackground(true);
408 Q_EMIT signalOpenUrlRequest(req);
411 void ArticleViewerNg::slotOpenLinkInBrowser()
413 OpenUrlRequest req(mCurrentUrl);
414 req.setOptions(OpenUrlRequest::ExternalBrowser);
415 Q_EMIT signalOpenUrlRequest(req);
418 QUrl ArticleViewerNg::linkOrImageUrlAt(const QPoint &global) const
420 const QPoint local = page()->view()->mapFromGlobal(global);
421 const QWebHitTestResult hit = page()->currentFrame()->hitTestContent(local);
422 if (!hit.linkUrl().isEmpty()) {
423 return hit.linkUrl();
424 } else if (!hit.imageUrl().isEmpty()) {
425 return hit.imageUrl();
426 } else {
427 return QUrl();
431 bool ArticleViewerNg::zoomTextOnlyInFrame() const
433 return settings()->testAttribute(QWebSettings::ZoomTextOnly);
436 void ArticleViewerNg::slotZoomTextOnlyInFrame(bool textOnlyInFrame)
438 settings()->setAttribute(QWebSettings::ZoomTextOnly, textOnlyInFrame);
441 void ArticleViewerNg::slotExpandUrl()
443 //TODO
446 void ArticleViewerNg::slotBlockImage()
448 if (mCurrentUrl.isEmpty()) {
449 return;
451 MessageViewer::AdBlockManager::self()->addCustomRule(mCurrentUrl.url(), true);
454 bool ArticleViewerNg::adblockEnabled() const
456 return MessageViewer::AdBlockManager::self()->isEnabled();