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"
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"
47 #include "feedpropertiesdialog.h"
48 #include "fetchqueue.h"
50 #include "framemanager.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"
62 #include "treenodevisitor.h"
64 #include "mainframe.h"
65 #include <MessageViewer/ZoomActionMenu>
66 #include "job/downloadarticlejob.h"
69 #include <kfileitem.h>
70 #include <KLocalizedString>
71 #include <kmessagebox.h>
75 #include <ktoggleaction.h>
79 #include <QNetworkConfigurationManager>
81 #include <QTextDocument>
82 #include <QDomDocument>
84 #include <QDesktopServices>
90 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
91 #include <webengine/webengineframe.h>
92 #include "articleviewer-ng/webengine/articleviewerwebenginewidgetng.h"
94 #include "webkit/webviewframe.h"
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
) {
109 MainWidget::MainWidget(Part
*part
, QWidget
*parent
, ActionManagerImpl
*actionManager
, const char *name
)
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);
123 m_shuttingDown
= false;
124 m_displayingAboutPage
= false;
125 setFocusPolicy(Qt::StrongFocus
);
127 QVBoxLayout
*lt
= new QVBoxLayout(this);
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()) {
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
);
257 connect(m_articleViewer
->articleViewerWidgetNg()->articleViewerNg(), &ArticleViewerNg::articleAction
, this, &MainWidget::slotArticleAction
);
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
);
272 Kernel::self()->frameManager()->slotAddFrame(m_mainFrame
);
274 const QList
<int> sp1sizes
= Settings::splitter1Sizes();
275 if (sp1sizes
.count() >= m_horizontalSplitter
->count()) {
276 m_horizontalSplitter
->setSizes(sp1sizes
);
278 const QList
<int> sp2sizes
= Settings::splitter2Sizes();
279 if (sp2sizes
.count() >= m_articleSplitter
->count()) {
280 m_articleSplitter
->setSizes(sp2sizes
);
283 if (!Settings::self()->disableIntroduction()) {
284 m_articleWidget
->hide();
285 m_articleViewer
->displayAboutPage();
286 m_mainFrame
->slotSetTitle(i18n("About"));
287 m_displayingAboutPage
= true;
290 m_fetchTimer
= new QTimer(this);
291 connect(m_fetchTimer
, &QTimer::timeout
,
292 this, &MainWidget::slotDoIntervalFetches
);
293 m_fetchTimer
->start(1000 * 60);
295 // delete expired articles once per hour
296 m_expiryTimer
= new QTimer(this);
297 connect(m_expiryTimer
, &QTimer::timeout
,
298 this, &MainWidget::slotDeleteExpiredArticles
);
299 m_expiryTimer
->start(3600 * 1000);
301 m_markReadTimer
= new QTimer(this);
302 m_markReadTimer
->setSingleShot(true);
303 connect(m_markReadTimer
, &QTimer::timeout
, this, &MainWidget::slotSetCurrentArticleReadDelayed
);
305 setFeedList(QSharedPointer
<FeedList
>(new FeedList(Kernel::self()->storage())));
307 switch (Settings::viewMode()) {
312 slotWidescreenView();
318 if (!Settings::resetQuickFilterOnNodeChange()) {
319 m_searchBar
->slotSetStatus(Settings::statusFilter());
320 m_searchBar
->slotSetText(Settings::textFilter());
324 void MainWidget::slotOnShutdown()
326 disconnect(m_tabWidget
, &TabWidget::signalCurrentFrameChanged
,
327 this, &MainWidget::slotCurrentFrameChanged
);
329 m_shuttingDown
= true;
331 // close all pageviewers in a controlled way
332 // fixes bug 91660, at least when no part loading data
333 while (m_tabWidget
->count() > 1) { // remove frames until only the main frame remains
334 m_tabWidget
->setCurrentIndex(m_tabWidget
->count() - 1); // select last page
335 m_tabWidget
->slotRemoveCurrentFrame();
338 Kernel::self()->fetchQueue()->slotAbort();
339 setFeedList(QSharedPointer
<FeedList
>());
341 delete m_feedListManagementInterface
;
342 delete m_feedListView
; // call delete here, so that the header settings will get saved
343 delete m_articleListView
; // same for this one
349 Settings::self()->save();
352 void MainWidget::saveSettings()
354 const QList
<int> spl1
= m_horizontalSplitter
->sizes();
355 if (std::count(spl1
.begin(), spl1
.end(), 0) == 0) {
356 Settings::setSplitter1Sizes(spl1
);
358 const QList
<int> spl2
= m_articleSplitter
->sizes();
359 if (std::count(spl2
.begin(), spl2
.end(), 0) == 0) {
360 Settings::setSplitter2Sizes(spl2
);
362 Settings::setViewMode(m_viewMode
);
363 Settings::self()->save();
365 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
366 void MainWidget::connectFrame(Akregator::WebEngineFrame
*frame
)
368 connect(m_tabWidget
, &TabWidget::signalCopyInFrame
, frame
, &WebEngineFrame::slotCopyInFrame
);
369 connect(m_tabWidget
, &TabWidget::signalPrintInFrame
, frame
, &WebEngineFrame::slotPrintInFrame
);
370 connect(m_tabWidget
, &TabWidget::signalZoomChangedInFrame
, frame
, &WebEngineFrame::slotZoomChangeInFrame
);
371 connect(m_tabWidget
, &TabWidget::signalZoomTextOnlyInFrame
, frame
, &WebEngineFrame::slotZoomTextOnlyInFrame
);
372 connect(m_tabWidget
, &TabWidget::signalPrintPreviewInFrame
, frame
, &WebEngineFrame::slotPrintPreviewInFrame
);
373 connect(m_tabWidget
, &TabWidget::signalFindTextInFrame
, frame
, &WebEngineFrame::slotFindTextInFrame
);
374 connect(m_tabWidget
, &TabWidget::signalTextToSpeechInFrame
, frame
, &WebEngineFrame::slotTextToSpeechInFrame
);
375 connect(m_tabWidget
, &TabWidget::signalSaveLinkAsInFrame
, frame
, &WebEngineFrame::slotSaveLinkAsInFrame
);
376 connect(m_tabWidget
, &TabWidget::signalCopyLinkAsInFrame
, frame
, &WebEngineFrame::slotCopyLinkAsInFrame
);
377 connect(m_tabWidget
, &TabWidget::signalCopyImageLocation
, frame
, &WebEngineFrame::slotCopyImageLocationInFrame
);
378 connect(m_tabWidget
, &TabWidget::signalSaveImageOnDisk
, frame
, &WebEngineFrame::slotSaveImageOnDiskInFrame
);
379 connect(m_tabWidget
, &TabWidget::signalBlockImage
, frame
, &WebEngineFrame::slotBlockImageInFrame
);
381 connect(frame
, &WebEngineFrame::showStatusBarMessage
, this, &MainWidget::slotShowStatusBarMessage
);
382 connect(frame
, &WebEngineFrame::signalIconChanged
, m_tabWidget
, &TabWidget::slotSetIcon
);
386 void MainWidget::connectFrame(WebViewFrame
*frame
)
388 connect(m_tabWidget
, &TabWidget::signalCopyInFrame
, frame
, &WebViewFrame::slotCopyInFrame
);
389 connect(m_tabWidget
, &TabWidget::signalPrintInFrame
, frame
, &WebViewFrame::slotPrintInFrame
);
390 connect(m_tabWidget
, &TabWidget::signalZoomChangedInFrame
, frame
, &WebViewFrame::slotZoomChangeInFrame
);
391 connect(m_tabWidget
, &TabWidget::signalZoomTextOnlyInFrame
, frame
, &WebViewFrame::slotZoomTextOnlyInFrame
);
392 connect(m_tabWidget
, &TabWidget::signalPrintPreviewInFrame
, frame
, &WebViewFrame::slotPrintPreviewInFrame
);
393 connect(m_tabWidget
, &TabWidget::signalFindTextInFrame
, frame
, &WebViewFrame::slotFindTextInFrame
);
394 connect(m_tabWidget
, &TabWidget::signalTextToSpeechInFrame
, frame
, &WebViewFrame::slotTextToSpeechInFrame
);
395 connect(m_tabWidget
, &TabWidget::signalSaveLinkAsInFrame
, frame
, &WebViewFrame::slotSaveLinkAsInFrame
);
396 connect(m_tabWidget
, &TabWidget::signalCopyLinkAsInFrame
, frame
, &WebViewFrame::slotCopyLinkAsInFrame
);
397 connect(m_tabWidget
, &TabWidget::signalCopyImageLocation
, frame
, &WebViewFrame::slotCopyImageLocationInFrame
);
398 connect(m_tabWidget
, &TabWidget::signalSaveImageOnDisk
, frame
, &WebViewFrame::slotSaveImageOnDiskInFrame
);
399 connect(m_tabWidget
, &TabWidget::signalBlockImage
, frame
, &WebViewFrame::slotBlockImageInFrame
);
401 connect(frame
, &WebViewFrame::showStatusBarMessage
, this, &MainWidget::slotShowStatusBarMessage
);
402 connect(frame
, &WebViewFrame::signalIconChanged
, m_tabWidget
, &TabWidget::slotSetIcon
);
406 void MainWidget::slotRequestNewFrame(int &frameId
)
408 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
409 WebEngineFrame
*frame
= new WebEngineFrame(m_actionManager
->actionCollection(), m_tabWidget
);
411 WebViewFrame
*frame
= new WebViewFrame(m_actionManager
->actionCollection(), m_tabWidget
);
415 Kernel::self()->frameManager()->slotAddFrame(frame
);
417 frameId
= frame
->id();
420 void MainWidget::sendArticle(bool attach
)
425 Frame
*frame
= Kernel::self()->frameManager()->currentFrame();
427 if (frame
&& frame
->id() > 0) { // are we in some other tab than the articlelist?
428 text
= frame
->url().toString().toLatin1();
429 title
= frame
->title();
430 } else { // nah, we're in articlelist..
431 const Article article
= m_selectionController
->currentArticle();
432 if (!article
.isNull()) {
433 text
= article
.link().toDisplayString().toLatin1();
434 title
= Akregator::Utils::convertHtmlTags(article
.title());
438 if (text
.isEmpty()) {
441 sendArticle(text
, title
, attach
);
444 void MainWidget::cleanUpDownloadFile()
446 Q_FOREACH (QPointer
<Akregator::DownloadArticleJob
> job
, mListDownloadArticleJobs
) {
448 job
->forceCleanupTemporaryFile();
453 void MainWidget::sendArticle(const QByteArray
&text
, const QString
&title
, bool attach
)
456 QPointer
<Akregator::DownloadArticleJob
> download
= new Akregator::DownloadArticleJob(this);
457 download
->setArticleUrl(QUrl(QString::fromUtf8(text
)));
458 download
->setText(QString::fromUtf8(text
));
459 download
->setTitle(title
);
460 mListDownloadArticleJobs
.append(download
);
464 query
.addQueryItem(QStringLiteral("subject"), title
);
465 query
.addQueryItem(QStringLiteral("body"), QString::fromUtf8(text
));
467 url
.setScheme(QStringLiteral("mailto"));
469 QDesktopServices::openUrl(url
);
473 void MainWidget::importFeedList(const QDomDocument
&doc
)
475 ImportFeedListCommand
*cmd
= new ImportFeedListCommand
;
476 cmd
->setParentWidget(this);
477 cmd
->setFeedListDocument(doc
);
478 cmd
->setTargetList(m_feedList
);
482 void MainWidget::setFeedList(const QSharedPointer
<FeedList
> &list
)
484 if (list
== m_feedList
) {
487 const QSharedPointer
<FeedList
> oldList
= m_feedList
;
491 connect(m_feedList
.data(), &FeedList::unreadCountChanged
,
492 this, &MainWidget::slotSetTotalUnread
);
495 slotSetTotalUnread();
497 m_feedListManagementInterface
->setFeedList(m_feedList
);
498 Kernel::self()->setFeedList(m_feedList
);
499 ProgressManager::self()->setFeedList(m_feedList
);
500 m_selectionController
->setFeedList(m_feedList
);
503 oldList
->disconnect(this);
506 slotDeleteExpiredArticles();
509 void MainWidget::deleteExpiredArticles(const QSharedPointer
<FeedList
> &list
)
514 ExpireItemsCommand
*cmd
= new ExpireItemsCommand(this);
515 cmd
->setParentWidget(this);
516 cmd
->setFeedList(list
);
517 cmd
->setFeeds(list
->feedIds());
521 void MainWidget::slotDeleteExpiredArticles()
523 deleteExpiredArticles(m_feedList
);
526 QDomDocument
MainWidget::feedListToOPML()
530 dom
= m_feedList
->toOpml();
535 void MainWidget::addFeedToGroup(const QString
&url
, const QString
&groupName
)
538 QList
<TreeNode
*> namedGroups
= m_feedList
->findByTitle(groupName
);
540 foreach (TreeNode
*const candidate
, namedGroups
) {
541 if (candidate
->isGroup()) {
542 group
= static_cast<Folder
*>(candidate
);
548 Folder
*g
= new Folder(groupName
);
549 m_feedList
->allFeedsFolder()->appendChild(g
);
553 // Invoke the Add Feed dialog with url filled in.
554 addFeed(url
, 0, group
, true);
557 void MainWidget::slotNormalView()
559 if (m_viewMode
== NormalView
) {
563 if (m_viewMode
== CombinedView
) {
564 m_articleWidget
->show();
566 const Article article
= m_selectionController
->currentArticle();
568 if (!article
.isNull()) {
569 m_articleViewer
->showArticle(article
);
571 m_articleViewer
->slotShowSummary(m_selectionController
->selectedSubscription());
575 m_articleSplitter
->setOrientation(Qt::Vertical
);
576 m_viewMode
= NormalView
;
578 Settings::setViewMode(m_viewMode
);
581 void MainWidget::slotWidescreenView()
583 if (m_viewMode
== WidescreenView
) {
587 if (m_viewMode
== CombinedView
) {
588 m_articleWidget
->show();
590 Article article
= m_selectionController
->currentArticle();
592 if (!article
.isNull()) {
593 m_articleViewer
->showArticle(article
);
595 m_articleViewer
->slotShowSummary(m_selectionController
->selectedSubscription());
599 m_articleSplitter
->setOrientation(Qt::Horizontal
);
600 m_viewMode
= WidescreenView
;
602 Settings::setViewMode(m_viewMode
);
605 void MainWidget::slotCombinedView()
607 if (m_viewMode
== CombinedView
) {
611 m_articleListView
->slotClear();
612 m_articleWidget
->hide();
613 m_viewMode
= CombinedView
;
615 Settings::setViewMode(m_viewMode
);
618 void MainWidget::slotMoveCurrentNodeUp()
620 TreeNode
*current
= m_selectionController
->selectedSubscription();
624 TreeNode
*prev
= current
->prevSibling();
625 Folder
*parent
= current
->parent();
627 if (!prev
|| !parent
) {
631 parent
->removeChild(prev
);
632 parent
->insertChild(prev
, current
);
633 m_feedListView
->ensureNodeVisible(current
);
636 void MainWidget::slotMoveCurrentNodeDown()
638 TreeNode
*current
= m_selectionController
->selectedSubscription();
642 TreeNode
*next
= current
->nextSibling();
643 Folder
*parent
= current
->parent();
645 if (!next
|| !parent
) {
649 parent
->removeChild(current
);
650 parent
->insertChild(current
, next
);
651 m_feedListView
->ensureNodeVisible(current
);
654 void MainWidget::slotMoveCurrentNodeLeft()
656 TreeNode
*current
= m_selectionController
->selectedSubscription();
657 if (!current
|| !current
->parent() || !current
->parent()->parent()) {
661 Folder
*parent
= current
->parent();
662 Folder
*grandparent
= current
->parent()->parent();
664 parent
->removeChild(current
);
665 grandparent
->insertChild(current
, parent
);
666 m_feedListView
->ensureNodeVisible(current
);
669 void MainWidget::slotMoveCurrentNodeRight()
671 TreeNode
*current
= m_selectionController
->selectedSubscription();
672 if (!current
|| !current
->parent()) {
675 TreeNode
*prev
= current
->prevSibling();
677 if (prev
&& prev
->isGroup()) {
678 Folder
*fg
= static_cast<Folder
*>(prev
);
679 current
->parent()->removeChild(current
);
680 fg
->appendChild(current
);
681 m_feedListView
->ensureNodeVisible(current
);
685 void MainWidget::slotSendLink()
690 void MainWidget::slotSendFile()
695 void MainWidget::slotNodeSelected(TreeNode
*node
)
697 m_markReadTimer
->stop();
699 if (m_displayingAboutPage
) {
700 m_mainFrame
->slotSetTitle(i18n("Articles"));
701 if (m_viewMode
!= CombinedView
) {
702 m_articleWidget
->show();
704 if (Settings::showQuickFilter()) {
707 m_displayingAboutPage
= false;
710 m_tabWidget
->setCurrentWidget(m_mainFrame
);
711 if (Settings::resetQuickFilterOnNodeChange()) {
712 m_searchBar
->slotClearSearch();
715 if (m_viewMode
== CombinedView
) {
716 m_articleViewer
->showNode(node
);
718 m_articleViewer
->slotShowSummary(node
);
722 m_mainFrame
->setWindowTitle(node
->title());
725 m_actionManager
->slotNodeSelected(node
);
728 void MainWidget::slotFeedAdd()
731 if (!m_selectionController
->selectedSubscription()) {
732 group
= m_feedList
->allFeedsFolder();
734 if (m_selectionController
->selectedSubscription()->isGroup()) {
735 group
= static_cast<Folder
*>(m_selectionController
->selectedSubscription());
737 group
= m_selectionController
->selectedSubscription()->parent();
742 TreeNode
*const lastChild
= !group
->children().isEmpty() ? group
->children().last() : 0;
744 addFeed(QString(), lastChild
, group
, false);
747 void MainWidget::addFeed(const QString
&url
, TreeNode
*after
, Folder
*parent
, bool autoExec
)
749 CreateFeedCommand
*cmd(new CreateFeedCommand(this));
750 cmd
->setParentWidget(this);
751 cmd
->setPosition(parent
, after
);
752 cmd
->setRootFolder(m_feedList
->allFeedsFolder());
753 cmd
->setAutoExecute(autoExec
);
755 cmd
->setSubscriptionListView(m_feedListView
);
759 void MainWidget::slotFeedAddGroup()
761 CreateFolderCommand
*cmd
= new CreateFolderCommand(this);
762 cmd
->setParentWidget(this);
763 cmd
->setSelectedSubscription(m_selectionController
->selectedSubscription());
764 cmd
->setRootFolder(m_feedList
->allFeedsFolder());
765 cmd
->setSubscriptionListView(m_feedListView
);
769 void MainWidget::slotFeedRemove()
771 TreeNode
*selectedNode
= m_selectionController
->selectedSubscription();
773 // don't delete root element! (safety valve)
774 if (!selectedNode
|| selectedNode
== m_feedList
->allFeedsFolder()) {
778 DeleteSubscriptionCommand
*cmd
= new DeleteSubscriptionCommand(this);
779 cmd
->setParentWidget(this);
780 cmd
->setSubscription(m_feedList
, selectedNode
->id());
784 void MainWidget::slotFeedModify()
786 TreeNode
*const node
= m_selectionController
->selectedSubscription();
790 EditSubscriptionCommand
*cmd
= new EditSubscriptionCommand(this);
791 cmd
->setParentWidget(this);
792 cmd
->setSubscription(m_feedList
, node
->id());
793 cmd
->setSubscriptionListView(m_feedListView
);
797 void MainWidget::slotNextUnreadArticle()
799 ensureArticleTabVisible();
800 if (m_viewMode
== CombinedView
) {
801 m_feedListView
->slotNextUnreadFeed();
804 TreeNode
*sel
= m_selectionController
->selectedSubscription();
805 if (sel
&& sel
->unread() > 0) {
806 m_articleListView
->slotNextUnreadArticle();
808 m_feedListView
->slotNextUnreadFeed();
812 void MainWidget::slotPrevUnreadArticle()
814 ensureArticleTabVisible();
815 if (m_viewMode
== CombinedView
) {
816 m_feedListView
->slotPrevUnreadFeed();
819 TreeNode
*sel
= m_selectionController
->selectedSubscription();
820 if (sel
&& sel
->unread() > 0) {
821 m_articleListView
->slotPreviousUnreadArticle();
823 m_feedListView
->slotPrevUnreadFeed();
827 void MainWidget::slotMarkAllFeedsRead()
829 KJob
*job
= m_feedList
->createMarkAsReadJob();
830 connect(job
, &KJob::finished
, m_selectionController
, &AbstractSelectionController::forceFilterUpdate
);
834 void MainWidget::slotMarkAllRead()
836 if (!m_selectionController
->selectedSubscription()) {
839 KJob
*job
= m_selectionController
->selectedSubscription()->createMarkAsReadJob();
840 connect(job
, &KJob::finished
, m_selectionController
, &AbstractSelectionController::forceFilterUpdate
);
844 void MainWidget::slotSetTotalUnread()
846 Q_EMIT
signalUnreadCountChanged(m_feedList
? m_feedList
->unread() : 0);
849 void MainWidget::slotDoIntervalFetches()
855 // the following solid check apparently doesn't work reliably and causes
856 // interval fetching not working although the user is actually online (but solid reports he's not
857 const Networking::Status status
= Solid::Networking::status();
858 if (status
!= Networking::Connected
&& status
!= Networking::Unknown
) {
862 m_feedList
->addToFetchQueue(Kernel::self()->fetchQueue(), true);
865 void MainWidget::slotFetchCurrentFeed()
867 if (!m_selectionController
->selectedSubscription()) {
870 if (isNetworkAvailable()) {
871 m_selectionController
->selectedSubscription()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
873 m_mainFrame
->slotSetStatusText(i18n("Networking is not available."));
877 void MainWidget::slotFetchAllFeeds()
879 if (m_feedList
&& isNetworkAvailable()) {
880 m_feedList
->addToFetchQueue(Kernel::self()->fetchQueue());
881 } else if (m_feedList
) {
882 m_mainFrame
->slotSetStatusText(i18n("Networking is not available."));
886 void MainWidget::slotFetchingStarted()
888 m_mainFrame
->slotSetState(Frame::Started
);
889 m_actionManager
->action(QStringLiteral("feed_stop"))->setEnabled(true);
890 m_mainFrame
->slotSetStatusText(i18n("Fetching Feeds..."));
893 void MainWidget::slotFetchingStopped()
895 m_mainFrame
->slotSetState(Frame::Completed
);
896 m_actionManager
->action(QStringLiteral("feed_stop"))->setEnabled(false);
897 m_mainFrame
->slotSetStatusText(QString());
900 void MainWidget::slotArticleSelected(const Akregator::Article
&article
)
902 if (m_viewMode
== CombinedView
) {
906 m_markReadTimer
->stop();
908 Q_ASSERT(article
.isNull() || article
.feed());
910 QVector
<Article
> articles
= m_selectionController
->selectedArticles();
911 Q_EMIT
signalArticlesSelected(articles
);
913 KToggleAction
*const maai
= qobject_cast
<KToggleAction
*>(m_actionManager
->action(QStringLiteral("article_set_status_important")));
915 maai
->setChecked(article
.keep());
917 m_articleViewer
->showArticle(article
);
918 if (m_selectionController
->selectedArticles().count() == 0) {
919 m_articleListView
->setCurrentIndex(m_selectionController
->currentArticleIndex());
922 if (article
.isNull() || article
.status() == Akregator::Read
) {
926 if (!Settings::useMarkReadDelay()) {
930 const int delay
= Settings::markReadDelay();
933 m_markReadTimer
->start(delay
* 1000);
935 Akregator::ArticleModifyJob
*job
= new Akregator::ArticleModifyJob
;
936 const Akregator::ArticleId aid
= { article
.feed()->xmlUrl(), article
.guid() };
937 job
->setStatus(aid
, Akregator::Read
);
942 void MainWidget::slotMouseButtonPressed(int button
, const QUrl
&url
)
944 if (button
!= Qt::MidButton
) {
948 if (!url
.isValid()) {
952 OpenUrlRequest
req(url
);
954 switch (Settings::mMBBehaviour()) {
955 case Settings::EnumMMBBehaviour::OpenInExternalBrowser
:
956 req
.setOptions(OpenUrlRequest::ExternalBrowser
);
958 case Settings::EnumMMBBehaviour::OpenInBackground
:
959 req
.setOptions(OpenUrlRequest::NewTab
);
960 req
.setOpenInBackground(true);
963 req
.setOptions(OpenUrlRequest::NewTab
);
964 req
.setOpenInBackground(false);
967 Kernel::self()->frameManager()->slotOpenUrlRequest(req
);
970 void MainWidget::slotOpenHomepage()
972 Feed
*feed
= dynamic_cast<Feed
*>(m_selectionController
->selectedSubscription());
978 QUrl
url(feed
->htmlUrl());
981 OpenUrlRequest
req(feed
->htmlUrl());
982 req
.setOptions(OpenUrlRequest::ExternalBrowser
);
983 Kernel::self()->frameManager()->slotOpenUrlRequest(req
);
987 void MainWidget::slotOpenSelectedArticlesInBrowser()
989 const QVector
<Article
> articles
= m_selectionController
->selectedArticles();
991 Q_FOREACH (const Akregator::Article
&article
, articles
) {
992 slotOpenArticleInBrowser(article
);
996 void MainWidget::slotOpenArticleInBrowser(const Akregator::Article
&article
)
998 if (!article
.isNull() && article
.link().isValid()) {
999 OpenUrlRequest
req(article
.link());
1000 req
.setOptions(OpenUrlRequest::ExternalBrowser
);
1001 Kernel::self()->frameManager()->slotOpenUrlRequest(req
);
1005 void MainWidget::openSelectedArticles(bool openInBackground
)
1007 const QVector
<Article
> articles
= m_selectionController
->selectedArticles();
1009 Q_FOREACH (const Akregator::Article
&article
, articles
) {
1010 const QUrl url
= article
.link();
1011 if (!url
.isValid()) {
1015 OpenUrlRequest
req(url
);
1016 req
.setOptions(OpenUrlRequest::NewTab
);
1017 if (openInBackground
) {
1018 req
.setOpenInBackground(true);
1019 Kernel::self()->frameManager()->slotOpenUrlRequest(req
, false /*don't use settings for open in background*/);
1021 Kernel::self()->frameManager()->slotOpenUrlRequest(req
);
1027 void MainWidget::currentArticleInfo(QString
&link
, QString
&title
)
1029 const Article article
= m_selectionController
->currentArticle();
1031 if (article
.isNull()) {
1034 if (article
.link().isValid()) {
1035 link
= article
.link().url();
1036 title
= Utils::convertHtmlTags(article
.title());
1040 void MainWidget::updateQuickSearchLineText()
1042 m_searchBar
->updateQuickSearchLineText(m_actionManager
->quickSearchLineText());
1045 void MainWidget::slotCopyLinkAddress()
1047 const Article article
= m_selectionController
->currentArticle();
1049 if (article
.isNull()) {
1054 if (article
.link().isValid()) {
1055 link
= article
.link().url();
1056 QClipboard
*cb
= QApplication::clipboard();
1057 cb
->setText(link
, QClipboard::Clipboard
);
1058 // don't set url to selection as it's a no-no according to a fd.o spec
1059 //cb->setText(link, QClipboard::Selection);
1063 void MainWidget::slotToggleShowQuickFilter()
1065 if (Settings::showQuickFilter()) {
1066 Settings::setShowQuickFilter(false);
1067 m_searchBar
->slotClearSearch();
1068 m_searchBar
->hide();
1070 Settings::setShowQuickFilter(true);
1071 if (!m_displayingAboutPage
) {
1072 m_searchBar
->show();
1078 void MainWidget::slotArticleDelete()
1081 if (m_viewMode
== CombinedView
) {
1085 const QVector
<Article
> articles
= m_selectionController
->selectedArticles();
1088 switch (articles
.count()) {
1092 msg
= i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>", articles
.first().title());
1095 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());
1098 if (KMessageBox::warningContinueCancel(this,
1099 msg
, i18n("Delete Article"),
1100 KStandardGuiItem::del(),
1101 KStandardGuiItem::cancel(),
1102 QStringLiteral("Disable delete article confirmation")) != KMessageBox::Continue
) {
1106 TreeNode
*const selected
= m_selectionController
->selectedSubscription();
1109 selected
->setNotificationMode(false);
1112 Akregator::ArticleDeleteJob
*job
= new Akregator::ArticleDeleteJob
;
1113 Q_FOREACH (const Akregator::Article
&i
, articles
) {
1114 Feed
*const feed
= i
.feed();
1118 const Akregator::ArticleId aid
= { feed
->xmlUrl(), i
.guid() };
1119 job
->appendArticleId(aid
);
1125 selected
->setNotificationMode(true);
1129 void MainWidget::slotFramesChanged()
1131 // We need to wait till the frame is fully loaded
1132 QMetaObject::invokeMethod(m_part
, "slotAutoSave", Qt::QueuedConnection
);
1135 void MainWidget::slotArticleToggleKeepFlag(bool)
1137 const QVector
<Article
> articles
= m_selectionController
->selectedArticles();
1139 if (articles
.isEmpty()) {
1143 bool allFlagsSet
= true;
1144 Q_FOREACH (const Akregator::Article
&i
, articles
) {
1145 allFlagsSet
= allFlagsSet
&& i
.keep();
1151 Akregator::ArticleModifyJob
*job
= new Akregator::ArticleModifyJob
;
1152 Q_FOREACH (const Akregator::Article
&i
, articles
) {
1153 const Akregator::ArticleId aid
= { i
.feed()->xmlUrl(), i
.guid() };
1154 job
->setKeep(aid
, !allFlagsSet
);
1162 void setArticleStatus(const QString
&feedUrl
, const QString
&articleId
, int status
)
1164 if (!feedUrl
.isEmpty() && !articleId
.isEmpty()) {
1165 Akregator::ArticleModifyJob
*job
= new Akregator::ArticleModifyJob
;
1166 const Akregator::ArticleId aid
= { feedUrl
, articleId
};
1167 job
->setStatus(aid
, status
);
1172 void setSelectedArticleStatus(const Akregator::AbstractSelectionController
*controller
, int status
)
1174 const QVector
<Akregator::Article
> articles
= controller
->selectedArticles();
1176 if (articles
.isEmpty()) {
1180 Akregator::ArticleModifyJob
*job
= new Akregator::ArticleModifyJob
;
1181 Q_FOREACH (const Akregator::Article
&i
, articles
) {
1182 const Akregator::ArticleId aid
= { i
.feed()->xmlUrl(), i
.guid() };
1183 job
->setStatus(aid
, status
);
1190 void MainWidget::slotSetSelectedArticleRead()
1192 ::setSelectedArticleStatus(m_selectionController
, Akregator::Read
);
1195 void MainWidget::slotSetSelectedArticleUnread()
1197 ::setSelectedArticleStatus(m_selectionController
, Akregator::Unread
);
1200 void MainWidget::slotSetSelectedArticleNew()
1202 ::setSelectedArticleStatus(m_selectionController
, Akregator::New
);
1205 void MainWidget::slotSetCurrentArticleReadDelayed()
1207 const Article article
= m_selectionController
->currentArticle();
1209 if (article
.isNull()) {
1213 Akregator::ArticleModifyJob
*const job
= new Akregator::ArticleModifyJob
;
1214 const Akregator::ArticleId aid
= { article
.feed()->xmlUrl(), article
.guid() };
1215 job
->setStatus(aid
, Akregator::Read
);
1219 void MainWidget::slotShowStatusBarMessage(const QString
&msg
)
1221 KPIM::BroadcastStatus::instance()->setStatusMsg(msg
);
1224 void MainWidget::readProperties(const KConfigGroup
&config
)
1226 if (!Settings::resetQuickFilterOnNodeChange()) {
1227 // read filter settings
1228 m_searchBar
->slotSetText(config
.readEntry("searchLine"));
1229 m_searchBar
->slotSetStatus(config
.readEntry("searchCombo").toInt());
1232 QStringList childList
= config
.readEntry(QStringLiteral("Children"),
1234 Q_FOREACH (const QString
&framePrefix
, childList
) {
1235 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1236 WebEngineFrame
*const frame
= new WebEngineFrame(m_actionManager
->actionCollection(), m_tabWidget
);
1238 WebViewFrame
*const frame
= new WebViewFrame(m_actionManager
->actionCollection(), m_tabWidget
);
1240 frame
->loadConfig(config
, framePrefix
+ QLatin1Char('_'));
1242 connectFrame(frame
);
1243 Kernel::self()->frameManager()->slotAddFrame(frame
);
1248 void MainWidget::saveProperties(KConfigGroup
&config
)
1250 // save filter settings
1251 config
.writeEntry("searchLine", m_searchBar
->text());
1252 config
.writeEntry("searchCombo", m_searchBar
->status());
1254 Kernel::self()->frameManager()->saveProperties(config
);
1257 void MainWidget::ensureArticleTabVisible()
1259 m_tabWidget
->setCurrentWidget(m_mainFrame
);
1262 void MainWidget::slotReloadAllTabs()
1264 m_tabWidget
->slotReloadAllTabs();
1267 bool MainWidget::isNetworkAvailable() const
1269 return m_networkConfigManager
->isOnline();
1272 void MainWidget::slotNetworkStatusChanged(bool status
)
1275 m_mainFrame
->slotSetStatusText(i18n("Networking is available now."));
1276 this->slotFetchAllFeeds();
1278 m_mainFrame
->slotSetStatusText(i18n("Networking is not available."));
1282 void MainWidget::slotOpenSelectedArticles()
1284 openSelectedArticles(false);
1287 void MainWidget::slotOpenSelectedArticlesInBackground()
1289 openSelectedArticles(true);
1292 void MainWidget::slotCurrentFrameChanged(int frameId
)
1294 Kernel::self()->frameManager()->slotChangeFrame(frameId
);
1295 m_actionManager
->zoomActionMenu()->setZoomFactor(Kernel::self()->frameManager()->currentFrame()->zoomFactor() * 100);
1296 m_actionManager
->zoomActionMenu()->setZoomTextOnly(Kernel::self()->frameManager()->currentFrame()->zoomTextOnlyInFrame());
1299 void MainWidget::slotFocusQuickSearch()
1301 m_searchBar
->setFocusSearchLine();
1303 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1304 void MainWidget::slotArticleAction(Akregator::ArticleViewerWebEngine::ArticleAction type
, const QString
&articleId
, const QString
&feed
)
1306 void MainWidget::slotArticleAction(ArticleViewerNg::ArticleAction type
, const QString
&articleId
, const QString
&feed
)
1310 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1311 case ArticleViewerWebEngine::DeleteAction
: {
1313 case ArticleViewerNg::DeleteAction
: {
1315 Akregator::ArticleDeleteJob
*job
= new Akregator::ArticleDeleteJob
;
1316 const Akregator::ArticleId aid
= { feed
, articleId
};
1317 job
->appendArticleId(aid
);
1321 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1322 case ArticleViewerWebEngine::MarkAsRead
:
1324 case ArticleViewerNg::MarkAsRead
:
1326 ::setArticleStatus(feed
, articleId
, Akregator::Read
);
1328 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1329 case ArticleViewerWebEngine::MarkAsUnRead
:
1331 case ArticleViewerNg::MarkAsUnRead
:
1333 ::setArticleStatus(feed
, articleId
, Akregator::Unread
);
1336 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1337 case ArticleViewerWebEngine::MarkAsImportant
: {
1339 case ArticleViewerNg::MarkAsImportant
: {
1341 Akregator::ArticleModifyJob
*job
= new Akregator::ArticleModifyJob
;
1342 const Akregator::Article article
= m_feedList
->findArticle(feed
, articleId
);
1343 const Akregator::ArticleId aid
= { feed
, articleId
};
1344 job
->setKeep(aid
, !article
.keep());
1348 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1349 case ArticleViewerWebEngine::SendUrlArticle
: {
1351 case ArticleViewerNg::SendUrlArticle
: {
1353 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1354 case ArticleViewerWebEngine::SendFileArticle
:
1356 case ArticleViewerNg::SendFileArticle
:
1358 const Article article
= m_feedList
->findArticle(feed
, articleId
);
1359 const QByteArray text
= article
.link().toDisplayString().toLatin1();
1360 const QString title
= Akregator::Utils::convertHtmlTags(article
.title());
1361 if (text
.isEmpty()) {
1364 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1365 sendArticle(text
, title
, (type
== ArticleViewerWebEngine::SendFileArticle
));
1367 sendArticle(text
, title
, (type
== ArticleViewerNg::SendFileArticle
));
1371 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1372 case ArticleViewerWebEngine::OpenInBackgroundTab
: {
1374 case ArticleViewerNg::OpenInBackgroundTab
: {
1376 const Akregator::Article article
= m_feedList
->findArticle(feed
, articleId
);
1377 const QUrl url
= article
.link();
1378 if (url
.isValid()) {
1379 OpenUrlRequest
req(url
);
1380 req
.setOptions(OpenUrlRequest::NewTab
);
1381 req
.setOpenInBackground(true);
1382 Kernel::self()->frameManager()->slotOpenUrlRequest(req
, false /*don't use settings for open in background*/);
1386 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1387 case ArticleViewerWebEngine::OpenInExternalBrowser
: {
1389 case ArticleViewerNg::OpenInExternalBrowser
: {
1391 const Akregator::Article article
= m_feedList
->findArticle(feed
, articleId
);
1392 slotOpenArticleInBrowser(article
);
1395 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1396 case ArticleViewerWebEngine::Share
:
1398 case ArticleViewerNg::Share
:
1400 const Akregator::Article article
= m_feedList
->findArticle(feed
, articleId
);
1401 const QUrl url
= article
.link();
1402 if (url
.isValid()) {