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

akregator

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

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