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 TQt, and distribute the resulting executable, 00022 without including the source code for TQt 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 <tqdom.h> 00035 #include <tqstring.h> 00036 #include <tqvaluelist.h> 00037 00038 namespace Akregator { 00039 00040 class TagNode::TagNodePrivate 00041 { 00042 public: 00043 Filters::TagMatcher filter; 00044 TreeNode* observed; 00045 int unread; 00046 TQString icon; 00047 Tag tag; 00048 TQValueList<Article> articles; 00049 TQValueList<Article> addedArticlesNotify; 00050 TQValueList<Article> removedArticlesNotify; 00051 TQValueList<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, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotObservedDestroyed(TreeNode*))); 00064 connect(observed, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesAdded(TreeNode*, const TQValueList<Article>&)) ); 00065 connect(observed, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesUpdated(TreeNode*, const TQValueList<Article>&)) ); 00066 connect(observed, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesRemoved(TreeNode*, const TQValueList<Article>&)) ); 00067 00068 d->articles = observed->articles(tag.id()); 00069 calcUnread(); 00070 } 00071 00072 TQString 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 TQValueList<Article>::Iterator en = d->articles.end(); 00101 for (TQValueList<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 TQValueList<Article> TagNode::articles(const TQString& tag) 00124 { 00125 return d->articles; 00126 } 00127 00128 TQStringList TagNode::tags() const 00129 { 00130 // TODO 00131 return TQStringList(); 00132 } 00133 00134 TQDomElement TagNode::toOPML( TQDomElement parent, TQDomDocument document ) const 00135 { 00136 return TQDomElement(); 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 TQValueList<Article>::Iterator en = d->articles.end(); 00164 for (TQValueList<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 TQValueList<Article>& list) 00195 { 00196 bool added = false; 00197 for (TQValueList<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 TQValueList<Article>& list) 00215 { 00216 bool updated = false; 00217 for (TQValueList<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 TQValueList<Article>& list) 00251 { 00252 bool removed = false; 00253 for (TQValueList<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 TQString& 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"