Use short url plugin directly
[kdepim.git] / akregator / src / mainwidget.cpp
blob2f6ef123fa2b55ccb75f0814cb74ab5cff434aa5
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);
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()) {
308 case CombinedView:
309 slotCombinedView();
310 break;
311 case WidescreenView:
312 slotWidescreenView();
313 break;
314 default:
315 slotNormalView();
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
345 delete m_mainTab;
346 delete m_mainFrame;
347 m_mainFrame = 0;
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);
385 #else
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);
404 #endif
406 void MainWidget::slotRequestNewFrame(int &frameId)
408 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
409 WebEngineFrame *frame = new WebEngineFrame(m_actionManager->actionCollection(), m_tabWidget);
410 #else
411 WebViewFrame *frame = new WebViewFrame(m_actionManager->actionCollection(), m_tabWidget);
412 #endif
413 connectFrame(frame);
415 Kernel::self()->frameManager()->slotAddFrame(frame);
417 frameId = frame->id();
420 void MainWidget::sendArticle(bool attach)
422 QByteArray text;
423 QString title;
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()) {
439 return;
441 sendArticle(text, title, attach);
444 void MainWidget::cleanUpDownloadFile()
446 Q_FOREACH (QPointer<Akregator::DownloadArticleJob> job, mListDownloadArticleJobs) {
447 if (job) {
448 job->forceCleanupTemporaryFile();
453 void MainWidget::sendArticle(const QByteArray &text, const QString &title, bool attach)
455 if (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);
461 download->start();
462 } else {
463 QUrlQuery query;
464 query.addQueryItem(QStringLiteral("subject"), title);
465 query.addQueryItem(QStringLiteral("body"), QString::fromUtf8(text));
466 QUrl url;
467 url.setScheme(QStringLiteral("mailto"));
468 url.setQuery(query);
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);
479 cmd->start();
482 void MainWidget::setFeedList(const QSharedPointer<FeedList> &list)
484 if (list == m_feedList) {
485 return;
487 const QSharedPointer<FeedList> oldList = m_feedList;
489 m_feedList = list;
490 if (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);
502 if (oldList) {
503 oldList->disconnect(this);
506 slotDeleteExpiredArticles();
509 void MainWidget::deleteExpiredArticles(const QSharedPointer<FeedList> &list)
511 if (!list) {
512 return;
514 ExpireItemsCommand *cmd = new ExpireItemsCommand(this);
515 cmd->setParentWidget(this);
516 cmd->setFeedList(list);
517 cmd->setFeeds(list->feedIds());
518 cmd->start();
521 void MainWidget::slotDeleteExpiredArticles()
523 deleteExpiredArticles(m_feedList);
526 QDomDocument MainWidget::feedListToOPML()
528 QDomDocument dom;
529 if (m_feedList) {
530 dom = m_feedList->toOpml();
532 return dom;
535 void MainWidget::addFeedToGroup(const QString &url, const QString &groupName)
537 // Locate the group.
538 QList<TreeNode *> namedGroups = m_feedList->findByTitle(groupName);
539 Folder *group = 0;
540 foreach (TreeNode *const candidate, namedGroups) {
541 if (candidate->isGroup()) {
542 group = static_cast<Folder *>(candidate);
543 break;
547 if (!group) {
548 Folder *g = new Folder(groupName);
549 m_feedList->allFeedsFolder()->appendChild(g);
550 group = 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) {
560 return;
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);
570 } else {
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) {
584 return;
587 if (m_viewMode == CombinedView) {
588 m_articleWidget->show();
590 Article article = m_selectionController->currentArticle();
592 if (!article.isNull()) {
593 m_articleViewer->showArticle(article);
594 } else {
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) {
608 return;
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();
621 if (!current) {
622 return;
624 TreeNode *prev = current->prevSibling();
625 Folder *parent = current->parent();
627 if (!prev || !parent) {
628 return;
631 parent->removeChild(prev);
632 parent->insertChild(prev, current);
633 m_feedListView->ensureNodeVisible(current);
636 void MainWidget::slotMoveCurrentNodeDown()
638 TreeNode *current = m_selectionController->selectedSubscription();
639 if (!current) {
640 return;
642 TreeNode *next = current->nextSibling();
643 Folder *parent = current->parent();
645 if (!next || !parent) {
646 return;
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()) {
658 return;
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()) {
673 return;
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()
687 sendArticle();
690 void MainWidget::slotSendFile()
692 sendArticle(true);
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()) {
705 m_searchBar->show();
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);
717 } else {
718 m_articleViewer->slotShowSummary(node);
721 if (node) {
722 m_mainFrame->setWindowTitle(node->title());
725 m_actionManager->slotNodeSelected(node);
728 void MainWidget::slotFeedAdd()
730 Folder *group = 0;
731 if (!m_selectionController->selectedSubscription()) {
732 group = m_feedList->allFeedsFolder();
733 } else {
734 if (m_selectionController->selectedSubscription()->isGroup()) {
735 group = static_cast<Folder *>(m_selectionController->selectedSubscription());
736 } else {
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);
754 cmd->setUrl(url);
755 cmd->setSubscriptionListView(m_feedListView);
756 cmd->start();
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);
766 cmd->start();
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()) {
775 return;
778 DeleteSubscriptionCommand *cmd = new DeleteSubscriptionCommand(this);
779 cmd->setParentWidget(this);
780 cmd->setSubscription(m_feedList, selectedNode->id());
781 cmd->start();
784 void MainWidget::slotFeedModify()
786 TreeNode *const node = m_selectionController->selectedSubscription();
787 if (!node) {
788 return;
790 EditSubscriptionCommand *cmd = new EditSubscriptionCommand(this);
791 cmd->setParentWidget(this);
792 cmd->setSubscription(m_feedList, node->id());
793 cmd->setSubscriptionListView(m_feedListView);
794 cmd->start();
797 void MainWidget::slotNextUnreadArticle()
799 ensureArticleTabVisible();
800 if (m_viewMode == CombinedView) {
801 m_feedListView->slotNextUnreadFeed();
802 return;
804 TreeNode *sel = m_selectionController->selectedSubscription();
805 if (sel && sel->unread() > 0) {
806 m_articleListView->slotNextUnreadArticle();
807 } else {
808 m_feedListView->slotNextUnreadFeed();
812 void MainWidget::slotPrevUnreadArticle()
814 ensureArticleTabVisible();
815 if (m_viewMode == CombinedView) {
816 m_feedListView->slotPrevUnreadFeed();
817 return;
819 TreeNode *sel = m_selectionController->selectedSubscription();
820 if (sel && sel->unread() > 0) {
821 m_articleListView->slotPreviousUnreadArticle();
822 } else {
823 m_feedListView->slotPrevUnreadFeed();
827 void MainWidget::slotMarkAllFeedsRead()
829 KJob *job = m_feedList->createMarkAsReadJob();
830 connect(job, &KJob::finished, m_selectionController, &AbstractSelectionController::forceFilterUpdate);
831 job->start();
834 void MainWidget::slotMarkAllRead()
836 if (!m_selectionController->selectedSubscription()) {
837 return;
839 KJob *job = m_selectionController->selectedSubscription()->createMarkAsReadJob();
840 connect(job, &KJob::finished, m_selectionController, &AbstractSelectionController::forceFilterUpdate);
841 job->start();
844 void MainWidget::slotSetTotalUnread()
846 Q_EMIT signalUnreadCountChanged(m_feedList ? m_feedList->unread() : 0);
849 void MainWidget::slotDoIntervalFetches()
851 if (!m_feedList) {
852 return;
854 #if 0
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) {
859 return;
861 #endif
862 m_feedList->addToFetchQueue(Kernel::self()->fetchQueue(), true);
865 void MainWidget::slotFetchCurrentFeed()
867 if (!m_selectionController->selectedSubscription()) {
868 return;
870 if (isNetworkAvailable()) {
871 m_selectionController->selectedSubscription()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
872 } else {
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) {
903 return;
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")));
914 Q_ASSERT(maai);
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) {
923 return;
926 if (!Settings::useMarkReadDelay()) {
927 return;
930 const int delay = Settings::markReadDelay();
932 if (delay > 0) {
933 m_markReadTimer->start(delay * 1000);
934 } else {
935 Akregator::ArticleModifyJob *job = new Akregator::ArticleModifyJob;
936 const Akregator::ArticleId aid = { article.feed()->xmlUrl(), article.guid() };
937 job->setStatus(aid, Akregator::Read);
938 job->start();
942 void MainWidget::slotMouseButtonPressed(int button, const QUrl &url)
944 if (button != Qt::MidButton) {
945 return;
948 if (!url.isValid()) {
949 return;
952 OpenUrlRequest req(url);
954 switch (Settings::mMBBehaviour()) {
955 case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
956 req.setOptions(OpenUrlRequest::ExternalBrowser);
957 break;
958 case Settings::EnumMMBBehaviour::OpenInBackground:
959 req.setOptions(OpenUrlRequest::NewTab);
960 req.setOpenInBackground(true);
961 break;
962 default:
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());
974 if (!feed) {
975 return;
978 QUrl url(feed->htmlUrl());
980 if (url.isValid()) {
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()) {
1012 continue;
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*/);
1020 } else {
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()) {
1032 return;
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()) {
1050 return;
1053 QString link;
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();
1069 } else {
1070 Settings::setShowQuickFilter(true);
1071 if (!m_displayingAboutPage) {
1072 m_searchBar->show();
1078 void MainWidget::slotArticleDelete()
1081 if (m_viewMode == CombinedView) {
1082 return;
1085 const QVector<Article> articles = m_selectionController->selectedArticles();
1087 QString msg;
1088 switch (articles.count()) {
1089 case 0:
1090 return;
1091 case 1:
1092 msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>", articles.first().title());
1093 break;
1094 default:
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) {
1103 return;
1106 TreeNode *const selected = m_selectionController->selectedSubscription();
1108 if (selected) {
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();
1115 if (!feed) {
1116 continue;
1118 const Akregator::ArticleId aid = { feed->xmlUrl(), i.guid() };
1119 job->appendArticleId(aid);
1122 job->start();
1124 if (selected) {
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()) {
1140 return;
1143 bool allFlagsSet = true;
1144 Q_FOREACH (const Akregator::Article &i, articles) {
1145 allFlagsSet = allFlagsSet && i.keep();
1146 if (!allFlagsSet) {
1147 break;
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);
1156 job->start();
1159 namespace
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);
1168 job->start();
1172 void setSelectedArticleStatus(const Akregator::AbstractSelectionController *controller, int status)
1174 const QVector<Akregator::Article> articles = controller->selectedArticles();
1176 if (articles.isEmpty()) {
1177 return;
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);
1185 job->start();
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()) {
1210 return;
1213 Akregator::ArticleModifyJob *const job = new Akregator::ArticleModifyJob;
1214 const Akregator::ArticleId aid = { article.feed()->xmlUrl(), article.guid() };
1215 job->setStatus(aid, Akregator::Read);
1216 job->start();
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());
1231 // Reopen tabs
1232 QStringList childList = config.readEntry(QStringLiteral("Children"),
1233 QStringList());
1234 Q_FOREACH (const QString &framePrefix, childList) {
1235 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1236 WebEngineFrame *const frame = new WebEngineFrame(m_actionManager->actionCollection(), m_tabWidget);
1237 #else
1238 WebViewFrame *const frame = new WebViewFrame(m_actionManager->actionCollection(), m_tabWidget);
1239 #endif
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)
1274 if (status) {
1275 m_mainFrame->slotSetStatusText(i18n("Networking is available now."));
1276 this->slotFetchAllFeeds();
1277 } else {
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)
1305 #else
1306 void MainWidget::slotArticleAction(ArticleViewerNg::ArticleAction type, const QString &articleId, const QString &feed)
1307 #endif
1309 switch (type) {
1310 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1311 case ArticleViewerWebEngine::DeleteAction: {
1312 #else
1313 case ArticleViewerNg::DeleteAction: {
1314 #endif
1315 Akregator::ArticleDeleteJob *job = new Akregator::ArticleDeleteJob;
1316 const Akregator::ArticleId aid = { feed, articleId };
1317 job->appendArticleId(aid);
1318 job->start();
1319 break;
1321 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1322 case ArticleViewerWebEngine::MarkAsRead:
1323 #else
1324 case ArticleViewerNg::MarkAsRead:
1325 #endif
1326 ::setArticleStatus(feed, articleId, Akregator::Read);
1327 break;
1328 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1329 case ArticleViewerWebEngine::MarkAsUnRead:
1330 #else
1331 case ArticleViewerNg::MarkAsUnRead:
1332 #endif
1333 ::setArticleStatus(feed, articleId, Akregator::Unread);
1334 break;
1336 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1337 case ArticleViewerWebEngine::MarkAsImportant: {
1338 #else
1339 case ArticleViewerNg::MarkAsImportant: {
1340 #endif
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());
1345 job->start();
1346 break;
1348 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1349 case ArticleViewerWebEngine::SendUrlArticle: {
1350 #else
1351 case ArticleViewerNg::SendUrlArticle: {
1352 #endif
1353 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1354 case ArticleViewerWebEngine::SendFileArticle:
1355 #else
1356 case ArticleViewerNg::SendFileArticle:
1357 #endif
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()) {
1362 return;
1364 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1365 sendArticle(text, title, (type == ArticleViewerWebEngine::SendFileArticle));
1366 #else
1367 sendArticle(text, title, (type == ArticleViewerNg::SendFileArticle));
1368 #endif
1369 break;
1371 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1372 case ArticleViewerWebEngine::OpenInBackgroundTab: {
1373 #else
1374 case ArticleViewerNg::OpenInBackgroundTab: {
1375 #endif
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*/);
1384 break;
1386 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1387 case ArticleViewerWebEngine::OpenInExternalBrowser: {
1388 #else
1389 case ArticleViewerNg::OpenInExternalBrowser: {
1390 #endif
1391 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1392 slotOpenArticleInBrowser(article);
1393 break;
1395 #ifdef QTWEBENGINE_EXPERIMENTAL_OPTION
1396 case ArticleViewerWebEngine::Share:
1397 #else
1398 case ArticleViewerNg::Share:
1399 #endif
1400 const Akregator::Article article = m_feedList->findArticle(feed, articleId);
1401 const QUrl url = article.link();
1402 if (url.isValid()) {
1403 //TODO
1405 break;