Make it compiles when deprecated method are disabled. Add more find package
[kdepim.git] / akregator / src / articlemodel.cpp
blob36f47e2df4aea9bdd88159ea3d19d0c369c649da
1 /*
2 This file is part of Akregator.
4 Copyright (C) 2007 Frank Osterfeld <osterfeld@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
24 #include "articlemodel.h"
26 #include "article.h"
27 #include "articlematcher.h"
28 #include "akregatorconfig.h"
29 #include "feed.h"
31 #include <Syndication/Tools>
33 #include <QMimeData>
34 #include <QString>
35 #include <QVector>
37 #include <KLocalizedString>
38 #include <QUrl>
40 #include <memory>
42 #include <QLocale>
43 #include <cassert>
44 #include <cmath>
46 using namespace Akregator;
48 class Q_DECL_HIDDEN ArticleModel::Private
50 private:
51 ArticleModel *const q;
52 public:
53 Private(const QVector<Article> &articles, ArticleModel *qq);
54 QVector<Article> articles;
55 QVector<QString> titleCache;
57 void articlesAdded(const QVector<Article> &);
58 void articlesRemoved(const QVector<Article> &);
59 void articlesUpdated(const QVector<Article> &);
63 //like Syndication::htmlToPlainText, but without linebreaks
65 static QString stripHtml(const QString &html)
67 QString str(html);
68 //TODO: preserve some formatting, such as line breaks
69 str.remove(QRegExp(QLatin1String("<[^>]*>"))); // remove tags
70 str = Syndication::resolveEntities(str);
71 return str.simplified();
74 ArticleModel::Private::Private(const QVector<Article> &articles_, ArticleModel *qq)
75 : q(qq), articles(articles_)
77 const int articlesCount(articles.count());
78 titleCache.resize(articlesCount);
79 for (int i = 0; i < articlesCount; ++i) {
80 titleCache[i] = stripHtml(articles[i].title());
84 ArticleModel::ArticleModel(const QVector<Article> &articles, QObject *parent) : QAbstractTableModel(parent), d(new Private(articles, this))
88 ArticleModel::~ArticleModel()
90 delete d;
93 int ArticleModel::columnCount(const QModelIndex &parent) const
95 return parent.isValid() ? 0 : ColumnCount;
98 int ArticleModel::rowCount(const QModelIndex &parent) const
100 return parent.isValid() ? 0 : d->articles.count();
103 QVariant ArticleModel::headerData(int section, Qt::Orientation, int role) const
105 if (role != Qt::DisplayRole) {
106 return QVariant();
109 switch (section) {
110 case ItemTitleColumn:
111 return i18nc("Articlelist's column header", "Title");
112 case FeedTitleColumn:
113 return i18nc("Articlelist's column header", "Feed");
114 case DateColumn:
115 return i18nc("Articlelist's column header", "Date");
116 case AuthorColumn:
117 return i18nc("Articlelist's column header", "Author");
118 case DescriptionColumn:
119 return i18nc("Articlelist's column header", "Description");
120 case ContentColumn:
121 return i18nc("Articlelist's column header", "Content");
124 return QVariant();
127 QVariant ArticleModel::data(const QModelIndex &index, int role) const
129 if (!index.isValid() || index.row() < 0 || index.row() >= d->articles.count()) {
130 return QVariant();
132 const int row = index.row();
133 const Article &article(d->articles[row]);
135 if (article.isNull()) {
136 return QVariant();
139 switch (role) {
140 case SortRole:
141 if (index.column() == DateColumn) {
142 return article.pubDate();
144 // no break
145 case Qt::DisplayRole: {
146 switch (index.column()) {
147 case FeedTitleColumn:
148 return article.feed() ? article.feed()->title() : QVariant();
149 case DateColumn:
150 return QLocale().toString(article.pubDate(), QLocale::ShortFormat);
151 case ItemTitleColumn:
152 return d->titleCache[row];
153 case AuthorColumn:
154 return article.authorShort();
155 case DescriptionColumn:
156 case ContentColumn:
157 return article.description();
160 case LinkRole: {
161 return article.link();
163 case ItemIdRole:
164 case GuidRole: {
165 return article.guid();
167 case FeedIdRole: {
168 return article.feed() ? article.feed()->xmlUrl() : QVariant();
170 case StatusRole: {
171 return article.status();
173 case IsImportantRole: {
174 return article.keep();
176 case IsDeletedRole: {
177 return article.isDeleted();
181 return QVariant();
184 void ArticleModel::clear()
186 beginResetModel();
187 d->articles.clear();
188 d->titleCache.clear();
189 endResetModel();
192 void ArticleModel::articlesAdded(TreeNode *, const QVector<Article> &l)
194 d->articlesAdded(l);
197 void ArticleModel::articlesRemoved(TreeNode *, const QVector<Article> &l)
199 d->articlesRemoved(l);
201 void ArticleModel::articlesUpdated(TreeNode *, const QVector<Article> &l)
203 d->articlesUpdated(l);
206 void ArticleModel::Private::articlesAdded(const QVector<Article> &list)
208 if (list.isEmpty()) { //assert?
209 return;
211 const int first = articles.count();
212 q->beginInsertRows(QModelIndex(), first, first + list.size() - 1);
214 const int oldSize = articles.size();
215 articles << list;
217 const int newArticlesCount(articles.count());
218 titleCache.resize(newArticlesCount);
219 for (int i = oldSize; i < newArticlesCount; ++i) {
220 titleCache[i] = stripHtml(articles[i].title());
222 q->endInsertRows();
225 void ArticleModel::Private::articlesRemoved(const QVector<Article> &list)
227 //might want to avoid indexOf() in case of performance problems
228 Q_FOREACH (const Article &i, list) {
229 const int row = articles.indexOf(i);
230 Q_ASSERT(row != -1);
231 q->removeRow(row, QModelIndex());
235 void ArticleModel::Private::articlesUpdated(const QVector<Article> &list)
237 int rmin = 0;
238 int rmax = 0;
240 const int numberOfArticles(articles.count());
241 if (numberOfArticles > 0) {
242 rmin = numberOfArticles - 1;
243 //might want to avoid indexOf() in case of performance problems
244 Q_FOREACH (const Article &i, list) {
245 const int row = articles.indexOf(i);
246 //TODO: figure out how why the Article might not be found in
247 //TODO: the articles list because we should need this conditional.
248 if (row >= 0) {
249 titleCache[row] = stripHtml(articles[row].title());
250 rmin = std::min(row, rmin);
251 rmax = std::max(row, rmax);
255 Q_EMIT q->dataChanged(q->index(rmin, 0), q->index(rmax, ColumnCount - 1));
258 bool ArticleModel::rowMatches(int row, const QSharedPointer<const Filters::AbstractMatcher> &matcher) const
260 Q_ASSERT(matcher);
261 return matcher->matches(article(row));
264 Article ArticleModel::article(int row) const
266 if (row < 0 || row >= d->articles.count()) {
267 return Article();
269 return d->articles[row];
272 QStringList ArticleModel::mimeTypes() const
274 return QStringList() << QStringLiteral("text/uri-list");
277 QMimeData *ArticleModel::mimeData(const QModelIndexList &indexes) const
279 QScopedPointer<QMimeData> md(new QMimeData);
280 QList<QUrl> urls;
281 Q_FOREACH (const QModelIndex &i, indexes) {
282 const QUrl url = i.data(ArticleModel::LinkRole).toUrl();
283 if (url.isValid()) {
284 urls.push_back(url);
285 } else {
286 const QUrl guid(i.data(ArticleModel::GuidRole).toString());
287 if (guid.isValid()) {
288 urls.push_back(guid);
292 md->setUrls(urls);
293 return md.take();
296 Qt::ItemFlags ArticleModel::flags(const QModelIndex &idx) const
298 const Qt::ItemFlags f = QAbstractTableModel::flags(idx);
299 if (!idx.isValid()) {
300 return f;
302 return f | Qt::ItemIsDragEnabled;