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

akregator

article.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
00005                   2005 Frank Osterfeld <osterfeld@kde.org>
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include "article.h"
00026 #include "feed.h"
00027 #include "feedstorage.h"
00028 #include "shared.h"
00029 #include "storage.h"
00030 #include "utils.h"
00031 
00032 #include <syndication/syndication.h>
00033 
00034 #include <QDateTime>
00035 #include <qdom.h>
00036 #include <QRegExp>
00037 #include <QList>
00038 
00039 #include <kdebug.h>
00040 #include <kurl.h>
00041 
00042 #include <cassert>
00043 
00044 using namespace Syndication;
00045 
00046 namespace {
00047 
00048 QString buildTitle(const QString& description)
00049 {
00050     QString s = description;
00051     if (description.trimmed().isEmpty())
00052         return "";
00053 
00054     int i = s.indexOf('>',500); /*avoid processing too much */
00055     if (i != -1)
00056         s = s.left(i+1);
00057     QRegExp rx("(<([^\\s>]*)(?:[^>]*)>)[^<]*", Qt::CaseInsensitive);
00058     QString tagName, toReplace, replaceWith;
00059     while (rx.indexIn(s) != -1 )
00060     {
00061         tagName=rx.cap(2);
00062         if (tagName=="SCRIPT"||tagName=="script")
00063             toReplace=rx.cap(0); // strip tag AND tag contents
00064         else if (tagName.startsWith("br") || tagName.startsWith("BR"))
00065         {
00066             toReplace=rx.cap(1);
00067             replaceWith=" ";
00068         }
00069         else
00070             toReplace=rx.cap(1);  // strip just tag
00071         s=s.replace(s.indexOf(toReplace),toReplace.length(),replaceWith); // do the deed
00072     }
00073     if (s.length()> 90)
00074         s=s.left(90)+"...";
00075     return s.simplified();
00076 }
00077 
00078 }
00079 
00080 namespace Akregator {
00081 
00082 struct Article::Private : public Shared
00083 {
00084     Private();
00085     Private( const QString& guid, Feed* feed, Backend::FeedStorage* archive );
00086     Private( const ItemPtr& article, Feed* feed, Backend::FeedStorage* archive );
00087 
00097     enum Status
00098     {
00099         Deleted=0x01,
00100         Trash=0x02,
00101         New=0x04,
00102         Read=0x08,
00103         Keep=0x10
00104     };
00105 
00106     Feed* feed;
00107     QString guid;
00108     Backend::FeedStorage* archive;
00109     int status;
00110     uint hash;
00111     QDateTime pubDate;
00112 };
00113 
00114 Article::Private::Private()
00115   : feed( 0 ),
00116     archive( 0 ),
00117     status( 0 ),
00118     hash( 0 ),
00119     pubDate( QDateTime::fromTime_t( 1 ) )
00120 {
00121 }
00122 
00123 Article::Private::Private( const QString& guid_, Feed* feed_, Backend::FeedStorage* archive_ )
00124   : feed( feed_ ),
00125     guid( guid_ ),
00126     archive( archive_ ),
00127     status( archive->status( guid ) ),
00128     hash( archive->hash( guid ) ),
00129     pubDate( QDateTime::fromTime_t( archive->pubDate( guid ) ) )
00130 {
00131 }
00132 
00133 Article::Private::Private( const ItemPtr& article, Feed* feed_, Backend::FeedStorage* archive_ )
00134   : feed( feed_ ),
00135     archive( archive_ ),
00136     status ( New ),
00137     hash( 0 )
00138 {
00139     assert( archive );
00140     const QList<PersonPtr> authorList = article->authors();
00141 
00142     QString author;
00143 
00144     const PersonPtr firstAuthor = !authorList.isEmpty() ? authorList.first() : PersonPtr();
00145 
00146     hash = Utils::calcHash(article->title() + article->description() + article->content() + article->link() + author);
00147 
00148     guid = article->id();
00149 
00150     if (!archive->contains(guid))
00151     {
00152         archive->addEntry(guid);
00153 
00154         archive->setHash(guid, hash);
00155         QString title = article->title();
00156         if (title.isEmpty())
00157             title = buildTitle(article->description());
00158         archive->setTitle(guid, title);
00159         archive->setContent(guid, article->content());
00160         archive->setDescription(guid, article->description());
00161         archive->setLink(guid, article->link());
00162         //archive->setComments(guid, article.comments());
00163         //archive->setCommentsLink(guid, article.commentsLink().url());
00164         archive->setGuidIsPermaLink(guid, false);
00165         archive->setGuidIsHash(guid, guid.startsWith("hash:"));
00166         const time_t datePublished = article->datePublished();
00167         if ( datePublished > 0 )
00168             pubDate.setTime_t( datePublished );
00169         else
00170             pubDate = QDateTime::currentDateTime();
00171         archive->setPubDate(guid, pubDate.toTime_t());
00172         if ( firstAuthor ) {
00173             archive->setAuthorName(guid, firstAuthor->name() );
00174             archive->setAuthorUri(guid, firstAuthor->uri() );
00175             archive->setAuthorEMail(guid, firstAuthor->email() );
00176         }
00177     }
00178     else
00179     {
00180         // always update comments count, as it's not used for hash calculation
00181         //archive->setComments(guid, article.comments());
00182         if (hash != archive->hash(guid)) //article is in archive, was it modified?
00183         { // if yes, update
00184             pubDate.setTime_t(archive->pubDate(guid));
00185             archive->setHash(guid, hash);
00186             QString title = article->title();
00187             if (title.isEmpty())
00188                 title = buildTitle(article->description());
00189             archive->setTitle(guid, title);
00190             archive->setDescription(guid, article->description());
00191             archive->setContent(guid, article->content());
00192             archive->setLink(guid, article->link());
00193             if ( firstAuthor ) {
00194                 archive->setAuthorName(guid, firstAuthor->name() );
00195                 archive->setAuthorUri(guid, firstAuthor->uri() );
00196                 archive->setAuthorEMail(guid, firstAuthor->email() );
00197             }
00198             //archive->setCommentsLink(guid, article.commentsLink());
00199         }
00200     }
00201 
00202 }
00203 
00204 
00205 Article::Article() : d( new Private )
00206 {
00207 }
00208 
00209 Article::Article( const QString& guid, Feed* feed ) : d( new Private( guid, feed, feed->storage()->archiveFor( feed->xmlUrl() ) ) )
00210 {
00211 }
00212 
00213 Article::Article( const ItemPtr& article, Feed* feed ) : d( new Private( article, feed, feed->storage()->archiveFor( feed->xmlUrl() ) ) )
00214 {
00215 }
00216 
00217 Article::Article( const ItemPtr& article, Backend::FeedStorage* archive ) : d( new Private( article, 0, archive ) )
00218 {
00219 }
00220 
00221 bool Article::isNull() const
00222 {
00223     return d->archive == 0; // TODO: use proper null state
00224 }
00225 
00226 void Article::offsetPubDate(int secs)
00227 {
00228    d->pubDate = d->pubDate.addSecs(secs);
00229    d->archive->setPubDate(d->guid, d->pubDate.toTime_t());
00230 
00231 }
00232 
00233 void Article::setDeleted()
00234 {
00235     if (isDeleted())
00236         return;
00237 
00238     setStatus(Read);
00239     d->status = Private::Deleted | Private::Read;
00240     d->archive->setStatus(d->guid, d->status);
00241     d->archive->setDeleted(d->guid);
00242 
00243     if (d->feed)
00244         d->feed->setArticleDeleted(*this);
00245 }
00246 
00247 bool Article::isDeleted() const
00248 {
00249     return (d->status & Private::Deleted) != 0;
00250 }
00251 
00252 Article::Article(const Article &other) : d( other.d )
00253 {
00254     d->ref();
00255 }
00256 
00257 Article::~Article()
00258 {
00259     if ( d->deref() )
00260     {
00261         delete d;
00262         d = 0;
00263     }
00264 }
00265 
00266 Article &Article::operator=(const Article &other)
00267 {
00268     Article copy( other );
00269     swap( copy );
00270     return *this;
00271 }
00272 
00273 
00274 bool Article::operator<(const Article &other) const
00275 {
00276     return pubDate() > other.pubDate() ||
00277             (pubDate() == other.pubDate() && guid() < other.guid() );
00278 }
00279 
00280 bool Article::operator<=(const Article &other) const
00281 {
00282     return (pubDate() > other.pubDate() || *this == other);
00283 }
00284 
00285 bool Article::operator>(const Article &other) const
00286 {
00287     return pubDate() < other.pubDate() ||
00288             (pubDate() == other.pubDate() && guid() > other.guid() );
00289 }
00290 
00291 bool Article::operator>=(const Article &other) const
00292 {
00293     return (pubDate() > other.pubDate() || *this == other);
00294 }
00295 
00296 bool Article::operator==(const Article &other) const
00297 {
00298     return d->guid == other.guid();
00299 }
00300 
00301 bool Article::operator!=(const Article &other) const
00302 {
00303     return d->guid != other.guid();
00304 }
00305 
00306 int Article::status() const
00307 {
00308     if ((d->status & Private::Read) != 0)
00309         return Read;
00310 
00311     if ((d->status & Private::New) != 0)
00312         return New;
00313 
00314     return Unread;
00315 }
00316 
00317 void Article::setStatus(int stat)
00318 {
00319     int oldStatus = status();
00320 
00321     if (oldStatus != stat)
00322     {
00323         switch (stat)
00324         {
00325             case Read:
00326                 d->status = (d->status | Private::Read) & ~Private::New;
00327                 break;
00328             case Unread:
00329                 d->status = (d->status & ~Private::Read) & ~Private::New;
00330                 break;
00331             case New:
00332                 d->status = (d->status | Private::New) & ~Private::Read;
00333                 break;
00334         }
00335         d->archive->setStatus(d->guid, d->status);
00336         if (d->feed)
00337             d->feed->setArticleChanged(*this, oldStatus);
00338      }
00339 }
00340 
00341 QString Article::title() const
00342 {
00343     return d->archive->title(d->guid);
00344 }
00345 
00346 QString Article::authorName() const
00347 {
00348     return d->archive->authorName(d->guid);
00349 }
00350 
00351 QString Article::authorEMail() const
00352 {
00353     return d->archive->authorEMail(d->guid);
00354 }
00355 
00356 QString Article::authorUri() const
00357 {
00358     return d->archive->authorUri(d->guid);
00359 }
00360 QString Article::authorShort() const {
00361     const QString name = authorName();
00362     if ( !name.isEmpty() )
00363         return name;
00364     const QString email = authorEMail();
00365     if ( !email.isEmpty() )
00366         return email;
00367     const QString uri = authorUri();
00368     if ( !uri.isEmpty() )
00369         return uri;
00370     return QString();
00371 }
00372 
00373 QString Article::authorAsHtml() const {
00374     const QString name = authorName();
00375     const QString email = authorEMail();
00376 
00377     if (!email.isEmpty())
00378         if (!name.isEmpty())
00379             return QString("<a href=\"mailto:%1\">%2</a>").arg( email, name );
00380         else
00381             return QString("<a href=\"mailto:%1\">%1</a>").arg( email );
00382 
00383     const QString uri = authorUri();
00384     if (!name.isEmpty())
00385         if (!uri.isEmpty())
00386                 return QString("<a href=\"%1\">%2</a>").arg( uri, name );
00387             else
00388                 return name;
00389     if ( !uri.isEmpty() )
00390         return QString( "<a href=\"%1\">%1</a>" ).arg( uri );
00391     return QString();
00392 }
00393 
00394 KUrl Article::link() const
00395 {
00396     return d->archive->link(d->guid);
00397 }
00398 
00399 QString Article::description() const
00400 {
00401     return d->archive->description(d->guid);
00402 }
00403 
00404 QString Article::content( ContentOption opt ) const
00405 {
00406     const QString cnt = d->archive->content( d->guid );
00407     return opt == ContentAndOnlyContent ? cnt : ( !cnt.isEmpty() ? cnt : description() );
00408 }
00409 
00410 QString Article::guid() const
00411 {
00412     return d->guid;
00413 }
00414 
00415 KUrl Article::commentsLink() const
00416 {
00417     return d->archive->commentsLink(d->guid);
00418 }
00419 
00420 
00421 int Article::comments() const
00422 {
00423     return d->archive->comments(d->guid);
00424 }
00425 
00426 
00427 bool Article::guidIsPermaLink() const
00428 {
00429     return d->archive->guidIsPermaLink(d->guid);
00430 }
00431 
00432 bool Article::guidIsHash() const
00433 {
00434     return d->archive->guidIsHash(d->guid);
00435 }
00436 
00437 uint Article::hash() const
00438 {
00439     return d->hash;
00440 }
00441 
00442 bool Article::keep() const
00443 {
00444     return (d->status & Private::Keep) != 0;
00445 }
00446 
00447 void Article::setKeep(bool keep)
00448 {
00449     d->status = keep ? (d->status | Private::Keep) : (d->status & ~Private::Keep);
00450     d->archive->setStatus(d->guid, d->status);
00451     if (d->feed)
00452         d->feed->setArticleChanged(*this);
00453 }
00454 
00455 Feed* Article::feed() const
00456 { return d->feed; }
00457 
00458 const QDateTime& Article::pubDate() const
00459 {
00460     return d->pubDate;
00461 }
00462 
00463 } // namespace Akregator

akregator

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

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal