folder.cpp
00001 /* 00002 This file is part of Akregator. 00003 00004 Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net> 00005 2004-2005 Frank Osterfeld <frank.osterfeld@kdemail.net> 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 00021 As a special exception, permission is given to link this program 00022 with any edition of TQt, and distribute the resulting executable, 00023 without including the source code for TQt in the source distribution. 00024 */ 00025 #include "article.h" 00026 #include "folder.h" 00027 #include "fetchqueue.h" 00028 #include "treenodevisitor.h" 00029 00030 #include <tqlistview.h> 00031 #include <tqdom.h> 00032 #include <tqstringlist.h> 00033 #include <tqvaluelist.h> 00034 00035 #include <kdebug.h> 00036 00037 namespace Akregator { 00038 00039 class Folder::FolderPrivate 00040 { 00041 public: 00043 TQValueList<TreeNode*> children; 00045 int unread; 00047 bool open; 00048 00050 TQValueList<Article> addedArticlesNotify; 00052 TQValueList<Article> removedArticlesNotify; 00053 }; 00054 00055 bool Folder::accept(TreeNodeVisitor* visitor) 00056 { 00057 if (visitor->visitFolder(this)) 00058 return true; 00059 else 00060 return visitor->visitTreeNode(this); 00061 } 00062 00063 Folder* Folder::fromOPML(TQDomElement e) 00064 { 00065 Folder* fg = new Folder(e.hasAttribute(TQString::fromLatin1("text")) ? e.attribute(TQString::fromLatin1("text")) : e.attribute(TQString::fromLatin1("title"))); 00066 fg->setOpen( e.attribute(TQString::fromLatin1("isOpen")) != TQString::fromLatin1(("false"))); 00067 fg->setId( e.attribute(TQString::fromLatin1("id")).toUInt() ); 00068 return fg; 00069 } 00070 00071 Folder::Folder(const TQString& title) : TreeNode(), d(new FolderPrivate) 00072 { 00073 d->unread = 0; 00074 setTitle(title); 00075 } 00076 00077 Folder::~Folder() 00078 { 00079 TreeNode* tmp = 0; 00080 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != d->children.end(); ++it) 00081 { 00082 delete tmp; 00083 tmp = *it; 00084 } 00085 delete tmp; 00086 00087 emitSignalDestroyed(); 00088 00089 delete d; 00090 d = 0; 00091 } 00092 00093 TQStringList Folder::tags() const 00094 { 00095 TQStringList t; 00096 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00097 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00098 { 00099 // intersect tag sets instead of appending lists, to avoid dupes. This sucks. Definitely. I want TQSet. Now. 00100 TQStringList t2 = (*it)->tags(); 00101 for (TQStringList::ConstIterator it2 = t2.begin(); it2 != t2.end(); ++it2) 00102 if (!t.contains(*it2)) 00103 t.append(*it2); 00104 } 00105 return t; 00106 } 00107 00108 TQValueList<Article> Folder::articles(const TQString& tag) 00109 { 00110 TQValueList<Article> seq; 00111 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00112 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00113 seq += (*it)->articles(tag); 00114 00115 return seq; 00116 } 00117 00118 TQDomElement Folder::toOPML( TQDomElement parent, TQDomDocument document ) const 00119 { 00120 TQDomElement el = document.createElement( "outline" ); 00121 el.setAttribute( "text", title() ); 00122 parent.appendChild( el ); 00123 el.setAttribute("isOpen", d->open ? "true" : "false"); 00124 el.setAttribute( "id", TQString::number(id()) ); 00125 00126 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00127 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00128 el.appendChild( (*it)->toOPML(el, document) ); 00129 00130 return el; 00131 } 00132 00133 TQValueList<TreeNode*> Folder::children() const 00134 { 00135 return d->children; 00136 } 00137 00138 void Folder::insertChild(TreeNode* node, TreeNode* after) 00139 { 00140 int pos = d->children.findIndex(after); 00141 00142 if (pos < 0) 00143 prependChild(node); 00144 else 00145 insertChild(pos+1, node); 00146 } 00147 00148 void Folder::insertChild(uint index, TreeNode* node) 00149 { 00150 // kdDebug() << "enter Folder::insertChild(int, node) " << node->title() << endl; 00151 if (node) 00152 { 00153 if (index >= d->children.size()) 00154 d->children.append(node); 00155 else 00156 d->children.insert(d->children.at(index), node); 00157 node->setParent(this); 00158 connectToNode(node); 00159 updateUnreadCount(); 00160 emit signalChildAdded(node); 00161 d->addedArticlesNotify += node->articles(); 00162 articlesModified(); 00163 nodeModified(); 00164 } 00165 // kdDebug() << "leave Folder::insertChild(int, node) " << node->title() << endl; 00166 } 00167 00168 void Folder::appendChild(TreeNode* node) 00169 { 00170 // kdDebug() << "enter Folder::appendChild() " << node->title() << endl; 00171 if (node) 00172 { 00173 d->children.append(node); 00174 node->setParent(this); 00175 connectToNode(node); 00176 updateUnreadCount(); 00177 emit signalChildAdded(node); 00178 d->addedArticlesNotify += node->articles(); 00179 articlesModified(); 00180 nodeModified(); 00181 } 00182 // kdDebug() << "leave Folder::appendChild() " << node->title() << endl; 00183 } 00184 00185 void Folder::prependChild(TreeNode* node) 00186 { 00187 // kdDebug() << "enter Folder::prependChild() " << node->title() << endl; 00188 if (node) 00189 { 00190 d->children.prepend(node); 00191 node->setParent(this); 00192 connectToNode(node); 00193 updateUnreadCount(); 00194 emit signalChildAdded(node); 00195 d->addedArticlesNotify += node->articles(); 00196 articlesModified(); 00197 nodeModified(); 00198 } 00199 // kdDebug() << "leave Folder::prependChild() " << node->title() << endl; 00200 } 00201 00202 void Folder::removeChild(TreeNode* node) 00203 { 00204 // kdDebug() << "enter Folder::removeChild() node:" << (node ? node->title() : "null") << endl; 00205 if (node && d->children.contains(node)) 00206 { 00207 node->setParent(0); 00208 d->children.remove(node); 00209 disconnectFromNode(node); 00210 updateUnreadCount(); 00211 emit signalChildRemoved(this, node); 00212 d->removedArticlesNotify += node->articles(); 00213 articlesModified(); // articles were removed, TODO: add guids to a list 00214 nodeModified(); 00215 } 00216 // kdDebug() << "leave Folder::removeChild() node: " << (node ? node->title() : "null") << endl; 00217 } 00218 00219 00220 TreeNode* Folder::firstChild() 00221 { 00222 return d->children.isEmpty() ? 0 : d->children.first(); 00223 } 00224 00225 TreeNode* Folder::lastChild() 00226 { 00227 return d->children.isEmpty() ? 0 : d->children.last(); 00228 } 00229 00230 bool Folder::isOpen() const 00231 { 00232 return d->open; 00233 } 00234 00235 void Folder::setOpen(bool open) 00236 { 00237 d->open = open; 00238 } 00239 00240 int Folder::unread() const 00241 { 00242 return d->unread; 00243 } 00244 00245 int Folder::totalCount() const 00246 { 00247 int totalCount = 0; 00248 00249 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00250 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00251 totalCount += (*it)->totalCount(); 00252 00253 return totalCount; 00254 } 00255 00256 void Folder::updateUnreadCount() 00257 { 00258 int unread = 0; 00259 00260 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00261 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00262 unread += (*it)->unread(); 00263 00264 d->unread = unread; 00265 } 00266 00267 void Folder::slotMarkAllArticlesAsRead() 00268 { 00269 setNotificationMode(false); 00270 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00271 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00272 (*it)->slotMarkAllArticlesAsRead(); 00273 setNotificationMode(true, true); 00274 } 00275 00276 void Folder::slotChildChanged(TreeNode* /*node*/) 00277 { 00278 updateUnreadCount(); 00279 nodeModified(); 00280 } 00281 00282 void Folder::slotChildDestroyed(TreeNode* node) 00283 { 00284 d->children.remove(node); 00285 updateUnreadCount(); 00286 nodeModified(); 00287 } 00288 00289 void Folder::slotDeleteExpiredArticles() 00290 { 00291 setNotificationMode(false); 00292 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00293 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00294 (*it)->slotDeleteExpiredArticles(); 00295 setNotificationMode(true, true); 00296 } 00297 00298 void Folder::slotAddToFetchQueue(FetchQueue* queue, bool intervalFetchOnly) 00299 { 00300 TQValueList<TreeNode*>::ConstIterator en = d->children.end(); 00301 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it) 00302 (*it)->slotAddToFetchQueue(queue, intervalFetchOnly); 00303 } 00304 00305 void Folder::doArticleNotification() 00306 { 00307 } 00308 00309 void Folder::connectToNode(TreeNode* child) 00310 { 00311 connect(child, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*))); 00312 connect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*))); 00313 connect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&))); 00314 connect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&))); 00315 connect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&))); 00316 } 00317 00318 void Folder::disconnectFromNode(TreeNode* child) 00319 { 00320 disconnect(child, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*))); 00321 disconnect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*))); 00322 disconnect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&))); 00323 disconnect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&))); 00324 disconnect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&))); 00325 } 00326 00327 TreeNode* Folder::next() 00328 { 00329 if ( firstChild() ) 00330 return firstChild(); 00331 00332 if ( nextSibling() ) 00333 return nextSibling(); 00334 00335 Folder* p = parent(); 00336 while (p) 00337 { 00338 if ( p->nextSibling() ) 00339 return p->nextSibling(); 00340 else 00341 p = p->parent(); 00342 } 00343 return 0; 00344 } 00345 00346 } // namespace Akregator 00347 #include "folder.moc"