• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

akregator

  • sources
  • kde-4.14
  • kdepim
  • akregator
  • src
feed.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5  2005 Frank Osterfeld <osterfeld@kde.org>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, permission is given to link this program
22  with any edition of Qt, and distribute the resulting executable,
23  without including the source code for Qt in the source distribution.
24 */
25 
26 #include "feed.h"
27 #include "akregatorconfig.h"
28 #include "article.h"
29 #include "articlejobs.h"
30 #include "feediconmanager.h"
31 #include "feedstorage.h"
32 #include "fetchqueue.h"
33 #include "folder.h"
34 #include "notificationmanager.h"
35 #include "storage.h"
36 #include "treenodevisitor.h"
37 #include "types.h"
38 #include "utils.h"
39 #include <syndication/syndication.h>
40 
41 #include <kdebug.h>
42 #include <kglobal.h>
43 #include <KIcon>
44 #include <kstandarddirs.h>
45 #include <kurl.h>
46 #include <KRandom>
47 
48 //#include <qtl.h>
49 
50 #include <QDateTime>
51 #include <QDomDocument>
52 #include <QDomElement>
53 #include <QHash>
54 #include <QIcon>
55 #include <QList>
56 #include <QPixmap>
57 #include <QTimer>
58 
59 #ifndef Q_MOC_RUN
60 #include <boost/bind.hpp>
61 #endif
62 
63 #include <memory>
64 
65 using Syndication::ItemPtr;
66 using namespace Akregator;
67 using namespace boost;
68 
69 class Akregator::Feed::Private
70 {
71  Akregator::Feed* const q;
72  public:
73  explicit Private( Backend::Storage* storage, Akregator::Feed* qq );
74 
75  Backend::Storage* storage;
76  bool autoFetch;
77  int fetchInterval;
78  ArchiveMode archiveMode;
79  int maxArticleAge;
80  int maxArticleNumber;
81  bool markImmediatelyAsRead;
82  bool useNotification;
83  bool loadLinkedWebsite;
84  int lastFetched;
85 
86  Syndication::ErrorCode fetchErrorCode;
87  int fetchTries;
88  bool followDiscovery;
89  Syndication::Loader* loader;
90  bool articlesLoaded;
91  Backend::FeedStorage* archive;
92 
93  QString xmlUrl;
94  QString htmlUrl;
95  QString description;
96 
98  QHash<QString, Article> articles;
99 
101  QList<Article> deletedArticles;
102 
105  QList<Article> addedArticlesNotify;
106  QList<Article> removedArticlesNotify;
107  QList<Article> updatedArticlesNotify;
108 
109  QPixmap imagePixmap;
110  Syndication::ImagePtr image;
111  QIcon favicon;
112  mutable int totalCount;
113  void setTotalCountDirty() const { totalCount = -1; }
114 };
115 
116 QString Akregator::Feed::archiveModeToString(ArchiveMode mode)
117 {
118  switch (mode)
119  {
120  case keepAllArticles:
121  return QLatin1String("keepAllArticles");
122  case disableArchiving:
123  return QLatin1String("disableArchiving");
124  case limitArticleNumber:
125  return QLatin1String("limitArticleNumber");
126  case limitArticleAge:
127  return QLatin1String("limitArticleAge");
128  default:
129  break;
130  }
131  return QLatin1String("globalDefault");
132 }
133 
134 Akregator::Feed* Akregator::Feed::fromOPML(QDomElement e, Backend::Storage* storage )
135 {
136 
137  if( !e.hasAttribute(QLatin1String("xmlUrl")) && !e.hasAttribute(QLatin1String("xmlurl")) && !e.hasAttribute(QLatin1String("xmlURL")) )
138  return 0;
139 
140  QString title = e.hasAttribute(QLatin1String("text")) ? e.attribute(QLatin1String("text")) : e.attribute(QLatin1String("title"));
141 
142  QString xmlUrl = e.hasAttribute(QLatin1String("xmlUrl")) ? e.attribute(QLatin1String("xmlUrl")) : e.attribute(QLatin1String("xmlurl"));
143  if (xmlUrl.isEmpty())
144  xmlUrl = e.attribute(QLatin1String("xmlURL"));
145 
146  bool useCustomFetchInterval = e.attribute(QLatin1String("useCustomFetchInterval")) == QLatin1String("true");
147 
148  QString htmlUrl = e.attribute(QLatin1String("htmlUrl"));
149  QString description = e.attribute(QLatin1String("description"));
150  int fetchInterval = e.attribute(QLatin1String("fetchInterval")).toInt();
151  ArchiveMode archiveMode = stringToArchiveMode(e.attribute(QLatin1String("archiveMode")));
152  int maxArticleAge = e.attribute(QLatin1String("maxArticleAge")).toUInt();
153  int maxArticleNumber = e.attribute(QLatin1String("maxArticleNumber")).toUInt();
154  bool markImmediatelyAsRead = e.attribute(QLatin1String("markImmediatelyAsRead")) == QLatin1String("true");
155  bool useNotification = e.attribute(QLatin1String("useNotification")) == QLatin1String("true");
156  bool loadLinkedWebsite = e.attribute(QLatin1String("loadLinkedWebsite")) == QLatin1String("true");
157  uint id = e.attribute(QLatin1String("id")).toUInt();
158 
159  Feed* const feed = new Feed( storage );
160  feed->setTitle(title);
161  feed->setXmlUrl(xmlUrl);
162  feed->setCustomFetchIntervalEnabled(useCustomFetchInterval);
163  feed->setHtmlUrl(htmlUrl);
164  feed->setId(id);
165  feed->setDescription(description);
166  feed->setArchiveMode(archiveMode);
167  feed->setUseNotification(useNotification);
168  feed->setFetchInterval(fetchInterval);
169  feed->setMaxArticleAge(maxArticleAge);
170  feed->setMaxArticleNumber(maxArticleNumber);
171  feed->setMarkImmediatelyAsRead(markImmediatelyAsRead);
172  feed->setLoadLinkedWebsite(loadLinkedWebsite);
173  feed->loadArticles(); // TODO: make me fly: make this delayed
174 
175  return feed;
176 }
177 
178 bool Akregator::Feed::accept(TreeNodeVisitor* visitor)
179 {
180  if (visitor->visitFeed(this))
181  return true;
182  else
183  return visitor->visitTreeNode(this);
184 }
185 
186 QVector<const Folder*> Akregator::Feed::folders() const
187 {
188  return QVector<const Folder*>();
189 }
190 
191 QVector<Folder*> Akregator::Feed::folders()
192 {
193  return QVector<Folder*>();
194 }
195 
196 QVector<const Akregator::Feed*> Akregator::Feed::feeds() const
197 {
198  QVector<const Akregator::Feed*> list;
199  list.append( this );
200  return list;
201 }
202 
203 QVector<Akregator::Feed*> Akregator::Feed::feeds()
204 {
205  QVector<Feed*> list;
206  list.append( this );
207  return list;
208 }
209 
210 Article Akregator::Feed::findArticle(const QString& guid) const
211 {
212  return d->articles.value(guid);
213 }
214 
215 QList<Article> Akregator::Feed::articles()
216 {
217  if (!d->articlesLoaded)
218  loadArticles();
219  return d->articles.values();
220 }
221 
222 Backend::Storage* Akregator::Feed::storage()
223 {
224  return d->storage;
225 }
226 
227 void Akregator::Feed::loadArticles()
228 {
229  if (d->articlesLoaded)
230  return;
231 
232  if (!d->archive && d->storage)
233  d->archive = d->storage->archiveFor(xmlUrl());
234 
235  QStringList list = d->archive->articles();
236  for ( QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
237  {
238  Article mya(*it, this);
239  d->articles[mya.guid()] = mya;
240  if (mya.isDeleted())
241  d->deletedArticles.append(mya);
242  }
243 
244  d->articlesLoaded = true;
245  enforceLimitArticleNumber();
246  recalcUnreadCount();
247 }
248 
249 void Akregator::Feed::recalcUnreadCount()
250 {
251  QList<Article> tarticles = articles();
252  QList<Article>::ConstIterator it;
253  QList<Article>::ConstIterator en = tarticles.constEnd();
254 
255  int oldUnread = d->archive->unread();
256 
257  int unread = 0;
258 
259  for (it = tarticles.constBegin(); it != en; ++it)
260  if (!(*it).isDeleted() && (*it).status() != Read)
261  ++unread;
262 
263  if (unread != oldUnread)
264  {
265  d->archive->setUnread(unread);
266  nodeModified();
267  }
268 }
269 
270 Akregator::Feed::ArchiveMode Akregator::Feed::stringToArchiveMode(const QString& str)
271 {
272  if (str == QLatin1String("globalDefault"))
273  return globalDefault;
274  if (str == QLatin1String("keepAllArticles"))
275  return keepAllArticles;
276  if (str == QLatin1String("disableArchiving"))
277  return disableArchiving;
278  if (str == QLatin1String("limitArticleNumber"))
279  return limitArticleNumber;
280  if (str == QLatin1String("limitArticleAge"))
281  return limitArticleAge;
282 
283  return globalDefault;
284 }
285 
286 Akregator::Feed::Private::Private( Backend::Storage* storage_, Akregator::Feed* qq )
287  : q( qq ),
288  storage( storage_ ),
289  autoFetch( false ),
290  fetchInterval( 30 ),
291  archiveMode( globalDefault ),
292  maxArticleAge( 60 ),
293  maxArticleNumber( 1000 ),
294  markImmediatelyAsRead( false ),
295  useNotification( false ),
296  loadLinkedWebsite( false ),
297  lastFetched( 0 ),
298  fetchErrorCode( Syndication::Success ),
299  fetchTries( 0 ),
300  followDiscovery( false ),
301  loader( 0 ),
302  articlesLoaded( false ),
303  archive( 0 ),
304  totalCount( -1 )
305 {
306  assert( q );
307  assert( storage );
308 }
309 
310 Akregator::Feed::Feed( Backend::Storage* storage ) : TreeNode(), d( new Private( storage, this ) )
311 {
312 }
313 
314 Akregator::Feed::~Feed()
315 {
316  FeedIconManager::self()->removeListener( this );
317  slotAbortFetch();
318  emitSignalDestroyed();
319  delete d;
320  d = 0;
321 }
322 
323 bool Akregator::Feed::useCustomFetchInterval() const { return d->autoFetch; }
324 
325 void Akregator::Feed::setCustomFetchIntervalEnabled(bool enabled) { d->autoFetch = enabled; }
326 
327 int Akregator::Feed::fetchInterval() const { return d->fetchInterval; }
328 
329 void Akregator::Feed::setFetchInterval(int interval) { d->fetchInterval = interval; }
330 
331 int Akregator::Feed::maxArticleAge() const { return d->maxArticleAge; }
332 
333 void Akregator::Feed::setMaxArticleAge(int maxArticleAge) { d->maxArticleAge = maxArticleAge; }
334 
335 int Akregator::Feed::maxArticleNumber() const { return d->maxArticleNumber; }
336 
337 void Akregator::Feed::setMaxArticleNumber(int maxArticleNumber) { d->maxArticleNumber = maxArticleNumber; }
338 
339 bool Akregator::Feed::markImmediatelyAsRead() const { return d->markImmediatelyAsRead; }
340 
341 bool Akregator::Feed::isFetching() const { return d->loader != 0; }
342 
343 void Akregator::Feed::setMarkImmediatelyAsRead(bool enabled)
344 {
345  d->markImmediatelyAsRead = enabled;
346  if (enabled)
347  createMarkAsReadJob()->start();
348 }
349 
350 void Akregator::Feed::setUseNotification(bool enabled)
351 {
352  d->useNotification = enabled;
353 }
354 
355 bool Akregator::Feed::useNotification() const
356 {
357  return d->useNotification;
358 }
359 
360 void Akregator::Feed::setLoadLinkedWebsite(bool enabled)
361 {
362  d->loadLinkedWebsite = enabled;
363 }
364 
365 bool Akregator::Feed::loadLinkedWebsite() const
366 {
367  return d->loadLinkedWebsite;
368 }
369 
370 QPixmap Akregator::Feed::image() const { return d->imagePixmap; }
371 
372 QString Akregator::Feed::xmlUrl() const { return d->xmlUrl; }
373 
374 void Akregator::Feed::setXmlUrl(const QString& s)
375 {
376  d->xmlUrl = s;
377  if( ! Settings::fetchOnStartup() )
378  QTimer::singleShot(KRandom::random() % 4000, this, SLOT(slotAddFeedIconListener())); // TODO: let's give a gui some time to show up before starting the fetch when no fetch on startup is used. replace this with something proper later...
379 }
380 
381 QString Akregator::Feed::htmlUrl() const { return d->htmlUrl; }
382 
383 void Akregator::Feed::setHtmlUrl(const QString& s) { d->htmlUrl = s; }
384 
385 QString Akregator::Feed::description() const { return d->description; }
386 
387 void Akregator::Feed::setDescription(const QString& s) { d->description = s; }
388 
389 bool Akregator::Feed::fetchErrorOccurred() const { return d->fetchErrorCode != Syndication::Success; }
390 
391 Syndication::ErrorCode Akregator::Feed::fetchErrorCode() const { return d->fetchErrorCode; }
392 
393 bool Akregator::Feed::isArticlesLoaded() const { return d->articlesLoaded; }
394 
395 QDomElement Akregator::Feed::toOPML( QDomElement parent, QDomDocument document ) const
396 {
397  QDomElement el = document.createElement( QLatin1String("outline") );
398  el.setAttribute( QLatin1String("text"), title() );
399  el.setAttribute( QLatin1String("title"), title() );
400  el.setAttribute( QLatin1String("xmlUrl"), d->xmlUrl );
401  el.setAttribute( QLatin1String("htmlUrl"), d->htmlUrl );
402  el.setAttribute( QLatin1String("id"), QString::number(id()) );
403  el.setAttribute( QLatin1String("description"), d->description );
404  el.setAttribute( QLatin1String("useCustomFetchInterval"), (useCustomFetchInterval() ? QLatin1String("true") : QLatin1String("false")) );
405  el.setAttribute( QLatin1String("fetchInterval"), QString::number(fetchInterval()) );
406  el.setAttribute( QLatin1String("archiveMode"), archiveModeToString(d->archiveMode) );
407  el.setAttribute( QLatin1String("maxArticleAge"), d->maxArticleAge );
408  el.setAttribute( QLatin1String("maxArticleNumber"), d->maxArticleNumber );
409  if (d->markImmediatelyAsRead)
410  el.setAttribute( QLatin1String("markImmediatelyAsRead"), QLatin1String("true") );
411  if (d->useNotification)
412  el.setAttribute( QLatin1String("useNotification"), QLatin1String("true") );
413  if (d->loadLinkedWebsite)
414  el.setAttribute( QLatin1String("loadLinkedWebsite"), QLatin1String("true") );
415  el.setAttribute( QLatin1String("maxArticleNumber"), d->maxArticleNumber );
416  el.setAttribute( QLatin1String("type"), QLatin1String("rss") ); // despite some additional fields, it is still "rss" OPML
417  el.setAttribute( QLatin1String("version"), QLatin1String("RSS") );
418  parent.appendChild( el );
419  return el;
420 }
421 
422 KJob* Akregator::Feed::createMarkAsReadJob()
423 {
424  std::auto_ptr<ArticleModifyJob> job( new ArticleModifyJob );
425  Q_FOREACH ( const Article& i, articles() )
426  {
427  const ArticleId aid = { xmlUrl(), i.guid() };
428  job->setStatus( aid, Read );
429  }
430  return job.release();
431 }
432 
433 void Akregator::Feed::slotAddToFetchQueue(FetchQueue* queue, bool intervalFetchOnly)
434 {
435  if (!intervalFetchOnly)
436  queue->addFeed(this);
437  else
438  {
439  int interval = -1;
440 
441  if (useCustomFetchInterval() )
442  interval = fetchInterval() * 60;
443  else
444  if ( Settings::useIntervalFetch() )
445  interval = Settings::autoFetchInterval() * 60;
446 
447  uint lastFetch = d->archive->lastFetch();
448 
449  uint now = QDateTime::currentDateTime().toTime_t();
450 
451  if ( interval > 0 && now - lastFetch >= (uint)interval )
452  queue->addFeed(this);
453  }
454 }
455 
456 void Akregator::Feed::slotAddFeedIconListener()
457 {
458  FeedIconManager::self()->addListener( KUrl( d->xmlUrl ), this );
459 }
460 
461 void Akregator::Feed::appendArticles(const Syndication::FeedPtr feed)
462 {
463  d->setTotalCountDirty();
464  bool changed = false;
465  const bool notify = useNotification() || Settings::useNotifications();
466 
467  QList<ItemPtr> items = feed->items();
468  QList<ItemPtr>::ConstIterator it = items.constBegin();
469  QList<ItemPtr>::ConstIterator en = items.constEnd();
470 
471 
472  int nudge=0;
473 
474  QList<Article> deletedArticles = d->deletedArticles;
475 
476  for ( ; it != en; ++it)
477  {
478  if ( !d->articles.contains((*it)->id()) ) // article not in list
479  {
480  Article mya(*it, this);
481  mya.offsetPubDate(nudge);
482  nudge--;
483  appendArticle(mya);
484  d->addedArticlesNotify.append(mya);
485 
486  if (!mya.isDeleted() && !markImmediatelyAsRead())
487  mya.setStatus(New);
488  else
489  mya.setStatus(Read);
490  if ( notify )
491  NotificationManager::self()->slotNotifyArticle( mya );
492  changed = true;
493  }
494  else // article is in list
495  {
496  // if the article's guid is no hash but an ID, we have to check if the article was updated. That's done by comparing the hash values.
497  Article old = d->articles[(*it)->id()];
498  Article mya(*it, this);
499  if (!mya.guidIsHash() && mya.hash() != old.hash() && !old.isDeleted())
500  {
501  mya.setKeep(old.keep());
502  int oldstatus = old.status();
503  old.setStatus(Read);
504 
505  d->articles.remove(old.guid());
506  appendArticle(mya);
507 
508  mya.setStatus(oldstatus);
509 
510  d->updatedArticlesNotify.append(mya);
511  changed = true;
512  }
513  else if (old.isDeleted())
514  deletedArticles.removeAll(mya);
515  }
516  }
517 
518 
519  QList<Article>::ConstIterator dit = deletedArticles.constBegin();
520  QList<Article>::ConstIterator dtmp;
521  QList<Article>::ConstIterator den = deletedArticles.constEnd();
522 
523  // delete articles with delete flag set completely from archive, which aren't in the current feed source anymore
524  while (dit != den)
525  {
526  dtmp = dit;
527  ++dit;
528  d->articles.remove((*dtmp).guid());
529  d->archive->deleteArticle((*dtmp).guid());
530  d->removedArticlesNotify.append( *dtmp );
531  changed = true;
532  d->deletedArticles.removeAll(*dtmp);
533  }
534 
535  if (changed)
536  articlesModified();
537 }
538 
539 bool Akregator::Feed::usesExpiryByAge() const
540 {
541  return ( d->archiveMode == globalDefault && Settings::archiveMode() == Settings::EnumArchiveMode::limitArticleAge) || d->archiveMode == limitArticleAge;
542 }
543 
544 bool Akregator::Feed::isExpired(const Article& a) const
545 {
546  QDateTime now = QDateTime::currentDateTime();
547  int expiryAge = -1;
548 // check whether the feed uses the global default and the default is limitArticleAge
549  if ( d->archiveMode == globalDefault && Settings::archiveMode() == Settings::EnumArchiveMode::limitArticleAge)
550  expiryAge = Settings::maxArticleAge() *24*3600;
551  else // otherwise check if this feed has limitArticleAge set
552  if ( d->archiveMode == limitArticleAge)
553  expiryAge = d->maxArticleAge *24*3600;
554 
555  return ( expiryAge != -1 && a.pubDate().secsTo(now) > expiryAge);
556 }
557 
558 void Akregator::Feed::appendArticle(const Article& a)
559 {
560  if ( (a.keep() && Settings::doNotExpireImportantArticles()) || ( !usesExpiryByAge() || !isExpired(a) ) ) // if not expired
561  {
562  if (!d->articles.contains(a.guid()))
563  {
564  d->articles[a.guid()] = a;
565  if (!a.isDeleted() && a.status() != Read)
566  setUnread(unread()+1);
567  }
568  }
569 }
570 
571 
572 void Akregator::Feed::fetch(bool followDiscovery)
573 {
574  d->followDiscovery = followDiscovery;
575  d->fetchTries = 0;
576 
577  // mark all new as unread
578  QList<Article> articles = d->articles.values();
579  QList<Article>::Iterator it;
580  QList<Article>::Iterator en = articles.end();
581  for (it = articles.begin(); it != en; ++it)
582  {
583  if ((*it).status() == New)
584  {
585  (*it).setStatus(Unread);
586  }
587  }
588 
589  emit fetchStarted(this);
590 
591  tryFetch();
592 }
593 
594 void Akregator::Feed::slotAbortFetch()
595 {
596  if (d->loader)
597  {
598  d->loader->abort();
599  }
600 }
601 
602 void Akregator::Feed::tryFetch()
603 {
604  d->fetchErrorCode = Syndication::Success;
605 
606  d->loader = Syndication::Loader::create( this, SLOT(fetchCompleted(Syndication::Loader*,
607  Syndication::FeedPtr,
608  Syndication::ErrorCode)) );
609  //connect(d->loader, SIGNAL(progress(ulong)), this, SLOT(slotSetProgress(ulong)));
610  d->loader->loadFrom( d->xmlUrl);
611 }
612 
613 void Akregator::Feed::slotImageFetched(const QPixmap& image)
614 {
615  setImage(image);
616 }
617 
618 void Akregator::Feed::fetchCompleted(Syndication::Loader *l, Syndication::FeedPtr doc, Syndication::ErrorCode status)
619 {
620  // Note that loader instances delete themselves
621  d->loader = 0;
622 
623  // fetching wasn't successful:
624  if (status != Syndication::Success)
625  {
626  if (status == Syndication::Aborted)
627  {
628  d->fetchErrorCode = Syndication::Success;
629  emit fetchAborted(this);
630  }
631  else if (d->followDiscovery && (status == Syndication::InvalidXml) && (d->fetchTries < 3) && (l->discoveredFeedURL().isValid()))
632  {
633  d->fetchTries++;
634  d->xmlUrl = l->discoveredFeedURL().url();
635  emit fetchDiscovery(this);
636  tryFetch();
637  }
638  else
639  {
640  d->fetchErrorCode = status;
641  emit fetchError(this);
642  }
643  markAsFetchedNow();
644  return;
645  }
646 
647  loadArticles(); // TODO: make me fly: make this delayed
648 
649  FeedIconManager::self()->addListener( KUrl( xmlUrl() ), this );
650 
651  d->fetchErrorCode = Syndication::Success;
652 
653  if (d->imagePixmap.isNull())
654  {
655  //QString u = d->xmlUrl;
656  QString imageFileName = KGlobal::dirs()->saveLocation("cache", QLatin1String("akregator/Media/"))
657  + Utils::fileNameForUrl(d->xmlUrl) + QLatin1String(".png");
658  d->imagePixmap=QPixmap(imageFileName, "PNG");
659 
660  // if we ain't got the image and the feed provides one, get it....
661  // TODO: reenable image fetching!
662  if (false) // d->imagePixmap.isNull() && doc.image())
663  {
664  //d->image = *doc.image();
665  //connect(&d->image, SIGNAL(gotPixmap(QPixmap)), this, SLOT(slotImageFetched(QPixmap)));
666  //d->image.getPixmap();
667  }
668  }
669 
670  if (title().isEmpty())
671  setTitle( Syndication::htmlToPlainText( doc->title() ) );
672 
673  d->description = doc->description();
674  d->htmlUrl = doc->link();
675 
676  appendArticles(doc);
677 
678  markAsFetchedNow();
679  emit fetched(this);
680 }
681 
682 void Akregator::Feed::markAsFetchedNow()
683 {
684  if ( d->archive )
685  d->archive->setLastFetch( QDateTime::currentDateTime().toTime_t());
686 }
687 
688 QIcon Akregator::Feed::icon() const
689 {
690  if ( fetchErrorOccurred() )
691  return KIcon(QLatin1String("dialog-error"));
692 
693  return !d->favicon.isNull() ? d->favicon : KIcon(QLatin1String("text-html"));
694 }
695 
696 void Akregator::Feed::deleteExpiredArticles( ArticleDeleteJob* deleteJob )
697 {
698  if ( !usesExpiryByAge() )
699  return;
700 
701  setNotificationMode(false);
702 
703  const QList<Article> articles = d->articles.values();
704  QList<ArticleId> toDelete;
705  const QString feedUrl = xmlUrl();
706  const bool useKeep = Settings::doNotExpireImportantArticles();
707 
708  Q_FOREACH ( const Article& i, articles )
709  {
710  if ( ( !useKeep || !i.keep() ) && isExpired( i ) )
711  {
712  const ArticleId aid = { feedUrl, i.guid() };
713  toDelete.append( aid );
714  }
715  }
716 
717  deleteJob->appendArticleIds( toDelete );
718  setNotificationMode(true);
719 }
720 
721 void Akregator::Feed::setFavicon( const QIcon& icon )
722 {
723  d->favicon = icon;
724  nodeModified();
725 }
726 
727 void Akregator::Feed::setImage(const QPixmap &p)
728 {
729  if (p.isNull())
730  return;
731  d->imagePixmap=p;
732  d->imagePixmap.save(KGlobal::dirs()->saveLocation("cache", QString(QLatin1String("akregator/Media/"))+ Utils::fileNameForUrl(d->xmlUrl) + QLatin1String(".png")),"PNG");
733  nodeModified();
734 }
735 
736 Akregator::Feed::ArchiveMode Akregator::Feed::archiveMode() const
737 {
738  return d->archiveMode;
739 }
740 
741 void Akregator::Feed::setArchiveMode(ArchiveMode archiveMode)
742 {
743  d->archiveMode = archiveMode;
744 }
745 
746 int Akregator::Feed::unread() const
747 {
748  return d->archive ? d->archive->unread() : 0;
749 }
750 
751 void Akregator::Feed::setUnread(int unread)
752 {
753  if (d->archive && unread != d->archive->unread())
754  {
755  d->archive->setUnread(unread);
756  nodeModified();
757  }
758 }
759 
760 
761 void Akregator::Feed::setArticleDeleted(Article& a)
762 {
763  d->setTotalCountDirty();
764  if (!d->deletedArticles.contains(a))
765  d->deletedArticles.append(a);
766 
767  d->updatedArticlesNotify.append(a);
768  articlesModified();
769 }
770 
771 void Akregator::Feed::setArticleChanged(Article& a, int oldStatus)
772 {
773  if (oldStatus != -1)
774  {
775  int newStatus = a.status();
776  if (oldStatus == Read && newStatus != Read)
777  setUnread(unread()+1);
778  else if (oldStatus != Read && newStatus == Read)
779  setUnread(unread()-1);
780  }
781  d->updatedArticlesNotify.append(a);
782  articlesModified();
783 }
784 
785 int Akregator::Feed::totalCount() const
786 {
787  if ( d->totalCount == -1 )
788  d->totalCount = std::count_if( d->articles.constBegin(), d->articles.constEnd(), !bind( &Article::isDeleted, _1 ) );
789  return d->totalCount;
790 }
791 
792 TreeNode* Akregator::Feed::next()
793 {
794  if ( nextSibling() )
795  return nextSibling();
796 
797  Folder* p = parent();
798  while (p)
799  {
800  if ( p->nextSibling() )
801  return p->nextSibling();
802  else
803  p = p->parent();
804  }
805  return 0;
806 }
807 
808 
809 const TreeNode* Akregator::Feed::next() const
810 {
811  if ( nextSibling() )
812  return nextSibling();
813 
814  const Folder* p = parent();
815  while (p)
816  {
817  if ( p->nextSibling() )
818  return p->nextSibling();
819  else
820  p = p->parent();
821  }
822  return 0;
823 }
824 
825 void Akregator::Feed::doArticleNotification()
826 {
827  if (!d->addedArticlesNotify.isEmpty())
828  {
829  // copy list, otherwise the refcounting in Article::Private breaks for
830  // some reason (causing segfaults)
831  QList<Article> l = d->addedArticlesNotify;
832  emit signalArticlesAdded(this, l);
833  d->addedArticlesNotify.clear();
834  }
835  if (!d->updatedArticlesNotify.isEmpty())
836  {
837  // copy list, otherwise the refcounting in Article::Private breaks for
838  // some reason (causing segfaults)
839  QList<Article> l = d->updatedArticlesNotify;
840  emit signalArticlesUpdated(this, l);
841  d->updatedArticlesNotify.clear();
842  }
843  if (!d->removedArticlesNotify.isEmpty())
844  {
845  // copy list, otherwise the refcounting in Article::Private breaks for
846  // some reason (causing segfaults)
847  QList<Article> l = d->removedArticlesNotify;
848  emit signalArticlesRemoved(this, l);
849  d->removedArticlesNotify.clear();
850  }
851  TreeNode::doArticleNotification();
852 }
853 
854 void Akregator::Feed::enforceLimitArticleNumber()
855 {
856  int limit = -1;
857  if (d->archiveMode == globalDefault && Settings::archiveMode() == Settings::EnumArchiveMode::limitArticleNumber)
858  limit = Settings::maxArticleNumber();
859  else if (d->archiveMode == limitArticleNumber)
860  limit = maxArticleNumber();
861 
862  if (limit == -1 || limit >= d->articles.count() - d->deletedArticles.count())
863  return;
864 
865  QList<Article> articles = d->articles.values();
866  qSort(articles);
867 
868  int c = 0;
869  const bool useKeep = Settings::doNotExpireImportantArticles();
870 
871  Q_FOREACH ( Article i, articles ) //krazy:exclude=foreach
872  {
873  if (c < limit)
874  {
875  if ( !i.isDeleted() && ( !useKeep || !i.keep() ) )
876  ++c;
877  }
878  else if ( !useKeep || !i.keep() )
879  {
880  i.setDeleted();
881  }
882  }
883 }
Akregator::Feed::totalCount
int totalCount() const
returns the number of total articles in this feed
Definition: feed.cpp:785
Akregator::Feed::maxArticleAge
int maxArticleAge() const
returns the maximum age of articles used for expiration by age (used in limitArticleAge archive mode)...
Definition: feed.cpp:331
Akregator::Feed::feeds
QVector< const Feed * > feeds() const
Definition: feed.cpp:196
Akregator::Feed::accept
bool accept(TreeNodeVisitor *visitor)
Definition: feed.cpp:178
Syndication::ItemPtr
boost::shared_ptr< Item > ItemPtr
Definition: article.h:50
Akregator::Feed::useCustomFetchInterval
bool useCustomFetchInterval() const
returns whether this feed uses its own fetch interval or the global setting
Definition: feed.cpp:323
Akregator::Feed::icon
QIcon icon() const
Definition: feed.cpp:688
types.h
QList::remove
iterator remove(iterator pos)
Akregator::Feed::useNotification
bool useNotification() const
Definition: feed.cpp:355
QDomNode::appendChild
QDomNode appendChild(const QDomNode &newChild)
Akregator::FeedIconManager::removeListener
void removeListener(FaviconListener *listener)
Definition: feediconmanager.cpp:134
QVector::append
void append(const T &value)
Akregator::Feed::setMarkImmediatelyAsRead
void setMarkImmediatelyAsRead(bool enabled)
Definition: feed.cpp:343
Akregator::Feed::toOPML
QDomElement toOPML(QDomElement parent, QDomDocument document) const
exports the feed settings to OPML
Definition: feed.cpp:395
Akregator::Feed::fromOPML
static Feed * fromOPML(QDomElement e, Akregator::Backend::Storage *storage)
creates a Feed object from a description in OPML format
Definition: feed.cpp:134
QDomElement::attribute
QString attribute(const QString &name, const QString &defValue) const
Akregator::Utils::fileNameForUrl
static QString fileNameForUrl(const QString &url)
returns a file name for a URL, with chars like "/" ":" replaced by "_".
Definition: utils.cpp:42
Akregator::Feed::setFetchInterval
void setFetchInterval(int interval)
Sets custom auto fetch interval.
Definition: feed.cpp:329
Akregator::Feed::unread
int unread() const
returns the unread count for this feed
Definition: feed.cpp:746
articlejobs.h
uint
unsigned int uint
Definition: article.h:41
Akregator::Feed::setUseNotification
void setUseNotification(bool enabled)
Definition: feed.cpp:350
Akregator::NotificationManager::slotNotifyArticle
void slotNotifyArticle(const Akregator::Article &article)
notifies an article.
Definition: notificationmanager.cpp:60
Akregator::Feed::fetchInterval
int fetchInterval() const
Returns custom auto fetch interval of this feed.
Definition: feed.cpp:327
Akregator::Feed::markImmediatelyAsRead
bool markImmediatelyAsRead() const
if true, new articles are marked immediately as read instead of new/unread.
Definition: feed.cpp:339
Akregator::Backend::Storage
Storage is the main interface to the article archive.
Definition: storage.h:43
Akregator::Feed::~Feed
~Feed()
Definition: feed.cpp:314
Akregator::TreeNode::setId
virtual void setId(uint id)
sets the ID
Definition: treenode.cpp:203
Akregator::Feed::setMaxArticleNumber
void setMaxArticleNumber(int maxArticleNumber)
sets the article count limit used in limitArticleNumber archive mode
Definition: feed.cpp:337
Akregator::New
article was fetched in the last fetch of it's feed and not read yet.
Definition: types.h:33
Akregator::FetchQueue::addFeed
void addFeed(Feed *f)
adds a feed to the queue
Definition: fetchqueue.cpp:71
feed.h
Akregator::TreeNode::parent
virtual const Folder * parent() const
Returns the parent node.
Definition: treenode.cpp:141
treenodevisitor.h
utils.h
Akregator::Feed::folders
QVector< const Folder * > folders() const
Definition: feed.cpp:186
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
QPixmap::save
bool save(const QString &fileName, const char *format, int quality) const
Akregator::Feed::fetchErrorCode
Syndication::ErrorCode fetchErrorCode() const
Definition: feed.cpp:391
Akregator::Feed::setFavicon
void setFavicon(const QIcon &icon)
sets the favicon (used in the tree view)
Definition: feed.cpp:721
QDomElement::hasAttribute
bool hasAttribute(const QString &name) const
Akregator::Feed::next
const TreeNode * next() const
returns the next node in the tree.
Definition: feed.cpp:809
QHash
Definition: feedlist.h:41
Akregator::NotificationManager::self
static NotificationManager * self()
singleton instance of notification manager
Definition: notificationmanager.cpp:130
QDomElement::setAttribute
void setAttribute(const QString &name, const QString &value)
QString::toInt
int toInt(bool *ok, int base) const
QString::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
Akregator::Feed::archiveMode
ArchiveMode archiveMode() const
returns the archiving mode which is used for this feed
Definition: feed.cpp:736
Akregator::TreeNode::setTitle
void setTitle(const QString &title)
Sets the title of the node.
Definition: treenode.cpp:92
Akregator::Article::keep
bool keep() const
if true, the article should be kept even when expired
Definition: article.cpp:495
Akregator::ArticleModifyJob
Definition: articlejobs.h:88
Akregator::Feed::fetch
void fetch(bool followDiscovery=false)
starts fetching
Definition: feed.cpp:572
Akregator::Read
article is read
Definition: types.h:32
fetchqueue.h
Akregator::Feed::slotAbortFetch
void slotAbortFetch()
Definition: feed.cpp:594
Akregator::Feed::xmlUrl
QString xmlUrl() const
returns the url of the actual feed source (rss/rdf/atom file)
Definition: feed.cpp:372
Akregator::Backend::FeedStorage
Definition: feedstorage.h:66
QString
QList
Definition: article.h:41
article.h
storage.h
Akregator::Article::isDeleted
bool isDeleted() const
Definition: article.cpp:279
Akregator::Feed::htmlUrl
QString htmlUrl() const
returns the URL of the HTML page of this feed
Definition: feed.cpp:381
Akregator::ArticleId
Definition: articlejobs.h:48
QStringList
Akregator::Article::hash
uint hash() const
returns a hash value used to detect changes in articles with non-hash GUIDs.
Definition: article.cpp:490
Akregator::Article::guid
QString guid() const
Definition: article.cpp:463
QPixmap
QList::end
iterator end()
Akregator::Feed::ArchiveMode
ArchiveMode
the archiving modes
Definition: feed.h:61
Akregator::Feed::isArticlesLoaded
bool isArticlesLoaded() const
returns if the article archive of this feed is loaded
Definition: feed.cpp:393
QPixmap::isNull
bool isNull() const
Akregator::Feed::image
QPixmap image() const
returns the feed image
Definition: feed.cpp:370
QDomDocument
Akregator::Feed::setLoadLinkedWebsite
void setLoadLinkedWebsite(bool enabled)
if true, the linked URL is loaded directly in the article viewer instead of showing the description ...
Definition: feed.cpp:360
folder.h
Akregator::ArticleDeleteJob::appendArticleIds
void appendArticleIds(const Akregator::ArticleIdList &ids)
Definition: articlejobs.cpp:47
QDateTime::toTime_t
uint toTime_t() const
Akregator::TreeNode::doArticleNotification
virtual void doArticleNotification()
reimplement this in subclasses to do the actual notification called by articlesModified ...
Definition: treenode.cpp:224
Akregator::Feed::Feed
Feed(Akregator::Backend::Storage *storage)
default constructor
Definition: feed.cpp:310
Akregator::Article::pubDate
QDateTime pubDate() const
Definition: article.cpp:511
Akregator::Feed::loadLinkedWebsite
bool loadLinkedWebsite() const
Definition: feed.cpp:365
Akregator::Feed::slotAddToFetchQueue
void slotAddToFetchQueue(Akregator::FetchQueue *queue, bool intervalFetchOnly=false)
add this feed to the fetch queue queue
Definition: feed.cpp:433
Akregator::Feed::setXmlUrl
void setXmlUrl(const QString &s)
sets the url of the actual feed source (rss/rdf/atom file)
Definition: feed.cpp:374
QDateTime::currentDateTime
QDateTime currentDateTime()
Akregator::TreeNode::nextSibling
virtual const TreeNode * nextSibling() const
Get the next sibling.
Definition: treenode.cpp:112
Akregator::Feed::slotAddFeedIconListener
void slotAddFeedIconListener()
Definition: feed.cpp:456
Akregator::TreeNodeVisitor::visitFeed
virtual bool visitFeed(Feed *)
Definition: treenodevisitor.h:42
QVector
Akregator::ArticleDeleteJob
Definition: articlejobs.h:69
Akregator::Feed::description
QString description() const
returns the description of this feed
Definition: feed.cpp:385
Akregator::Unread
article wasn't read yet by the user
Definition: types.h:31
QLatin1String
QDateTime::secsTo
int secsTo(const QDateTime &other) const
Akregator::TreeNodeVisitor
Definition: treenodevisitor.h:35
Akregator::Feed::stringToArchiveMode
static ArchiveMode stringToArchiveMode(const QString &str)
converts strings to ArchiveMode value if parsing fails, it returns ArchiveMode::globalDefault ...
Definition: feed.cpp:270
Akregator::Feed
represents a feed
Definition: feed.h:53
Akregator::Folder
Represents a folder (containing feeds and/or other folders)
Definition: folder.h:44
Akregator::Feed::findArticle
Article findArticle(const QString &guid) const
returns article by guid
Definition: feed.cpp:210
Akregator::Feed::deleteExpiredArticles
void deleteExpiredArticles(Akregator::ArticleDeleteJob *job)
deletes expired articles
Definition: feed.cpp:696
QList::ConstIterator
typedef ConstIterator
Akregator::Feed::setArchiveMode
void setArchiveMode(ArchiveMode archiveMode)
sets the archiving mode for this feed
Definition: feed.cpp:741
Akregator::FeedIconManager::addListener
void addListener(const KUrl &url, FaviconListener *listener)
Definition: feediconmanager.cpp:123
Akregator::Feed::maxArticleNumber
int maxArticleNumber() const
returns the article count limit used in limitArticleNumber archive mode
Definition: feed.cpp:335
Akregator::Article
A proxy class for Syndication::ItemPtr with some additional methods to assist sorting.
Definition: article.h:63
Akregator::Article::status
int status() const
Definition: article.cpp:338
Akregator::Feed::fetchErrorOccurred
bool fetchErrorOccurred() const
returns whether a fetch error has occurred
Definition: feed.cpp:389
Akregator::Feed::createMarkAsReadJob
KJob * createMarkAsReadJob()
Definition: feed.cpp:422
notificationmanager.h
QList::constEnd
const_iterator constEnd() const
feediconmanager.h
QDomDocument::createElement
QDomElement createElement(const QString &tagName)
QList::constBegin
const_iterator constBegin() const
Akregator::Feed::setMaxArticleAge
void setMaxArticleAge(int maxArticleAge)
sets the maximum age of articles used for expiration by age (used in limitArticleAge archive mode) ...
Definition: feed.cpp:333
Akregator::Feed::setHtmlUrl
void setHtmlUrl(const QString &s)
sets the URL of the HTML page of this feed
Definition: feed.cpp:383
feedstorage.h
QDomElement
Akregator::TreeNode
Abstract base class for all kind of elements in the feed tree, like feeds and feed groups (and search...
Definition: treenode.h:58
KJob
QList::begin
iterator begin()
Akregator::FetchQueue
Definition: fetchqueue.h:37
Akregator::Feed::setImage
void setImage(const QPixmap &p)
sets the feed image
Definition: feed.cpp:727
Akregator::FeedIconManager::self
static FeedIconManager * self()
Definition: feediconmanager.cpp:115
QIcon
QDateTime
Akregator::Feed::setCustomFetchIntervalEnabled
void setCustomFetchIntervalEnabled(bool enabled)
set if the feed has its custom fetch interval or uses the global setting
Definition: feed.cpp:325
Akregator::Feed::setDescription
void setDescription(const QString &s)
sets the description of this feed
Definition: feed.cpp:387
Akregator::TreeNodeVisitor::visitTreeNode
virtual bool visitTreeNode(TreeNode *)
Definition: treenodevisitor.h:40
Akregator::Feed::archiveModeToString
static QString archiveModeToString(ArchiveMode mode)
converts ArchiveMode values to corresponding strings
Definition: feed.cpp:116
QString::toUInt
uint toUInt(bool *ok, int base) const
QTimer::singleShot
singleShot
Akregator::Feed::isFetching
bool isFetching() const
Definition: feed.cpp:341
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:00 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akregator

Skip menu "akregator"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal