Add code for expand url
[kdepim.git] / akregator / src / mainwidget.cpp
blob4c571ac3eae9bb27f65c106e91d26f09ddc69598
1 /*
2 This file is part of Akregator.
4 Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5 2004 Sashmit Bhaduri <smt@vfemail.net>
6 2005 Frank Osterfeld <osterfeld@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 As a special exception, permission is given to link this program
23 with any edition of Qt, and distribute the resulting executable,
24 without including the source code for Qt in the source distribution.
27 #include "mainwidget.h"
28 #include "utils.h"
29 #include "actionmanagerimpl.h"
30 #include "addfeeddialog.h"
31 #include "articlelistview.h"
32 #include "articleviewerwidget.h"
33 #include "abstractselectioncontroller.h"
34 #include "articlejobs.h"
35 #include "articlematcher.h"
36 #include "akregatorconfig.h"
37 #include "akregator_part.h"
38 #include "Libkdepim/BroadcastStatus"
39 #include "createfeedcommand.h"
40 #include "createfoldercommand.h"
41 #include "deletesubscriptioncommand.h"
42 #include "editsubscriptioncommand.h"
43 #include "expireitemscommand.h"
44 #include "importfeedlistcommand.h"
45 #include "feed.h"
46 #include "feedlist.h"
47 #include "feedpropertiesdialog.h"
48 #include "fetchqueue.h"
49 #include "folder.h"
50 #include "framemanager.h"
51 #include "kernel.h"
52 #include "notificationmanager.h"
53 #include "openurlrequest.h"
54 #include "progressmanager.h"
55 #include "widgets/searchbar.h"
56 #include "selectioncontroller.h"
57 #include "subscriptionlistjobs.h"
58 #include "subscriptionlistmodel.h"
59 #include "subscriptionlistview.h"
60 #include "tabwidget.h"
61 #include "treenode.h"
62 #include "treenodevisitor.h"
63 #include "types.h"
64 #include "mainframe.h"
65 #include <MessageViewer/ZoomActionMenu>
66 #include "job/downloadarticlejob.h"
68 #include <QAction>
69 #include <kfileitem.h>
70 #include <KLocalizedString>
71 #include <kmessagebox.h>
72 #include <krandom.h>
73 #include <kshell.h>
75 #include <ktoggleaction.h>
76 #include <QUrl>
78 #include <QClipboard>
79 #include <QNetworkConfigurationManager>
80 #include <QSplitter>
81 #include <QTextDocument>
82 #include <QDomDocument>
83 #include <QTimer>
84 #include <QDesktopServices>
86 #include <algorithm>
87 #include <memory>
88 #include <cassert>
90 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
91 #include <webengine/webengineframe.h>
92 #include "articleviewer-ng/webengine/articleviewerwebenginewidgetng.h"
93 #else
94 #include "webkit/webviewframe.h"
95 #endif
97 using namespace Akregator;
99 MainWidget::~MainWidget()
101 // if m_shuttingDown is false, slotOnShutdown was not called. That
102 // means that not the whole app is shutdown, only the part. So it
103 // should be no risk to do the cleanups now
104 if (!m_shuttingDown) {
105 slotOnShutdown();
109 MainWidget::MainWidget(Part *part, QWidget *parent, ActionManagerImpl *actionManager, const char *name)
110 : QWidget(parent),
111 m_feedList(),
112 m_viewMode(NormalView),
113 m_actionManager(actionManager),
114 m_feedListManagementInterface(new FeedListManagementImpl),
115 m_networkConfigManager(new QNetworkConfigurationManager(this))
117 setObjectName(QLatin1String(name));
119 FeedListManagementInterface::setInstance(m_feedListManagementInterface);
121 m_actionManager->initMainWidget(this);
122 m_part = part;
123 m_shuttingDown = false;
124 m_displayingAboutPage = false;
125 setFocusPolicy(Qt::StrongFocus);
127 QVBoxLayout *lt = new QVBoxLayout(this);
128 lt->setMargin(0);
130 m_horizontalSplitter = new QSplitter(Qt::Horizontal, this);
132 m_horizontalSplitter->setOpaqueResize(true);
133 m_horizontalSplitter->setChildrenCollapsible(false);
134 lt->addWidget(m_horizontalSplitter);
136 connect(Kernel::self()->fetchQueue(), &FetchQueue::signalStarted,
137 this, &MainWidget::slotFetchingStarted);
138 connect(Kernel::self()->fetchQueue(), &FetchQueue::signalStopped,
139 this, &MainWidget::slotFetchingStopped);
141 m_feedListView = new SubscriptionListView(m_horizontalSplitter);
142 m_feedListView->setObjectName(QStringLiteral("feedtree"));
143 m_actionManager->initSubscriptionListView(m_feedListView);
145 connect(m_feedListView, &SubscriptionListView::userActionTakingPlace,
146 this, &MainWidget::ensureArticleTabVisible);
148 m_tabWidget = new TabWidget(m_horizontalSplitter);
149 m_actionManager->initTabWidget(m_tabWidget);
151 connect(m_part, &Part::signalSettingsChanged,
152 m_tabWidget, &TabWidget::slotSettingsChanged);
154 connect(m_tabWidget, &TabWidget::signalCurrentFrameChanged,
155 this, &MainWidget::slotCurrentFrameChanged);
157 connect(m_tabWidget, &TabWidget::signalRemoveFrameRequest,
158 Kernel::self()->frameManager(), &FrameManager::slotRemoveFrame);
160 connect(m_tabWidget, SIGNAL(signalOpenUrlRequest(Akregator::OpenUrlRequest&)),
161 Kernel::self()->frameManager(), SLOT(slotOpenUrlRequest(Akregator::OpenUrlRequest&)));
163 connect(Kernel::self()->frameManager(), &FrameManager::signalFrameAdded,
164 m_tabWidget, &TabWidget::slotAddFrame);
166 connect(Kernel::self()->frameManager(), &FrameManager::signalSelectFrame,
167 m_tabWidget, &TabWidget::slotSelectFrame);
169 connect(Kernel::self()->frameManager(), &FrameManager::signalFrameRemoved,
170 m_tabWidget, &TabWidget::slotRemoveFrame);
172 connect(Kernel::self()->frameManager(), &FrameManager::signalRequestNewFrame,
173 this, &MainWidget::slotRequestNewFrame);
175 connect(Kernel::self()->frameManager(), &FrameManager::signalFrameAdded,
176 this, &MainWidget::slotFramesChanged);
177 connect(Kernel::self()->frameManager(), &FrameManager::signalFrameRemoved,
178 this, &MainWidget::slotFramesChanged);
179 connect(m_networkConfigManager, &QNetworkConfigurationManager::onlineStateChanged,
180 this, &MainWidget::slotNetworkStatusChanged);
182 m_tabWidget->setWhatsThis(i18n("You can view multiple articles in several open tabs."));
184 m_mainTab = new QWidget(this);
185 m_mainTab->setObjectName(QStringLiteral("Article Tab"));
186 m_mainTab->setWhatsThis(i18n("Articles list."));
188 QVBoxLayout *mainTabLayout = new QVBoxLayout(m_mainTab);
189 mainTabLayout->setMargin(0);
191 m_searchBar = new SearchBar(m_mainTab);
192 if (!Settings::showQuickFilter()) {
193 m_searchBar->hide();
195 m_articleSplitter = new QSplitter(Qt::Vertical, m_mainTab);
196 m_articleSplitter->setObjectName(QStringLiteral("panner2"));
197 m_articleSplitter->setChildrenCollapsible(false);
199 m_articleWidget = new QWidget(m_articleSplitter);
200 QVBoxLayout *articleWidgetLayout = new QVBoxLayout;
201 m_articleWidget->setLayout(articleWidgetLayout);
202 articleWidgetLayout->setMargin(0);
203 articleWidgetLayout->setSpacing(0);
205 m_articleListView = new ArticleListView;
206 articleWidgetLayout->addWidget(m_searchBar);
207 articleWidgetLayout->addWidget(m_articleListView);
208 connect(m_articleListView, &ArticleListView::userActionTakingPlace,
209 this, &MainWidget::ensureArticleTabVisible);
211 m_selectionController = new SelectionController(this);
212 m_selectionController->setArticleLister(m_articleListView);
213 m_selectionController->setFeedSelector(m_feedListView);
215 connect(m_searchBar, &SearchBar::signalSearch,
216 m_selectionController, &AbstractSelectionController::setFilters);
218 FolderExpansionHandler *expansionHandler = new FolderExpansionHandler(this);
219 connect(m_feedListView, &QTreeView::expanded, expansionHandler, &FolderExpansionHandler::itemExpanded);
220 connect(m_feedListView, &QTreeView::collapsed, expansionHandler, &FolderExpansionHandler::itemCollapsed);
222 m_selectionController->setFolderExpansionHandler(expansionHandler);
224 connect(m_selectionController, &AbstractSelectionController::currentSubscriptionChanged,
225 this, &MainWidget::slotNodeSelected);
227 connect(m_selectionController, &AbstractSelectionController::currentArticleChanged,
228 this, &MainWidget::slotArticleSelected);
230 connect(m_selectionController, &AbstractSelectionController::articleDoubleClicked,
231 this, &MainWidget::slotOpenArticleInBrowser);
233 m_actionManager->initArticleListView(m_articleListView);
235 connect(m_articleListView, &ArticleListView::signalMouseButtonPressed,
236 this, &MainWidget::slotMouseButtonPressed);
238 m_articleViewer = new ArticleViewerWidget(Settings::grantleeDirectory(), m_actionManager->actionCollection(), m_articleSplitter);
239 m_articleListView->setFocusProxy(m_articleViewer);
240 setFocusProxy(m_articleViewer);
242 connect(m_articleViewer, &ArticleViewerWidget::showStatusBarMessage, this, &MainWidget::slotShowStatusBarMessage);
243 connect(m_articleViewer, SIGNAL(signalOpenUrlRequest(Akregator::OpenUrlRequest&)),
244 Kernel::self()->frameManager(), SLOT(slotOpenUrlRequest(Akregator::OpenUrlRequest&)));
245 connect(m_part, &Part::signalSettingsChanged,
246 m_articleViewer, &ArticleViewerWidget::slotPaletteOrFontChanged);
247 connect(m_searchBar, &SearchBar::signalSearch,
248 m_articleViewer, &ArticleViewerWidget::setFilters);
249 mainTabLayout->addWidget(m_articleSplitter);
251 m_mainFrame = new MainFrame(this, m_part, m_mainTab);
252 m_mainFrame->slotSetTitle(i18n("Articles"));
253 m_mainFrame->setArticleViewer(m_articleViewer);
254 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
255 connect(m_articleViewer->articleViewerWidgetNg()->articleViewerNg(), &ArticleViewerWebEngine::articleAction, this, &MainWidget::slotArticleAction);
256 #else
257 connect(m_articleViewer->articleViewerWidgetNg()->articleViewerNg(), &ArticleViewerNg::articleAction, this, &MainWidget::slotArticleAction);
258 #endif
259 connect(m_tabWidget, &TabWidget::signalCopyInFrame, m_mainFrame, &MainFrame::slotCopyInFrame);
260 connect(m_tabWidget, &TabWidget::signalPrintInFrame, m_mainFrame, &MainFrame::slotPrintInFrame);
261 connect(m_tabWidget, &TabWidget::signalZoomChangedInFrame, m_mainFrame, &MainFrame::slotZoomChangeInFrame);
262 connect(m_tabWidget, &TabWidget::signalZoomTextOnlyInFrame, m_mainFrame, &MainFrame::slotZoomTextOnlyInFrame);
263 connect(m_tabWidget, &TabWidget::signalPrintPreviewInFrame, m_mainFrame, &MainFrame::slotPrintPreviewInFrame);
264 connect(m_tabWidget, &TabWidget::signalFindTextInFrame, m_mainFrame, &MainFrame::slotFindTextInFrame);
265 connect(m_tabWidget, &TabWidget::signalTextToSpeechInFrame, m_mainFrame, &MainFrame::slotTextToSpeechInFrame);
266 connect(m_tabWidget, &TabWidget::signalSaveLinkAsInFrame, m_mainFrame, &MainFrame::slotSaveLinkAsInFrame);
267 connect(m_tabWidget, &TabWidget::signalCopyLinkAsInFrame, m_mainFrame, &MainFrame::slotCopyLinkAsInFrame);
268 connect(m_tabWidget, &TabWidget::signalCopyImageLocation, m_mainFrame, &MainFrame::slotCopyImageLocationInFrame);
269 connect(m_tabWidget, &TabWidget::signalSaveImageOnDisk, m_mainFrame, &MainFrame::slotSaveImageOnDiskInFrame);
270 connect(m_tabWidget, &TabWidget::signalBlockImage, m_mainFrame, &MainFrame::slotBlockImageInFrame);
271 connect(m_tabWidget, &TabWidget::signalExpandUrl, m_mainFrame, &MainFrame::slotExpandUrlInFrame);
273 Kernel::self()->frameManager()->slotAddFrame(m_mainFrame);
275 const QList<int> sp1sizes = Settings::splitter1Sizes();
276 if (sp1sizes.count() >= m_horizontalSplitter->count()) {
277 m_horizontalSplitter->setSizes(sp1sizes);
279 const QList<int> sp2sizes = Settings::splitter2Sizes();
280 if (sp2sizes.count() >= m_articleSplitter->count()) {
281 m_articleSplitter->setSizes(sp2sizes);
284 if (!Settings::self()->disableIntroduction()) {
285 m_articleWidget->hide();
286 m_articleViewer->displayAboutPage();
287 m_mainFrame->slotSetTitle(i18n("About"));
288 m_displayingAboutPage = true;
291 m_fetchTimer = new QTimer(this);
292 connect(m_fetchTimer, &QTimer::timeout,
293 this, &MainWidget::slotDoIntervalFetches);
294 m_fetchTimer->start(1000 * 60);
296 // delete expired articles once per hour
297 m_expiryTimer = new QTimer(this);
298 connect(m_expiryTimer, &QTimer::timeout,
299 this, &MainWidget::slotDeleteExpiredArticles);
300 m_expiryTimer->start(3600 * 1000);
302 m_markReadTimer = new QTimer(this);
303 m_markReadTimer->setSingleShot(true);
304 connect(m_markReadTimer, &QTimer::timeout, this, &MainWidget::slotSetCurrentArticleReadDelayed);
306 setFeedList(QSharedPointer<FeedList>(new FeedList(Kernel::self()->storage())));
308 switch (Settings::viewMode()) {
309 case CombinedView:
310 slotCombinedView();
311 break;
312 case WidescreenView:
313 slotWidescreenView();
314 break;
315 default:
316 slotNormalView();
319 if (!Settings::resetQuickFilterOnNodeChange()) {
320 m_searchBar->slotSetStatus(Settings::statusFilter());
321 m_searchBar->slotSetText(Settings::textFilter());
325 void MainWidget::slotOnShutdown()
327 disconnect(m_tabWidget, &TabWidget::signalCurrentFrameChanged,
328 this, &MainWidget::slotCurrentFrameChanged);
330 m_shuttingDown = true;
332 // close all pageviewers in a controlled way
333 // fixes bug 91660, at least when no part loading data
334 while (m_tabWidget->count() > 1) { // remove frames until only the main frame remains
335 m_tabWidget->setCurrentIndex(m_tabWidget->count() - 1); // select last page
336 m_tabWidget->slotRemoveCurrentFrame();
339 Kernel::self()->fetchQueue()->slotAbort();
340 setFeedList(QSharedPointer<FeedList>());
342 delete m_feedListManagementInterface;
343 delete m_feedListView; // call delete here, so that the header settings will get saved
344 delete m_articleListView; // same for this one
346 delete m_mainTab;
347 delete m_mainFrame;
348 m_mainFrame = 0;
350 Settings::self()->save();
353 void MainWidget::saveSettings()
355 const QList<int> spl1 = m_horizontalSplitter->sizes();
356 if (std::count(spl1.begin(), spl1.end(), 0) == 0) {
357 Settings::setSplitter1Sizes(spl1);
359 const QList<int> spl2 = m_articleSplitter->sizes();
360 if (std::count(spl2.begin(), spl2.end(), 0) == 0) {
361 Settings::setSplitter2Sizes(spl2);
363 Settings::setViewMode(m_viewMode);
364 Settings::self()->save();
366 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
367 void MainWidget::connectFrame(Akregator::WebEngineFrame *frame)
369 connect(m_tabWidget, &TabWidget::signalCopyInFrame, frame, &WebEngineFrame::slotCopyInFrame);
370 connect(m_tabWidget, &TabWidget::signalPrintInFrame, frame, &WebEngineFrame::slotPrintInFrame);
371 connect(m_tabWidget, &TabWidget::signalZoomChangedInFrame, frame, &WebEngineFrame::slotZoomChangeInFrame);
372 connect(m_tabWidget, &TabWidget::signalZoomTextOnlyInFrame, frame, &WebEngineFrame::slotZoomTextOnlyInFrame);
373 connect(m_tabWidget, &TabWidget::signalPrintPreviewInFrame, frame, &WebEngineFrame::slotPrintPreviewInFrame);
374 connect(m_tabWidget, &TabWidget::signalFindTextInFrame, frame, &WebEngineFrame::slotFindTextInFrame);
375 connect(m_tabWidget, &TabWidget::signalTextToSpeechInFrame, frame, &WebEngineFrame::slotTextToSpeechInFrame);
376 connect(m_tabWidget, &TabWidget::signalSaveLinkAsInFrame, frame, &WebEngineFrame::slotSaveLinkAsInFrame);
377 connect(m_tabWidget, &TabWidget::signalCopyLinkAsInFrame, frame, &WebEngineFrame::slotCopyLinkAsInFrame);
378 connect(m_tabWidget, &TabWidget::signalCopyImageLocation, frame, &WebEngineFrame::slotCopyImageLocationInFrame);
379 connect(m_tabWidget, &TabWidget::signalSaveImageOnDisk, frame, &WebEngineFrame::slotSaveImageOnDiskInFrame);
380 connect(m_tabWidget, &TabWidget::signalBlockImage, frame, &WebEngineFrame::slotBlockImageInFrame);
381 connect(m_tabWidget, &TabWidget::signalExpandUrl, m_mainFrame, &WebEngineFrame::slotExpandUrlInFrame);
383 connect(frame, &WebEngineFrame::showStatusBarMessage, this, &MainWidget::slotShowStatusBarMessage);
384 connect(frame, &WebEngineFrame::signalIconChanged, m_tabWidget, &TabWidget::slotSetIcon);
387 #else
388 void MainWidget::connectFrame(WebViewFrame *frame)
390 connect(m_tabWidget, &TabWidget::signalCopyInFrame, frame, &WebViewFrame::slotCopyInFrame);
391 connect(m_tabWidget, &TabWidget::signalPrintInFrame, frame, &WebViewFrame::slotPrintInFrame);
392 connect(m_tabWidget, &TabWidget::signalZoomChangedInFrame, frame, &WebViewFrame::slotZoomChangeInFrame);
393 connect(m_tabWidget, &TabWidget::signalZoomTextOnlyInFrame, frame, &WebViewFrame::slotZoomTextOnlyInFrame);
394 connect(m_tabWidget, &TabWidget::signalPrintPreviewInFrame, frame, &WebViewFrame::slotPrintPreviewInFrame);
395 connect(m_tabWidget, &TabWidget::signalFindTextInFrame, frame, &WebViewFrame::slotFindTextInFrame);
396 connect(m_tabWidget, &TabWidget::signalTextToSpeechInFrame, frame, &WebViewFrame::slotTextToSpeechInFrame);
397 connect(m_tabWidget, &TabWidget::signalSaveLinkAsInFrame, frame, &WebViewFrame::slotSaveLinkAsInFrame);
398 connect(m_tabWidget, &TabWidget::signalCopyLinkAsInFrame, frame, &WebViewFrame::slotCopyLinkAsInFrame);
399 connect(m_tabWidget, &TabWidget::signalCopyImageLocation, frame, &WebViewFrame::slotCopyImageLocationInFrame);
400 connect(m_tabWidget, &TabWidget::signalSaveImageOnDisk, frame, &WebViewFrame::slotSaveImageOnDiskInFrame);
401 connect(m_tabWidget, &TabWidget::signalBlockImage, frame, &WebViewFrame::slotBlockImageInFrame);
402 connect(m_tabWidget, &TabWidget::signalExpandUrl, frame, &WebViewFrame::slotExpandUrlInFrame);
404 connect(frame, &WebViewFrame::showStatusBarMessage, this, &MainWidget::slotShowStatusBarMessage);
405 connect(frame, &WebViewFrame::signalIconChanged, m_tabWidget, &TabWidget::slotSetIcon);
407 #endif
409 void MainWidget::slotRequestNewFrame(int &frameId)
411 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
412 WebEngineFrame *frame = new WebEngineFrame(m_actionManager->actionCollection(), m_tabWidget);
413 #else
414 WebViewFrame *frame = new WebViewFrame(m_actionManager->actionCollection(), m_tabWidget);
415 #endif
416 connectFrame(frame);
418 Kernel::self()->frameManager()->slotAddFrame(frame);
420 frameId = frame->id();
423 void MainWidget::sendArticle(bool attach)
425 QByteArray text;
426 QString title;
428 Frame *frame = Kernel::self()->frameManager()->currentFrame();
430 if (frame && frame->id() > 0) { // are we in some other tab than the articlelist?
431 text = frame->url().toString().toLatin1();
432 title = frame->title();
433 } else { // nah, we're in articlelist..
434 const Article article = m_selectionController->currentArticle();
435 if (!article.isNull()) {
436 text = article.link().toDisplayString().toLatin1();
437 title = Akregator::Utils::convertHtmlTags(article.title());
441 if (text.isEmpty()) {
442 return;
444 sendArticle(text, title, attach);
447 void MainWidget::cleanUpDownloadFile()
449 Q_FOREACH (QPointer<Akregator::DownloadArticleJob> job, mListDownloadArticleJobs) {
450 if (job) {
451 job->forceCleanupTemporaryFile();
456 void MainWidget::sendArticle(const QByteArray &text, const QString &title, bool attach)
458 if (attach) {
459 QPointer<Akregator::DownloadArticleJob> download = new Akregator::DownloadArticleJob(this);
460 download->setArticleUrl(QUrl(QString::fromUtf8(text)));
461 download->setText(QString::fromUtf8(text));
462 download->setTitle(title);
463 mListDownloadArticleJobs.append(download);
464 download->start();
465 } else {
466 QUrlQuery query;
467 query.addQueryItem(QStringLiteral("subject"), title);
468 query.addQueryItem(QStringLiteral("body"), QString::fromUtf8(text));
469 QUrl url;
470 url.setScheme(QStringLiteral("mailto"));
471 url.setQuery(query);
472 QDesktopServices::openUrl(url);
476 void MainWidget::importFeedList(const QDomDocument &doc)
478 ImportFeedListCommand *cmd = new ImportFeedListCommand;
479 cmd->setParentWidget(this);
480 cmd->setFeedListDocument(doc);
481 cmd->setTargetList(m_feedList);
482 cmd->start();
485 void MainWidget::setFeedList(const QSharedPointer<FeedList> &list)
487 if (list == m_feedList) {
488 return;
490 const QSharedPointer<FeedList> oldList = m_feedList;
492 m_feedList = list;
493 if (m_feedList) {
494 connect(m_feedList.data(), &FeedList::unreadCountChanged,
495 this, &MainWidget::slotSetTotalUnread);
498 slotSetTotalUnread();
500 m_feedListManagementInterface->setFeedList(m_feedList);
501 Kernel::self()->setFeedList(m_feedList);
502 ProgressManager::self()->setFeedList(m_feedList);
503 m_selectionController->setFeedList(m_feedList);
505 if (oldList) {
506 oldList->disconnect(this);
509 slotDeleteExpiredArticles();
512 void MainWidget::deleteExpiredArticles(const QSharedPointer<FeedList> &list)
514 if (!list) {
515 return;
517 ExpireItemsCommand *cmd = new ExpireItemsCommand(this);
518 cmd->setParentWidget(this);
519 cmd->setFeedList(list);
520 cmd->setFeeds(list->feedIds());
521 cmd->start();
524 void MainWidget::slotDeleteExpiredArticles()
526 deleteExpiredArticles(m_feedList);
529 QDomDocument MainWidget::feedListToOPML()
531 QDomDocument dom;
532 if (m_feedList) {
533 dom = m_feedList->toOpml();
535 return dom;
538 void MainWidget::addFeedToGroup(const QString &url, const QString &groupName)
540 // Locate the group.
541 QList<TreeNode *> namedGroups = m_feedList->findByTitle(groupName);
542 Folder *group = 0;
543 foreach (TreeNode *const candidate, namedGroups) {
544 if (candidate->isGroup()) {
545 group = static_cast<Folder *>(candidate);
546 break;
550 if (!group) {
551 Folder *g = new Folder(groupName);
552 m_feedList->allFeedsFolder()->appendChild(g);
553 group = g;
556 // Invoke the Add Feed dialog with url filled in.
557 addFeed(url, 0, group, true);
560 void MainWidget::slotNormalView()
562 if (m_viewMode == NormalView) {
563 return;
566 if (m_viewMode == CombinedView) {
567 m_articleWidget->show();
569 const Article article = m_selectionController->currentArticle();
571 if (!article.isNull()) {
572 m_articleViewer->showArticle(article);
573 } else {
574 m_articleViewer->slotShowSummary(m_selectionController->selectedSubscription());
578 m_articleSplitter->setOrientation(Qt::Vertical);
579 m_viewMode = NormalView;
581 Settings::setViewMode(m_viewMode);
584 void MainWidget::slotWidescreenView()
586 if (m_viewMode == WidescreenView) {
587 return;
590 if (m_viewMode == CombinedView) {
591 m_articleWidget->show();
593 Article article = m_selectionController->currentArticle();
595 if (!article.isNull()) {
596 m_articleViewer->showArticle(article);
597 } else {
598 m_articleViewer->slotShowSummary(m_selectionController->selectedSubscription());
602 m_articleSplitter->setOrientation(Qt::Horizontal);
603 m_viewMode = WidescreenView;
605 Settings::setViewMode(m_viewMode);
608 void MainWidget::slotCombinedView()
610 if (m_viewMode == CombinedView) {
611 return;
614 m_articleListView->slotClear();
615 m_articleWidget->hide();
616 m_viewMode = CombinedView;
618 Settings::setViewMode(m_viewMode);
621 void MainWidget::slotMoveCurrentNodeUp()
623 TreeNode *current = m_selectionController->selectedSubscription();
624 if (!current) {
625 return;
627 TreeNode *prev = current->prevSibling();
628 Folder *parent = current->parent();
630 if (!prev || !parent) {
631 return;
634 parent->removeChild(prev);
635 parent->insertChild(prev, current);
636 m_feedListView->ensureNodeVisible(current);
639 void MainWidget::slotMoveCurrentNodeDown()
641 TreeNode *current = m_selectionController->selectedSubscription();
642 if (!current) {
643 return;
645 TreeNode *next = current->nextSibling();
646 Folder *parent = current->parent();
648 if (!next || !parent) {
649 return;
652 parent->removeChild(current);
653 parent->insertChild(current, next);
654 m_feedListView->ensureNodeVisible(current);
657 void MainWidget::slotMoveCurrentNodeLeft()
659 TreeNode *current = m_selectionController->selectedSubscription();
660 if (!current || !current->parent() || !current->parent()->parent()) {
661 return;
664 Folder *parent = current->parent();
665 Folder *grandparent = current->parent()->parent();
667 parent->removeChild(current);
668 grandparent->insertChild(current, parent);
669 m_feedListView->ensureNodeVisible(current);
672 void MainWidget::slotMoveCurrentNodeRight()
674 TreeNode *current = m_selectionController->selectedSubscription();
675 if (!current || !current->parent()) {
676 return;
678 TreeNode *prev = current->prevSibling();
680 if (prev && prev->isGroup()) {
681 Folder *fg = static_cast<Folder *>(prev);
682 current->parent()->removeChild(current);
683 fg->appendChild(current);
684 m_feedListView->ensureNodeVisible(current);
688 void MainWidget::slotSendLink()
690 sendArticle();
693 void MainWidget::slotSendFile()
695 sendArticle(true);
698 void MainWidget::slotNodeSelected(TreeNode *node)
700 m_markReadTimer->stop();
702 if (m_displayingAboutPage) {
703 m_mainFrame->slotSetTitle(i18n("Articles"));
704 if (m_viewMode != CombinedView) {
705 m_articleWidget->show();
707 if (Settings::showQuickFilter()) {
708 m_searchBar->show();
710 m_displayingAboutPage = false;
713 m_tabWidget->setCurrentWidget(m_mainFrame);
714 if (Settings::resetQuickFilterOnNodeChange()) {
715 m_searchBar->slotClearSearch();
718 if (m_viewMode == CombinedView) {
719 m_articleViewer->showNode(node);
720 } else {
721 m_articleViewer->slotShowSummary(node);
724 if (node) {
725 m_mainFrame->setWindowTitle(node->title());
728 m_actionManager->slotNodeSelected(node);
731 void MainWidget::slotFeedAdd()
733 Folder *group = 0;
734 if (!m_selectionController->selectedSubscription()) {
735 group = m_feedList->allFeedsFolder();
736 } else {
737 if (m_selectionController->selectedSubscription()->isGroup()) {
738 group = static_cast<Folder *>(m_selectionController->selectedSubscription());
739 } else {
740 group = m_selectionController->selectedSubscription()->parent();
745 TreeNode *const lastChild = !group->children().isEmpty() ? group->children().last() : 0;
747 addFeed(QString(), lastChild, group, false);
750 void MainWidget::addFeed(const QString &url, TreeNode *after, Folder *parent, bool autoExec)
752 CreateFeedCommand *cmd(new CreateFeedCommand(this));
753 cmd->setParentWidget(this);
754 cmd->setPosition(parent, after);
755 cmd->setRootFolder(m_feedList->allFeedsFolder());
756 cmd->setAutoExecute(autoExec);
757 cmd->setUrl(url);
758 cmd->setSubscriptionListView(m_feedListView);
759 cmd->start();
762 void MainWidget::slotFeedAddGroup()
764 CreateFolderCommand *cmd = new CreateFolderCommand(this);
765 cmd->setParentWidget(this);
766 cmd->setSelectedSubscription(m_selectionController->selectedSubscription());
767 cmd->setRootFolder(m_feedList->allFeedsFolder());
768 cmd->setSubscriptionListView(m_feedListView);
769 cmd->start();
772 void MainWidget::slotFeedRemove()
774 TreeNode *selectedNode = m_selectionController->selectedSubscription();
776 // don't delete root element! (safety valve)
777 if (!selectedNode || selectedNode == m_feedList->allFeedsFolder()) {
778 return;
781 DeleteSubscriptionCommand *cmd = new DeleteSubscriptionCommand(this);
782 cmd->setParentWidget(this);
783 cmd->setSubscription(m_feedList, selectedNode->id());
784 cmd->start();
787 void MainWidget::slotFeedModify()
789 TreeNode *const node = m_selectionController->selectedSubscription();
790 if (!node) {
791 return;
793 EditSubscriptionCommand *cmd = new EditSubscriptionCommand(this);
794 cmd->setParentWidget(this);
795 cmd->setSubscription(m_feedList, node->id());
796 cmd->setSubscriptionListView(m_feedListView);
797 cmd->start();
800 void MainWidget::slotNextUnreadArticle()
802 ensureArticleTabVisible();
803 if (m_viewMode == CombinedView) {
804 m_feedListView->slotNextUnreadFeed();
805 return;
807 TreeNode *sel = m_selectionController->selectedSubscription();
808 if (sel && sel->unread() > 0) {
809 m_articleListView->slotNextUnreadArticle();
810 } else {
811 m_feedListView->slotNextUnreadFeed();
815 void MainWidget::slotPrevUnreadArticle()
817 ensureArticleTabVisible();
818 if (m_viewMode == CombinedView) {
819 m_feedListView->slotPrevUnreadFeed();
820 return;
822 TreeNode *sel = m_selectionController->selectedSubscription();
823 if (sel && sel->unread() > 0) {
824 m_articleListView->slotPreviousUnreadArticle();
825 } else {
826 m_feedListView->slotPrevUnreadFeed();
830 void MainWidget::slotMarkAllFeedsRead()
832 KJob *job = m_feedList->createMarkAsReadJob();
833 connect(job, &KJob::finished, m_selectionController, &AbstractSelectionController::forceFilterUpdate);
834 job->start();
837 void MainWidget::slotMarkAllRead()
839 if (!m_selectionController->selectedSubscription()) {
840 return;
842 KJob *job = m_selectionController->selectedSubscription()->createMarkAsReadJob();
843 connect(job, &KJob::finished, m_selectionController, &AbstractSelectionController::forceFilterUpdate);
844 job->start();
847 void MainWidget::slotSetTotalUnread()
849 Q_EMIT signalUnreadCountChanged(m_feedList ? m_feedList->unread() : 0);
852 void MainWidget::slotDoIntervalFetches()
854 if (!m_feedList) {
855 return;
857 #if 0
858 // the following solid check apparently doesn't work reliably and causes
859 // interval fetching not working although the user is actually online (but solid reports he's not
860 const Networking::Status status = Solid::Networking::status();
861 if (status != Networking::Connected && status != Networking::Unknown) {
862 return;
864 #endif
865 m_feedList->addToFetchQueue(Kernel::self()->fetchQueue(), true);
868 void MainWidget::slotFetchCurrentFeed()
870 if (!m_selectionController->selectedSubscription()) {
871 return;
873 if (isNetworkAvailable()) {
874 m_selectionController->selectedSubscription()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
875 } else {
876 m_mainFrame->slotSetStatusText(i18n("Networking is not available."));
880 void MainWidget::slotFetchAllFeeds()
882 if (m_feedList && isNetworkAvailable()) {
883 m_feedList->addToFetchQueue(Kernel::self()->fetchQueue());
884 } else if (m_feedList) {
885 m_mainFrame->slotSetStatusText(i18n("Networking is not available."));
889 void MainWidget::slotFetchingStarted()
891 m_mainFrame->slotSetState(Frame::Started);
892 m_actionManager->action(QStringLiteral("feed_stop"))->setEnabled(true);
893 m_mainFrame->slotSetStatusText(i18n("Fetching Feeds..."));
896 void MainWidget::slotFetchingStopped()
898 m_mainFrame->slotSetState(Frame::Completed);
899 m_actionManager->action(QStringLiteral("feed_stop"))->setEnabled(false);
900 m_mainFrame->slotSetStatusText(QString());
903 void MainWidget::slotArticleSelected(const Akregator::Article &article)
905 if (m_viewMode == CombinedView) {
906 return;
909 m_markReadTimer->stop();
911 Q_ASSERT(article.isNull() || article.feed());
913 QVector<Article> articles = m_selectionController->selectedArticles();
914 Q_EMIT signalArticlesSelected(articles);
916 KToggleAction *const maai = qobject_cast<KToggleAction *>(m_actionManager->action(QStringLiteral("article_set_status_important")));
917 Q_ASSERT(maai);
918 maai->setChecked(article.keep());
920 m_articleViewer->showArticle(article);
921 if (m_selectionController->selectedArticles().count() == 0) {
922 m_articleListView->setCurrentIndex(m_selectionController->currentArticleIndex());
925 if (article.isNull() || article.status() == Akregator::Read) {
926 return;
929 if (!Settings::useMarkReadDelay()) {
930 return;
933 const int delay = Settings::markReadDelay();
935 if (delay > 0) {
936 m_markReadTimer->start(delay * 1000);
937 } else {
938 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
939 const Akregator::ArticleId aid = { article.feed()->xmlUrl(), article.guid() };
940 job->setStatus(aid, Akregator::Read);
941 job->start();
945 void MainWidget::slotMouseButtonPressed(int button, const QUrl &url)
947 if (button != Qt::MidButton) {
948 return;
951 if (!url.isValid()) {
952 return;
955 OpenUrlRequest req(url);
957 switch (Settings::mMBBehaviour()) {
958 case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
959 req.setOptions(OpenUrlRequest::ExternalBrowser);
960 break;
961 case Settings::EnumMMBBehaviour::OpenInBackground:
962 req.setOptions(OpenUrlRequest::NewTab);
963 req.setOpenInBackground(true);
964 break;
965 default:
966 req.setOptions(OpenUrlRequest::NewTab);
967 req.setOpenInBackground(false);
970 Kernel::self()->frameManager()->slotOpenUrlRequest(req);
973 void MainWidget::slotOpenHomepage()
975 Feed *feed = dynamic_cast<Feed *>(m_selectionController->selectedSubscription());
977 if (!feed) {
978 return;
981 QUrl url(feed->htmlUrl());
983 if (url.isValid()) {
984 OpenUrlRequest req(feed->htmlUrl());
985 req.setOptions(OpenUrlRequest::ExternalBrowser);
986 Kernel::self()->frameManager()->slotOpenUrlRequest(req);
990 void MainWidget::slotOpenSelectedArticlesInBrowser()
992 const QVector<Article> articles = m_selectionController->selectedArticles();
994 Q_FOREACH (const Akregator::Article &article, articles) {
995 slotOpenArticleInBrowser(article);
999 void MainWidget::slotOpenArticleInBrowser(const Akregator::Article &article)
1001 if (!article.isNull() && article.link().isValid()) {
1002 OpenUrlRequest req(article.link());
1003 req.setOptions(OpenUrlRequest::ExternalBrowser);
1004 Kernel::self()->frameManager()->slotOpenUrlRequest(req);
1008 void MainWidget::openSelectedArticles(bool openInBackground)
1010 const QVector<Article> articles = m_selectionController->selectedArticles();
1012 Q_FOREACH (const Akregator::Article &article, articles) {
1013 const QUrl url = article.link();
1014 if (!url.isValid()) {
1015 continue;
1018 OpenUrlRequest req(url);
1019 req.setOptions(OpenUrlRequest::NewTab);
1020 if (openInBackground) {
1021 req.setOpenInBackground(true);
1022 Kernel::self()->frameManager()->slotOpenUrlRequest(req, false /*don't use settings for open in background*/);
1023 } else {
1024 Kernel::self()->frameManager()->slotOpenUrlRequest(req);
1030 void MainWidget::currentArticleInfo(QString &link, QString &title)
1032 const Article article = m_selectionController->currentArticle();
1034 if (article.isNull()) {
1035 return;
1037 if (article.link().isValid()) {
1038 link = article.link().url();
1039 title = Utils::convertHtmlTags(article.title());
1043 void MainWidget::updateQuickSearchLineText()
1045 m_searchBar->updateQuickSearchLineText(m_actionManager->quickSearchLineText());
1048 void MainWidget::slotCopyLinkAddress()
1050 const Article article = m_selectionController->currentArticle();
1052 if (article.isNull()) {
1053 return;
1056 QString link;
1057 if (article.link().isValid()) {
1058 link = article.link().url();
1059 QClipboard *cb = QApplication::clipboard();
1060 cb->setText(link, QClipboard::Clipboard);
1061 // don't set url to selection as it's a no-no according to a fd.o spec
1062 //cb->setText(link, QClipboard::Selection);
1066 void MainWidget::slotToggleShowQuickFilter()
1068 if (Settings::showQuickFilter()) {
1069 Settings::setShowQuickFilter(false);
1070 m_searchBar->slotClearSearch();
1071 m_searchBar->hide();
1072 } else {
1073 Settings::setShowQuickFilter(true);
1074 if (!m_displayingAboutPage) {
1075 m_searchBar->show();
1081 void MainWidget::slotArticleDelete()
1084 if (m_viewMode == CombinedView) {
1085 return;
1088 const QVector<Article> articles = m_selectionController->selectedArticles();
1090 QString msg;
1091 switch (articles.count()) {
1092 case 0:
1093 return;
1094 case 1:
1095 msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>", articles.first().title());
1096 break;
1097 default:
1098 msg = i18np("<qt>Are you sure you want to delete the selected article?</qt>", "<qt>Are you sure you want to delete the %1 selected articles?</qt>", articles.count());
1101 if (KMessageBox::warningContinueCancel(this,
1102 msg, i18n("Delete Article"),
1103 KStandardGuiItem::del(),
1104 KStandardGuiItem::cancel(),
1105 QStringLiteral("Disable delete article confirmation")) != KMessageBox::Continue) {
1106 return;
1109 TreeNode *const selected = m_selectionController->selectedSubscription();
1111 if (selected) {
1112 selected->setNotificationMode(false);
1115 Akregator::ArticleDeleteJob *job = new Akregator::ArticleDeleteJob;
1116 Q_FOREACH (const Akregator::Article &i, articles) {
1117 Feed *const feed = i.feed();
1118 if (!feed) {
1119 continue;
1121 const Akregator::ArticleId aid = { feed->xmlUrl(), i.guid() };
1122 job->appendArticleId(aid);
1125 job->start();
1127 if (selected) {
1128 selected->setNotificationMode(true);
1132 void MainWidget::slotFramesChanged()
1134 // We need to wait till the frame is fully loaded
1135 QMetaObject::invokeMethod(m_part, "slotAutoSave", Qt::QueuedConnection);
1138 void MainWidget::slotArticleToggleKeepFlag(bool)
1140 const QVector<Article> articles = m_selectionController->selectedArticles();
1142 if (articles.isEmpty()) {
1143 return;
1146 bool allFlagsSet = true;
1147 Q_FOREACH (const Akregator::Article &i, articles) {
1148 allFlagsSet = allFlagsSet && i.keep();
1149 if (!allFlagsSet) {
1150 break;
1154 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
1155 Q_FOREACH (const Akregator::Article &i, articles) {
1156 const Akregator::ArticleId aid = { i.feed()->xmlUrl(), i.guid() };
1157 job->setKeep(aid, !allFlagsSet);
1159 job->start();
1162 namespace
1165 void setArticleStatus(const QString &feedUrl, const QString &articleId, int status)
1167 if (!feedUrl.isEmpty() && !articleId.isEmpty()) {
1168 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
1169 const Akregator::ArticleId aid = { feedUrl, articleId };
1170 job->setStatus(aid, status);
1171 job->start();
1175 void setSelectedArticleStatus(const Akregator::AbstractSelectionController *controller, int status)
1177 const QVector<Akregator::Article> articles = controller->selectedArticles();
1179 if (articles.isEmpty()) {
1180 return;
1183 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
1184 Q_FOREACH (const Akregator::Article &i, articles) {
1185 const Akregator::ArticleId aid = { i.feed()->xmlUrl(), i.guid() };
1186 job->setStatus(aid, status);
1188 job->start();
1193 void MainWidget::slotSetSelectedArticleRead()
1195 ::setSelectedArticleStatus(m_selectionController, Akregator::Read);
1198 void MainWidget::slotSetSelectedArticleUnread()
1200 ::setSelectedArticleStatus(m_selectionController, Akregator::Unread);
1203 void MainWidget::slotSetSelectedArticleNew()
1205 ::setSelectedArticleStatus(m_selectionController, Akregator::New);
1208 void MainWidget::slotSetCurrentArticleReadDelayed()
1210 const Article article = m_selectionController->currentArticle();
1212 if (article.isNull()) {
1213 return;
1216 Akregator::ArticleModifyJob *const job = new Akregator::ArticleModifyJob;
1217 const Akregator::ArticleId aid = { article.feed()->xmlUrl(), article.guid() };
1218 job->setStatus(aid, Akregator::Read);
1219 job->start();
1222 void MainWidget::slotShowStatusBarMessage(const QString &msg)
1224 KPIM::BroadcastStatus::instance()->setStatusMsg(msg);
1227 void MainWidget::readProperties(const KConfigGroup &config)
1229 if (!Settings::resetQuickFilterOnNodeChange()) {
1230 // read filter settings
1231 m_searchBar->slotSetText(config.readEntry("searchLine"));
1232 m_searchBar->slotSetStatus(config.readEntry("searchCombo").toInt());
1234 // Reopen tabs
1235 QStringList childList = config.readEntry(QStringLiteral("Children"),
1236 QStringList());
1237 Q_FOREACH (const QString &framePrefix, childList) {
1238 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1239 WebEngineFrame *const frame = new WebEngineFrame(m_actionManager->actionCollection(), m_tabWidget);
1240 #else
1241 WebViewFrame *const frame = new WebViewFrame(m_actionManager->actionCollection(), m_tabWidget);
1242 #endif
1243 frame->loadConfig(config, framePrefix + QLatin1Char('_'));
1245 connectFrame(frame);
1246 Kernel::self()->frameManager()->slotAddFrame(frame);
1251 void MainWidget::saveProperties(KConfigGroup &config)
1253 // save filter settings
1254 config.writeEntry("searchLine", m_searchBar->text());
1255 config.writeEntry("searchCombo", m_searchBar->status());
1257 Kernel::self()->frameManager()->saveProperties(config);
1260 void MainWidget::ensureArticleTabVisible()
1262 m_tabWidget->setCurrentWidget(m_mainFrame);
1265 void MainWidget::slotReloadAllTabs()
1267 m_tabWidget->slotReloadAllTabs();
1270 bool MainWidget::isNetworkAvailable() const
1272 return m_networkConfigManager->isOnline();
1275 void MainWidget::slotNetworkStatusChanged(bool status)
1277 if (status) {
1278 m_mainFrame->slotSetStatusText(i18n("Networking is available now."));
1279 this->slotFetchAllFeeds();
1280 } else {
1281 m_mainFrame->slotSetStatusText(i18n("Networking is not available."));
1285 void MainWidget::slotOpenSelectedArticles()
1287 openSelectedArticles(false);
1290 void MainWidget::slotOpenSelectedArticlesInBackground()
1292 openSelectedArticles(true);
1295 void MainWidget::slotCurrentFrameChanged(int frameId)
1297 Kernel::self()->frameManager()->slotChangeFrame(frameId);
1298 m_actionManager->zoomActionMenu()->setZoomFactor(Kernel::self()->frameManager()->currentFrame()->zoomFactor() * 100);
1299 m_actionManager->zoomActionMenu()->setZoomTextOnly(Kernel::self()->frameManager()->currentFrame()->zoomTextOnlyInFrame());
1302 void MainWidget::slotFocusQuickSearch()
1304 m_searchBar->setFocusSearchLine();
1306 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1307 void MainWidget::slotArticleAction(Akregator::ArticleViewerWebEngine::ArticleAction type, const QString &articleId, const QString &feed)
1308 #else
1309 void MainWidget::slotArticleAction(ArticleViewerNg::ArticleAction type, const QString &articleId, const QString &feed)
1310 #endif
1312 switch (type) {
1313 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1314 case ArticleViewerWebEngine::DeleteAction: {
1315 #else
1316 case ArticleViewerNg::DeleteAction: {
1317 #endif
1318 Akregator::ArticleDeleteJob *job = new Akregator::ArticleDeleteJob;
1319 const Akregator::ArticleId aid = { feed, articleId };
1320 job->appendArticleId(aid);
1321 job->start();
1322 break;
1324 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1325 case ArticleViewerWebEngine::MarkAsRead:
1326 #else
1327 case ArticleViewerNg::MarkAsRead:
1328 #endif
1329 ::setArticleStatus(feed, articleId, Akregator::Read);
1330 break;
1331 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1332 case ArticleViewerWebEngine::MarkAsUnRead:
1333 #else
1334 case ArticleViewerNg::MarkAsUnRead:
1335 #endif
1336 ::setArticleStatus(feed, articleId, Akregator::Unread);
1337 break;
1339 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1340 case ArticleViewerWebEngine::MarkAsImportant: {
1341 #else
1342 case ArticleViewerNg::MarkAsImportant: {
1343 #endif
1344 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
1345 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1346 const Akregator::ArticleId aid = { feed, articleId };
1347 job->setKeep(aid, !article.keep());
1348 job->start();
1349 break;
1351 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1352 case ArticleViewerWebEngine::SendUrlArticle: {
1353 #else
1354 case ArticleViewerNg::SendUrlArticle: {
1355 #endif
1356 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1357 case ArticleViewerWebEngine::SendFileArticle:
1358 #else
1359 case ArticleViewerNg::SendFileArticle:
1360 #endif
1361 const Article article = m_feedList->findArticle(feed, articleId);
1362 const QByteArray text = article.link().toDisplayString().toLatin1();
1363 const QString title = Akregator::Utils::convertHtmlTags(article.title());
1364 if (text.isEmpty()) {
1365 return;
1367 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1368 sendArticle(text, title, (type == ArticleViewerWebEngine::SendFileArticle));
1369 #else
1370 sendArticle(text, title, (type == ArticleViewerNg::SendFileArticle));
1371 #endif
1372 break;
1374 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1375 case ArticleViewerWebEngine::OpenInBackgroundTab: {
1376 #else
1377 case ArticleViewerNg::OpenInBackgroundTab: {
1378 #endif
1379 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1380 const QUrl url = article.link();
1381 if (url.isValid()) {
1382 OpenUrlRequest req(url);
1383 req.setOptions(OpenUrlRequest::NewTab);
1384 req.setOpenInBackground(true);
1385 Kernel::self()->frameManager()->slotOpenUrlRequest(req, false /*don't use settings for open in background*/);
1387 break;
1389 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1390 case ArticleViewerWebEngine::OpenInExternalBrowser: {
1391 #else
1392 case ArticleViewerNg::OpenInExternalBrowser: {
1393 #endif
1394 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1395 slotOpenArticleInBrowser(article);
1396 break;
1398 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1399 case ArticleViewerWebEngine::Share:
1400 #else
1401 case ArticleViewerNg::Share:
1402 #endif
1403 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1404 const QUrl url = article.link();
1405 if (url.isValid()) {
1406 //TODO
1408 break;