diff options
Diffstat (limited to 'akregator/src/tagnode.cpp')
-rw-r--r-- | akregator/src/tagnode.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/akregator/src/tagnode.cpp b/akregator/src/tagnode.cpp new file mode 100644 index 000000000..9fd1ee5e6 --- /dev/null +++ b/akregator/src/tagnode.cpp @@ -0,0 +1,304 @@ +/* + This file is part of Akregator. + + Copyright (C) 2005 Frank Osterfeld <frank.osterfeld at kdemail.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "article.h" +#include "articlefilter.h" +#include "fetchqueue.h" +#include "folder.h" +#include "tag.h" +#include "tagnode.h" +#include "treenode.h" +#include "treenodevisitor.h" + +#include <qdom.h> +#include <qstring.h> +#include <qvaluelist.h> + +namespace Akregator { + +class TagNode::TagNodePrivate +{ + public: + Filters::TagMatcher filter; + TreeNode* observed; + int unread; + QString icon; + Tag tag; + QValueList<Article> articles; + QValueList<Article> addedArticlesNotify; + QValueList<Article> removedArticlesNotify; + QValueList<Article> updatedArticlesNotify; +}; + +TagNode::TagNode(const Tag& tag, TreeNode* observed) : d(new TagNodePrivate) +{ + d->tag = tag; + d->icon = tag.icon(); + d->filter = Filters::TagMatcher(tag.id()); + setTitle(tag.name()); + d->observed = observed; + d->unread = 0; + + connect(observed, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotObservedDestroyed(TreeNode*))); + connect(observed, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesAdded(TreeNode*, const QValueList<Article>&)) ); + connect(observed, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesUpdated(TreeNode*, const QValueList<Article>&)) ); + connect(observed, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesRemoved(TreeNode*, const QValueList<Article>&)) ); + + d->articles = observed->articles(tag.id()); + calcUnread(); +} + +QString TagNode::icon() const +{ + return d->icon; +} + +Tag TagNode::tag() const +{ + return d->tag; +} + +TagNode::~TagNode() +{ + emitSignalDestroyed(); + delete d; + d = 0; +} + +bool TagNode::accept(TreeNodeVisitor* visitor) +{ + if (visitor->visitTagNode(this)) + return true; + else + return visitor->visitTreeNode(this); +} + +void TagNode::calcUnread() +{ + int unread = 0; + QValueList<Article>::Iterator en = d->articles.end(); + for (QValueList<Article>::Iterator it = d->articles.begin(); it != en; ++it) + if ((*it).status() != Article::Read) + ++unread; + if (d->unread != unread) + { + d->unread = unread; + nodeModified(); + } +} + +int TagNode::unread() const +{ + return d->unread; +} + + +int TagNode::totalCount() const +{ + return d->articles.count(); +} + + +QValueList<Article> TagNode::articles(const QString& tag) +{ + return d->articles; +} + +QStringList TagNode::tags() const +{ + // TODO + return QStringList(); +} + +QDomElement TagNode::toOPML( QDomElement parent, QDomDocument document ) const +{ + return QDomElement(); +} + +TreeNode* TagNode::next() +{ + if ( nextSibling() ) + return nextSibling(); + + Folder* p = parent(); + while (p) + { + if ( p->nextSibling() ) + return p->nextSibling(); + else + p = p->parent(); + } + return 0; +} + +void TagNode::slotDeleteExpiredArticles() +{ +// not our business +} + +void TagNode::slotMarkAllArticlesAsRead() +{ + setNotificationMode(false); + QValueList<Article>::Iterator en = d->articles.end(); + for (QValueList<Article>::Iterator it = d->articles.begin(); it != en; ++it) + (*it).setStatus(Article::Read); + setNotificationMode(true); +} + +void TagNode::slotAddToFetchQueue(FetchQueue* /*queue*/, bool /*intervalFetchOnly*/) +{ +// not our business +} + +void TagNode::doArticleNotification() +{ + if (!d->addedArticlesNotify.isEmpty()) + { + emit signalArticlesAdded(this, d->addedArticlesNotify); + d->addedArticlesNotify.clear(); + } + if (!d->updatedArticlesNotify.isEmpty()) + { + emit signalArticlesUpdated(this, d->updatedArticlesNotify); + d->updatedArticlesNotify.clear(); + } + if (!d->removedArticlesNotify.isEmpty()) + { + emit signalArticlesRemoved(this, d->removedArticlesNotify); + d->removedArticlesNotify.clear(); + } + TreeNode::doArticleNotification(); +} + +void TagNode::slotArticlesAdded(TreeNode* node, const QValueList<Article>& list) +{ + bool added = false; + for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it) + { + if (!d->articles.contains(*it) && d->filter.matches(*it)) + { + d->articles.append(*it); + d->addedArticlesNotify.append(*it); + added = true; + } + } + + if (added) + { + calcUnread(); + articlesModified(); + } +} + +void TagNode::slotArticlesUpdated(TreeNode* node, const QValueList<Article>& list) +{ + bool updated = false; + for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it) + { + if (d->articles.contains(*it)) + { + if (!d->filter.matches(*it)) // articles is in list, but doesn't match our criteria anymore -> remove it + { + d->articles.remove(*it); + d->removedArticlesNotify.append(*it); + updated = true; + } + else // otherwise the article remains in the list and we just forward the update + { + d->updatedArticlesNotify.append(*it); + updated = true; + } + } + else // article not in list + { + if (d->filter.matches(*it)) // articles is not in list, but matches our criteria -> add it + { + d->articles.append(*it); + d->addedArticlesNotify.append(*it); + updated = true; + } + } + } + if (updated) + { + calcUnread(); + articlesModified(); + } +} + +void TagNode::slotArticlesRemoved(TreeNode* node, const QValueList<Article>& list) +{ + bool removed = false; + for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it) + { + if (d->articles.contains(*it)) + { + d->articles.remove(*it); + d->removedArticlesNotify.append(*it); + removed = true; + } + } + if (removed) + { + calcUnread(); + articlesModified(); + } +} + +void TagNode::setTitle(const QString& title) +{ + if (d->tag.name() != title) + d->tag.setName(title); + TreeNode::setTitle(title); +} + +void TagNode::slotObservedDestroyed(TreeNode* /*observed*/) +{ + d->removedArticlesNotify = d->articles; + d->articles.clear(); + articlesModified(); +} + +void TagNode::tagChanged() +{ + bool changed = false; + if (title() != d->tag.name()) + { + setTitle(d->tag.name()); + changed = true; + } + + if (d->icon != d->tag.icon()) + { + d->icon = d->tag.icon(); + changed = true; + } + + if (changed) + nodeModified(); +} + +} // namespace Akregator + +#include "tagnode.moc" |