summaryrefslogtreecommitdiffstats
path: root/akregator/src/tagnode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'akregator/src/tagnode.cpp')
-rw-r--r--akregator/src/tagnode.cpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/akregator/src/tagnode.cpp b/akregator/src/tagnode.cpp
new file mode 100644
index 00000000..9fd1ee5e
--- /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"