akregator/src

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 Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 #include "article.h"
00026 #include "folder.h"
00027 #include "fetchqueue.h"
00028 #include "treenodevisitor.h"
00029 
00030 #include <qlistview.h>
00031 #include <qdom.h>
00032 #include <qstringlist.h>
00033 #include <qvaluelist.h>
00034 
00035 #include <kdebug.h>
00036 
00037 namespace Akregator {
00038 
00039 class Folder::FolderPrivate
00040 {
00041     public:
00043         QValueList<TreeNode*> children;
00045         int unread;
00047         bool open;
00048 
00050         QValueList<Article> addedArticlesNotify;
00052         QValueList<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(QDomElement e)
00064 {
00065     Folder* fg = new Folder(e.hasAttribute(QString::fromLatin1("text")) ? e.attribute(QString::fromLatin1("text")) : e.attribute(QString::fromLatin1("title")));
00066     fg->setOpen( e.attribute(QString::fromLatin1("isOpen")) != QString::fromLatin1(("false")));
00067     fg->setId( e.attribute(QString::fromLatin1("id")).toUInt() );
00068     return fg;
00069 }
00070 
00071 Folder::Folder(const QString& 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 (QValueList<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 QStringList Folder::tags() const
00094 {
00095     QStringList t;
00096     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00097     for (QValueList<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 QSet. Now.
00100         QStringList t2 = (*it)->tags();
00101         for (QStringList::ConstIterator it2 = t2.begin(); it2 != t2.end(); ++it2)
00102             if (!t.contains(*it2))
00103                 t.append(*it2);
00104     } 
00105     return t;
00106 }
00107 
00108 QValueList<Article> Folder::articles(const QString& tag)
00109 {
00110     QValueList<Article> seq;
00111     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00112     for (QValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
00113         seq += (*it)->articles(tag);
00114      
00115     return seq;
00116 }
00117 
00118 QDomElement Folder::toOPML( QDomElement parent, QDomDocument document ) const
00119 {
00120     QDomElement 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", QString::number(id()) );
00125 
00126     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00127     for (QValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
00128         el.appendChild( (*it)->toOPML(el, document) );
00129         
00130     return el;
00131 }
00132 
00133 QValueList<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     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00250     for (QValueList<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     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00261     for (QValueList<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     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00271     for (QValueList<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     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00293     for (QValueList<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     QValueList<TreeNode*>::ConstIterator en = d->children.end();
00301     for (QValueList<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, SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotChildChanged(TreeNode*)));
00312         connect(child, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotChildDestroyed(TreeNode*)));
00313         connect(child, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)));
00314         connect(child, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)));
00315         connect(child, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)));
00316 }
00317 
00318 void Folder::disconnectFromNode(TreeNode* child)
00319 {
00320         disconnect(child, SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotChildChanged(TreeNode*)));
00321         disconnect(child, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotChildDestroyed(TreeNode*)));
00322         disconnect(child, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)));
00323         disconnect(child, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)));
00324         disconnect(child, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<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"
KDE Home | KDE Accessibility Home | Description of Access Keys