File indexing completed on 2024-05-05 05:13:01
0001 /* 0002 This file is part of Akregator. 0003 0004 SPDX-FileCopyrightText: 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net> 0005 SPDX-FileCopyrightText: 2005 Frank Osterfeld <osterfeld@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0008 */ 0009 0010 #pragma once 0011 0012 #include "akregator_export.h" 0013 #include "treenode.h" 0014 0015 #include <Syndication/Syndication> 0016 0017 #include <QIcon> 0018 0019 #include <memory> 0020 0021 class QDomElement; 0022 class QString; 0023 0024 namespace Akregator 0025 { 0026 class Article; 0027 class FetchQueue; 0028 class TreeNodeVisitor; 0029 class ArticleDeleteJob; 0030 0031 namespace Backend 0032 { 0033 class Storage; 0034 } 0035 0036 class FeedPrivate; 0037 0038 /** represents a feed */ 0039 class AKREGATOR_EXPORT Feed : public TreeNode 0040 { 0041 friend class ::Akregator::Article; 0042 friend class ::Akregator::Folder; 0043 Q_OBJECT 0044 public: 0045 /** the archiving modes */ 0046 0047 enum ArchiveMode { 0048 globalDefault, /**< use default from Settings (default) */ 0049 keepAllArticles, /**< Don't delete any articles */ 0050 disableArchiving, /**< Don't save any articles except articles with keep flag set (equal to maxArticleNumber() == 0) */ 0051 limitArticleNumber, /**< Save maxArticleNumber() articles, plus the ones with keep flag set */ 0052 limitArticleAge /**< Save articles not older than maxArticleAge() (or keep flag set) */ 0053 }; 0054 0055 struct ImageInfo { 0056 QString imageUrl; 0057 int width = -1; 0058 int height = -1; 0059 bool operator==(const ImageInfo &other) const; 0060 bool operator!=(const ImageInfo &other) const; 0061 }; 0062 0063 // class methods 0064 /** converts strings to ArchiveMode value 0065 if parsing fails, it returns ArchiveMode::globalDefault 0066 */ 0067 static ArchiveMode stringToArchiveMode(const QString &str); 0068 0069 /** converts ArchiveMode values to corresponding strings */ 0070 static QString archiveModeToString(ArchiveMode mode); 0071 0072 /** creates a Feed object from a description in OPML format */ 0073 static Feed *fromOPML(const QDomElement &e, Akregator::Backend::Storage *storage); 0074 0075 /** default constructor */ 0076 explicit Feed(Akregator::Backend::Storage *storage); 0077 ~Feed() override; 0078 0079 [[nodiscard]] bool accept(TreeNodeVisitor *visitor) override; 0080 0081 /** exports the feed settings to OPML */ 0082 [[nodiscard]] QDomElement toOPML(QDomElement parent, QDomDocument document) const override; 0083 0084 /** 0085 returns whether this feed uses its own fetch interval or the global setting 0086 @return @c true iff this feed has a custom fetch interval 0087 */ 0088 [[nodiscard]] bool useCustomFetchInterval() const; 0089 0090 /** set if the feed has its custom fetch interval or uses the 0091 global setting 0092 @param enabled @c true: use custom interval, @c false: use global default 0093 */ 0094 void setCustomFetchIntervalEnabled(bool enabled); 0095 0096 // FIXME is it -1 or 0 to disable interval fetching? 0097 /** Returns custom auto fetch interval of this feed. 0098 @return custom fetch interval in minutes, 0 if disabled */ 0099 [[nodiscard]] int fetchInterval() const; 0100 0101 /** Sets custom auto fetch interval. 0102 @param interval interval in minutes, -1 for disabling auto fetching */ 0103 void setFetchInterval(int interval); 0104 0105 /** returns the archiving mode which is used for this feed */ 0106 [[nodiscard]] ArchiveMode archiveMode() const; 0107 0108 /** sets the archiving mode for this feed */ 0109 void setArchiveMode(ArchiveMode archiveMode); 0110 0111 /** returns the maximum age of articles used for expiration by age (used in @c limitArticleAge archive mode) 0112 @return expiry age in days */ 0113 [[nodiscard]] int maxArticleAge() const; 0114 0115 /** sets the maximum age of articles used for expiration by age (used in @c limitArticleAge archive mode) 0116 @param maxArticleAge expiry age in days */ 0117 void setMaxArticleAge(int maxArticleAge); 0118 0119 /** returns the article count limit used in @c limitArticleNumber archive mode **/ 0120 [[nodiscard]] int maxArticleNumber() const; 0121 0122 /** sets the article count limit used in @c limitArticleNumber archive mode **/ 0123 void setMaxArticleNumber(int maxArticleNumber); 0124 0125 /** if @c true, new articles are marked immediately as read instead of new/unread. Useful for high-traffic feeds. */ 0126 [[nodiscard]] bool markImmediatelyAsRead() const; 0127 0128 void setMarkImmediatelyAsRead(bool enabled); 0129 0130 void setUseNotification(bool enabled); 0131 0132 [[nodiscard]] bool useNotification() const; 0133 0134 /** if true, the linked URL is loaded directly in the article viewer instead of showing the description */ 0135 void setLoadLinkedWebsite(bool enabled); 0136 0137 [[nodiscard]] bool loadLinkedWebsite() const; 0138 0139 /** returns the feed logo */ 0140 [[nodiscard]] Feed::ImageInfo logoInfo() const; 0141 0142 /** sets the feed image */ 0143 void setLogoInfo(const ImageInfo &image); 0144 0145 /** returns the url of the actual feed source (rss/rdf/atom file) */ 0146 [[nodiscard]] QString xmlUrl() const; 0147 /** sets the url of the actual feed source (rss/rdf/atom file) */ 0148 void setXmlUrl(const QString &s); 0149 0150 /** returns the URL of the HTML page of this feed */ 0151 [[nodiscard]] QString htmlUrl() const; 0152 /** sets the URL of the HTML page of this feed */ 0153 void setHtmlUrl(const QString &s); 0154 0155 [[nodiscard]] Feed::ImageInfo faviconInfo() const; 0156 void setFaviconInfo(const Feed::ImageInfo &url); 0157 0158 /** returns the description of this feed */ 0159 [[nodiscard]] QString description() const; 0160 0161 /** sets the description of this feed */ 0162 void setDescription(const QString &s); 0163 0164 /** returns article by guid 0165 * @param guid the guid of the article to be returned 0166 * @return the article object with the given guid, or a 0167 * null article if non-existent 0168 */ 0169 [[nodiscard]] Article findArticle(const QString &guid) const; 0170 0171 /** returns whether a fetch error has occurred */ 0172 [[nodiscard]] bool fetchErrorOccurred() const; 0173 0174 Syndication::ErrorCode fetchErrorCode() const; 0175 0176 /** returns the unread count for this feed */ 0177 [[nodiscard]] int unread() const override; 0178 0179 /** returns the number of total articles in this feed 0180 @return number of articles */ 0181 0182 [[nodiscard]] int totalCount() const override; 0183 0184 /** returns if the article archive of this feed is loaded */ 0185 [[nodiscard]] bool isArticlesLoaded() const; 0186 0187 /** returns if this node is a feed group (@c false here) */ 0188 [[nodiscard]] bool isGroup() const override 0189 { 0190 return false; 0191 } 0192 0193 // impl 0194 [[nodiscard]] bool isAggregation() const override 0195 { 0196 return false; 0197 } 0198 0199 /** returns the next node in the tree. 0200 Calling next() unless it returns 0 iterates through the tree in pre-order 0201 */ 0202 const TreeNode *next() const override; 0203 TreeNode *next() override; 0204 0205 // impl 0206 [[nodiscard]] QIcon icon() const override; 0207 0208 /** deletes expired articles */ 0209 void deleteExpiredArticles(Akregator::ArticleDeleteJob *job); 0210 0211 [[nodiscard]] bool isFetching() const; 0212 0213 QList<const Feed *> feeds() const override; 0214 QList<Feed *> feeds() override; 0215 QList<const Folder *> folders() const override; 0216 QList<Folder *> folders() override; 0217 0218 KJob *createMarkAsReadJob() override; 0219 0220 [[nodiscard]] QString comment() const; 0221 void setComment(const QString &comment); 0222 void setFaviconLocalPath(const QString &file); 0223 void setCopyright(const QString ©right); 0224 [[nodiscard]] QString copyright() const; 0225 public Q_SLOTS: 0226 /** starts fetching */ 0227 void fetch(bool followDiscovery = false); 0228 0229 void slotAbortFetch(); 0230 0231 /** add this feed to the fetch queue @c queue */ 0232 void slotAddToFetchQueue(Akregator::FetchQueue *queue, bool intervalFetchOnly = false) override; 0233 0234 void slotAddFeedIconListener(); 0235 0236 Q_SIGNALS: 0237 /** emitted when fetching started */ 0238 void fetchStarted(Akregator::Feed *); 0239 /** emitted when feed finished fetching */ 0240 void fetched(Akregator::Feed *); 0241 /** emitted when a fetch error occurred */ 0242 void fetchError(Akregator::Feed *); 0243 /** emitted when a feed URL was found by auto discovery */ 0244 void fetchDiscovery(Akregator::Feed *); 0245 /** emitted when a fetch is aborted */ 0246 void fetchAborted(Akregator::Feed *); 0247 0248 private: 0249 Akregator::Backend::Storage *storage(); 0250 0251 private: 0252 void setFavicon(const QIcon &icon); 0253 void loadFavicon(const QString &url, bool downloadFavicon); 0254 QList<Article> articles() override; 0255 0256 /** loads articles from archive **/ 0257 void loadArticles(); 0258 void enforceLimitArticleNumber(); 0259 0260 void recalcUnreadCount(); 0261 0262 void doArticleNotification() override; 0263 0264 /** sets the unread count for this feed */ 0265 void setUnread(int unread); 0266 0267 /** notifies that article @c mya was set to "deleted". 0268 To be called by @ref Article 0269 */ 0270 void setArticleDeleted(Article &a); 0271 0272 /** Notifies that article @p a was changed. 0273 @param oldStatus The old status if the status was changed, 0274 or -1 if the status was not changed 0275 @param process Set to @c false to disable processing the change 0276 (updating article list and updating on-screen unread count) 0277 To be called by @ref Article 0278 */ 0279 void setArticleChanged(Article &a, int oldStatus = -1, bool process = true); 0280 0281 void appendArticles(const Syndication::FeedPtr &feed); 0282 0283 /** appends article @c a to the article list */ 0284 void appendArticle(const Article &a); 0285 0286 /** checks whether article @c a is expired (considering custom and global archive mode settings) */ 0287 bool isExpired(const Article &a) const; 0288 0289 /** returns @c true if either this article uses @c limitArticleAge as custom setting or uses the global default, which is @c limitArticleAge */ 0290 bool usesExpiryByAge() const; 0291 0292 /** executes the actual fetch action */ 0293 void tryFetch(); 0294 0295 void markAsFetchedNow(); 0296 0297 private Q_SLOTS: 0298 0299 void fetchCompleted(Syndication::Loader *loader, Syndication::FeedPtr doc, Syndication::ErrorCode errorCode); 0300 0301 private: 0302 std::unique_ptr<FeedPrivate> const d; 0303 }; 0304 } // namespace Akregator