akregator/src

tagnode.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
00005 
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 "articlefilter.h"
00027 #include "fetchqueue.h"
00028 #include "folder.h"
00029 #include "tag.h"
00030 #include "tagnode.h"
00031 #include "treenode.h"
00032 #include "treenodevisitor.h"
00033 
00034 #include <qdom.h>
00035 #include <qstring.h>
00036 #include <qvaluelist.h>
00037 
00038 namespace Akregator {
00039 
00040 class TagNode::TagNodePrivate
00041 {
00042     public:
00043     Filters::TagMatcher filter;
00044     TreeNode* observed;
00045     int unread;
00046     QString icon;
00047     Tag tag;
00048     QValueList<Article> articles;
00049     QValueList<Article> addedArticlesNotify;
00050     QValueList<Article> removedArticlesNotify;
00051     QValueList<Article> updatedArticlesNotify;
00052 };
00053 
00054 TagNode::TagNode(const Tag& tag, TreeNode* observed) : d(new TagNodePrivate)
00055 {
00056     d->tag = tag;
00057     d->icon = tag.icon();
00058     d->filter = Filters::TagMatcher(tag.id());
00059     setTitle(tag.name());
00060     d->observed = observed;
00061     d->unread = 0;
00062     
00063     connect(observed, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotObservedDestroyed(TreeNode*)));
00064     connect(observed, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesAdded(TreeNode*, const QValueList<Article>&)) );
00065     connect(observed, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesUpdated(TreeNode*, const QValueList<Article>&)) );
00066     connect(observed, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesRemoved(TreeNode*, const QValueList<Article>&)) );
00067 
00068     d->articles = observed->articles(tag.id());
00069     calcUnread();
00070 }
00071 
00072 QString TagNode::icon() const
00073 {
00074     return d->icon;
00075 }
00076 
00077 Tag TagNode::tag() const
00078 {
00079     return d->tag;
00080 }
00081 
00082 TagNode::~TagNode()
00083 {
00084     emitSignalDestroyed();
00085     delete d;
00086     d = 0;
00087 }
00088 
00089 bool TagNode::accept(TreeNodeVisitor* visitor)
00090 {
00091     if (visitor->visitTagNode(this))
00092         return true;
00093     else
00094         return visitor->visitTreeNode(this);
00095 }
00096 
00097 void TagNode::calcUnread()
00098 {
00099     int unread = 0;
00100     QValueList<Article>::Iterator en = d->articles.end();
00101     for (QValueList<Article>::Iterator it = d->articles.begin(); it != en; ++it)
00102         if ((*it).status() != Article::Read)
00103             ++unread;
00104     if (d->unread != unread)
00105     {
00106         d->unread = unread;
00107         nodeModified();
00108     }
00109 }
00110 
00111 int TagNode::unread() const
00112 {
00113     return d->unread;
00114 }
00115 
00116 
00117 int TagNode::totalCount() const
00118 {
00119     return d->articles.count();
00120 }
00121 
00122     
00123 QValueList<Article> TagNode::articles(const QString& tag)
00124 {
00125     return d->articles;
00126 }
00127 
00128 QStringList TagNode::tags() const
00129 {
00130    // TODO
00131    return QStringList();
00132 }
00133 
00134 QDomElement TagNode::toOPML( QDomElement parent, QDomDocument document ) const
00135 {
00136     return QDomElement();
00137 }    
00138 
00139 TreeNode* TagNode::next()
00140 {
00141     if ( nextSibling() )
00142         return nextSibling();
00143 
00144     Folder* p = parent();
00145     while (p)
00146     {
00147         if ( p->nextSibling() )
00148             return p->nextSibling();
00149         else
00150             p = p->parent();
00151     }
00152     return 0;
00153 }
00154 
00155 void TagNode::slotDeleteExpiredArticles() 
00156 { 
00157 // not our business
00158 }
00159     
00160 void TagNode::slotMarkAllArticlesAsRead()
00161 { 
00162     setNotificationMode(false);
00163     QValueList<Article>::Iterator en = d->articles.end();
00164     for (QValueList<Article>::Iterator it = d->articles.begin(); it != en; ++it)
00165         (*it).setStatus(Article::Read);
00166     setNotificationMode(true);
00167 }
00168     
00169 void TagNode::slotAddToFetchQueue(FetchQueue* /*queue*/, bool /*intervalFetchOnly*/)
00170 {
00171 // not our business
00172 }
00173 
00174 void TagNode::doArticleNotification()
00175 {
00176     if (!d->addedArticlesNotify.isEmpty())
00177     {
00178         emit signalArticlesAdded(this, d->addedArticlesNotify);
00179         d->addedArticlesNotify.clear();
00180     }
00181     if (!d->updatedArticlesNotify.isEmpty())
00182     {
00183         emit signalArticlesUpdated(this, d->updatedArticlesNotify);
00184         d->updatedArticlesNotify.clear();
00185     }
00186     if (!d->removedArticlesNotify.isEmpty())
00187     {
00188         emit signalArticlesRemoved(this, d->removedArticlesNotify);
00189         d->removedArticlesNotify.clear();
00190     }
00191     TreeNode::doArticleNotification();
00192 }
00193 
00194 void TagNode::slotArticlesAdded(TreeNode* node, const QValueList<Article>& list)
00195 {
00196     bool added = false;
00197     for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it)
00198     {
00199         if (!d->articles.contains(*it) && d->filter.matches(*it))
00200         {
00201             d->articles.append(*it);
00202             d->addedArticlesNotify.append(*it);
00203             added = true;
00204         }
00205     }
00206 
00207     if (added)
00208     {
00209         calcUnread();
00210         articlesModified();
00211     }
00212 }
00213 
00214 void TagNode::slotArticlesUpdated(TreeNode* node, const QValueList<Article>& list)
00215 {
00216     bool updated = false;
00217     for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it)
00218     {
00219         if (d->articles.contains(*it))
00220         {
00221             if (!d->filter.matches(*it)) // articles is in list, but doesn't match our criteria anymore -> remove it
00222         {
00223                 d->articles.remove(*it);
00224                 d->removedArticlesNotify.append(*it);
00225                 updated = true;
00226             }
00227             else // otherwise the article remains in the list and we just forward the update
00228             {
00229                 d->updatedArticlesNotify.append(*it);
00230                 updated = true;
00231             }
00232         }
00233         else // article not in list
00234         { 
00235             if (d->filter.matches(*it)) // articles is not in list, but matches our criteria -> add it
00236             {
00237                 d->articles.append(*it);
00238                 d->addedArticlesNotify.append(*it);
00239                 updated = true;
00240             }
00241         }
00242     }
00243     if (updated)
00244     {
00245         calcUnread();
00246         articlesModified();
00247     }
00248 }
00249 
00250 void TagNode::slotArticlesRemoved(TreeNode* node, const QValueList<Article>& list)
00251 {
00252     bool removed = false;
00253     for (QValueList<Article>::ConstIterator it = list.begin(); it != list.end(); ++it)
00254     {
00255         if (d->articles.contains(*it))
00256         {
00257             d->articles.remove(*it);
00258             d->removedArticlesNotify.append(*it);
00259             removed = true;
00260         }
00261     }
00262     if (removed)
00263     {
00264         calcUnread();
00265         articlesModified();
00266     }
00267 }
00268 
00269 void TagNode::setTitle(const QString& title)
00270 {
00271     if (d->tag.name() != title)
00272         d->tag.setName(title);
00273     TreeNode::setTitle(title);
00274 }
00275 
00276 void TagNode::slotObservedDestroyed(TreeNode* /*observed*/)
00277 {
00278     d->removedArticlesNotify = d->articles;
00279     d->articles.clear();
00280     articlesModified();
00281 }
00282 
00283 void TagNode::tagChanged()
00284 {
00285     bool changed = false;
00286     if (title() != d->tag.name())
00287     {
00288         setTitle(d->tag.name());
00289         changed = true;
00290     }
00291 
00292     if (d->icon != d->tag.icon())
00293     {
00294         d->icon = d->tag.icon();
00295         changed = true;
00296     }
00297 
00298     if (changed)
00299         nodeModified();
00300 }
00301 
00302 } // namespace Akregator
00303 
00304 #include "tagnode.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys