32 #include <syndication/syndication.h>
44 using namespace boost;
45 using namespace Syndication;
49 QString buildTitle(
const QString& description)
51 QString s = description;
52 if (description.trimmed().isEmpty())
55 int i = s.indexOf(QLatin1Char(
'>'),500);
58 QRegExp rx(QLatin1String(
"(<([^\\s>]*)(?:[^>]*)>)[^<]*"), Qt::CaseInsensitive);
59 QString tagName, toReplace, replaceWith;
60 while (rx.indexIn(s) != -1 )
63 if (tagName==QLatin1String(
"SCRIPT")||tagName==QLatin1String(
"script"))
65 else if (tagName.startsWith(QLatin1String(
"br")) || tagName.startsWith(QLatin1String(
"BR")))
68 replaceWith=QLatin1Char(
' ');
72 s=s.replace(s.indexOf(toReplace),toReplace.length(),replaceWith);
75 s=s.left(90)+QLatin1String(
"...");
76 return s.simplified();
83 struct Article::Private :
public Shared
86 Private(
const QString& guid, Feed* feed, Backend::FeedStorage* archive );
87 Private(
const ItemPtr& article, Feed* feed, Backend::FeedStorage* archive );
109 Backend::FeedStorage* archive;
113 mutable shared_ptr<const Enclosure> enclosure;
117 class EnclosureImpl :
public Enclosure
120 EnclosureImpl(
const QString& url,
const QString& type,
uint length ) :
m_url( url ),
m_type( type ),
m_length( length ) {}
121 QString url()
const {
return m_url; }
122 QString type()
const {
return m_type; }
123 QString title()
const {
return m_title; }
125 uint duration()
const {
return 0; }
126 bool isNull()
const {
return m_url.isNull(); }
135 Article::Private::Private()
140 pubDate( QDateTime::fromTime_t( 1 ) )
144 Article::Private::Private(
const QString& guid_, Feed* feed_, Backend::FeedStorage* archive_ )
148 status( archive->status( guid ) ),
149 hash( archive->hash( guid ) ),
150 pubDate( QDateTime::fromTime_t( archive->pubDate( guid ) ) )
154 Article::Private::Private(
const ItemPtr& article, Feed* feed_, Backend::FeedStorage* archive_ )
165 const PersonPtr firstAuthor = !authorList.isEmpty() ? authorList.first() : PersonPtr();
167 hash = Utils::calcHash(article->title() + article->description() + article->content() + article->link() + author);
169 guid = article->id();
171 if (!archive->contains(guid))
173 archive->addEntry(guid);
175 archive->setHash(guid, hash);
176 QString title = article->title();
178 title = buildTitle(article->description());
179 archive->setTitle(guid, title);
180 archive->setContent(guid, article->content());
181 archive->setDescription(guid, article->description());
182 archive->setLink(guid, article->link());
185 archive->setGuidIsPermaLink(guid,
false);
186 archive->setGuidIsHash(guid, guid.startsWith(QLatin1String(
"hash:")));
187 const time_t datePublished = article->datePublished();
188 if ( datePublished > 0 )
189 pubDate.setTime_t( datePublished );
191 pubDate = QDateTime::currentDateTime();
192 archive->setPubDate(guid, pubDate.toTime_t());
194 archive->setAuthorName(guid, firstAuthor->name() );
195 archive->setAuthorUri(guid, firstAuthor->uri() );
196 archive->setAuthorEMail(guid, firstAuthor->email() );
199 if ( !encs.isEmpty() )
201 archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length());
208 if (hash != archive->hash(guid))
210 pubDate.setTime_t(archive->pubDate(guid));
211 archive->setHash(guid, hash);
212 QString title = article->title();
214 title = buildTitle(article->description());
215 archive->setTitle(guid, title);
216 archive->setDescription(guid, article->description());
217 archive->setContent(guid, article->content());
218 archive->setLink(guid, article->link());
220 archive->setAuthorName(guid, firstAuthor->name() );
221 archive->setAuthorUri(guid, firstAuthor->uri() );
222 archive->setAuthorEMail(guid, firstAuthor->email() );
231 archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length());
237 Article::Article() : d( new Private )
241 Article::Article(
const QString& guid,
Feed* feed ) : d( new Private( guid, feed, feed->storage()->archiveFor( feed->xmlUrl() ) ) )
255 return d->archive == 0;
260 d->pubDate = d->pubDate.addSecs(secs);
261 d->archive->setPubDate(d->guid, d->pubDate.toTime_t());
265 void Article::setDeleted()
272 d->archive->setStatus(d->guid, d->status);
273 d->archive->setDeleted(d->guid);
276 d->feed->setArticleDeleted(*
this);
281 return (d->status & Private::Deleted) != 0;
330 return d->guid == other.
guid();
335 return d->guid != other.
guid();
349 void Article::setStatus(
int stat)
353 if (oldStatus != stat)
368 d->archive->setStatus(d->guid, d->status);
370 d->feed->setArticleChanged(*
this, oldStatus);
378 str = d->archive->title(d->guid);
387 str = d->archive->authorName(d->guid);
396 str = d->archive->authorEMail(d->guid);
405 str = d->archive->authorUri(d->guid);
412 if ( !name.isEmpty() )
415 if ( !email.isEmpty() )
418 if ( !uri.isEmpty() )
427 if (!email.isEmpty()) {
429 return QString::fromLatin1(
"<a href=\"mailto:%1\">%2</a>").arg( email, name );
431 return QString::fromLatin1(
"<a href=\"mailto:%1\">%1</a>").arg( email );
435 if (!name.isEmpty()) {
437 return QString::fromLatin1(
"<a href=\"%1\">%2</a>").arg( uri, name );
442 if ( !uri.isEmpty() )
443 return QString::fromLatin1(
"<a href=\"%1\">%1</a>" ).arg( uri );
449 return d->archive->link(d->guid);
454 return d->archive->description(d->guid);
459 const QString cnt = d->archive->content( d->guid );
470 return d->archive->commentsLink(d->guid);
476 return d->archive->comments(d->guid);
482 return d->archive->guidIsPermaLink(d->guid);
487 return d->archive->guidIsHash(d->guid);
497 return (d->status & Private::Keep) != 0;
500 void Article::setKeep(
bool keep)
502 d->status = keep ? (d->status | Private::Keep) : (d->status & ~Private::Keep);
503 d->archive->setStatus(d->guid, d->status);
505 d->feed->setArticleChanged(*
this);
524 d->archive->enclosure( d->guid, hasEnc, url, type, length );
526 d->enclosure.reset(
new EnclosureImpl( url, type, static_cast<uint>( length ) ) );
528 d->enclosure.reset(
new EnclosureImpl( QString(), QString(), 0 ) );
boost::shared_ptr< Item > ItemPtr
bool operator<(const Article &other) const
bool guidIsHash() const
returns if the guid is a hash or an ID taken from the source
bool operator>(const Article &other) const
Article & operator=(const Article &other)
KUrl commentsLink() const
article was fetched in the last fetch of it's feed and not read yet.
QString content(ContentOption opt=ContentAndOnlyContent) const
QString authorEMail() const
QString authorUri() const
QString authorName() const
bool keep() const
if true, the article should be kept even when expired
QString authorAsHtml() const
uint hash() const
returns a hash value used to detect changes in articles with non-hash GUIDs.
bool operator>=(const Article &other) const
void swap(Article &other)
bool operator==(const Article &other) const
QDateTime pubDate() const
QString description() const
QString authorShort() const
article wasn't read yet by the user
boost::shared_ptr< const Syndication::Enclosure > enclosure() const
A proxy class for Syndication::ItemPtr with some additional methods to assist sorting.
bool guidIsPermaLink() const
bool operator!=(const Article &other) const
void offsetPubDate(int secs)
bool operator<=(const Article &other) const