You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/akregator/src/folder.cpp

348 lines
11 KiB

/*
This file is part of Akregator.
Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
2004-2005 Frank Osterfeld <frank.osterfeld@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 TQt, and distribute the resulting executable,
without including the source code for TQt in the source distribution.
*/
#include "article.h"
#include "folder.h"
#include "fetchqueue.h"
#include "treenodevisitor.h"
#include <tqlistview.h>
#include <tqdom.h>
#include <tqstringlist.h>
#include <tqvaluelist.h>
#include <kdebug.h>
namespace Akregator {
class Folder::FolderPrivate
{
public:
/** List of tqchildren */
TQValueList<TreeNode*> tqchildren;
/** caching unread count of tqchildren */
int unread;
/** whether or not the folder is expanded */
bool open;
/** caches guids for notifying added articles */
TQValueList<Article> addedArticlesNotify;
/** caches guids for notifying removed articles */
TQValueList<Article> removedArticlesNotify;
};
bool Folder::accept(TreeNodeVisitor* visitor)
{
if (visitor->visitFolder(this))
return true;
else
return visitor->visitTreeNode(this);
}
Folder* Folder::fromOPML(TQDomElement e)
{
Folder* fg = new Folder(e.hasAttribute(TQString::tqfromLatin1("text")) ? e.attribute(TQString::tqfromLatin1("text")) : e.attribute(TQString::tqfromLatin1("title")));
fg->setOpen( e.attribute(TQString::tqfromLatin1("isOpen")) != TQString::tqfromLatin1(("false")));
fg->setId( e.attribute(TQString::tqfromLatin1("id")).toUInt() );
return fg;
}
Folder::Folder(const TQString& title) : TreeNode(), d(new FolderPrivate)
{
d->unread = 0;
setTitle(title);
}
Folder::~Folder()
{
TreeNode* tmp = 0;
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != d->tqchildren.end(); ++it)
{
delete tmp;
tmp = *it;
}
delete tmp;
emitSignalDestroyed();
delete d;
d = 0;
}
TQStringList Folder::tags() const
{
TQStringList t;
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
{
// intersect tag sets instead of appending lists, to avoid dupes. This sucks. Definitely. I want TQSet. Now.
TQStringList t2 = (*it)->tags();
for (TQStringList::ConstIterator it2 = t2.begin(); it2 != t2.end(); ++it2)
if (!t.contains(*it2))
t.append(*it2);
}
return t;
}
TQValueList<Article> Folder::articles(const TQString& tag)
{
TQValueList<Article> seq;
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
seq += (*it)->articles(tag);
return seq;
}
TQDomElement Folder::toOPML( TQDomElement tqparent, TQDomDocument document ) const
{
TQDomElement el = document.createElement( "outline" );
el.setAttribute( "text", title() );
tqparent.appendChild( el );
el.setAttribute("isOpen", d->open ? "true" : "false");
el.setAttribute( "id", TQString::number(id()) );
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
el.appendChild( (*it)->toOPML(el, document) );
return el;
}
TQValueList<TreeNode*> Folder::tqchildren() const
{
return d->tqchildren;
}
void Folder::insertChild(TreeNode* node, TreeNode* after)
{
int pos = d->tqchildren.findIndex(after);
if (pos < 0)
prependChild(node);
else
insertChild(pos+1, node);
}
void Folder::insertChild(uint index, TreeNode* node)
{
// kdDebug() << "enter Folder::insertChild(int, node) " << node->title() << endl;
if (node)
{
if (index >= d->tqchildren.size())
d->tqchildren.append(node);
else
d->tqchildren.insert(d->tqchildren.at(index), node);
node->setParent(this);
connectToNode(node);
updateUnreadCount();
emit signalChildAdded(node);
d->addedArticlesNotify += node->articles();
articlesModified();
nodeModified();
}
// kdDebug() << "leave Folder::insertChild(int, node) " << node->title() << endl;
}
void Folder::appendChild(TreeNode* node)
{
// kdDebug() << "enter Folder::appendChild() " << node->title() << endl;
if (node)
{
d->tqchildren.append(node);
node->setParent(this);
connectToNode(node);
updateUnreadCount();
emit signalChildAdded(node);
d->addedArticlesNotify += node->articles();
articlesModified();
nodeModified();
}
// kdDebug() << "leave Folder::appendChild() " << node->title() << endl;
}
void Folder::prependChild(TreeNode* node)
{
// kdDebug() << "enter Folder::prependChild() " << node->title() << endl;
if (node)
{
d->tqchildren.prepend(node);
node->setParent(this);
connectToNode(node);
updateUnreadCount();
emit signalChildAdded(node);
d->addedArticlesNotify += node->articles();
articlesModified();
nodeModified();
}
// kdDebug() << "leave Folder::prependChild() " << node->title() << endl;
}
void Folder::removeChild(TreeNode* node)
{
// kdDebug() << "enter Folder::removeChild() node:" << (node ? node->title() : "null") << endl;
if (node && d->tqchildren.contains(node))
{
node->setParent(0);
d->tqchildren.remove(node);
disconnectFromNode(node);
updateUnreadCount();
emit signalChildRemoved(this, node);
d->removedArticlesNotify += node->articles();
articlesModified(); // articles were removed, TODO: add guids to a list
nodeModified();
}
// kdDebug() << "leave Folder::removeChild() node: " << (node ? node->title() : "null") << endl;
}
TreeNode* Folder::firstChild()
{
return d->tqchildren.isEmpty() ? 0 : d->tqchildren.first();
}
TreeNode* Folder::lastChild()
{
return d->tqchildren.isEmpty() ? 0 : d->tqchildren.last();
}
bool Folder::isOpen() const
{
return d->open;
}
void Folder::setOpen(bool open)
{
d->open = open;
}
int Folder::unread() const
{
return d->unread;
}
int Folder::totalCount() const
{
int totalCount = 0;
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
totalCount += (*it)->totalCount();
return totalCount;
}
void Folder::updateUnreadCount()
{
int unread = 0;
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
unread += (*it)->unread();
d->unread = unread;
}
void Folder::slotMarkAllArticlesAsRead()
{
setNotificationMode(false);
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
(*it)->slotMarkAllArticlesAsRead();
setNotificationMode(true, true);
}
void Folder::slotChildChanged(TreeNode* /*node*/)
{
updateUnreadCount();
nodeModified();
}
void Folder::slotChildDestroyed(TreeNode* node)
{
d->tqchildren.remove(node);
updateUnreadCount();
nodeModified();
}
void Folder::slotDeleteExpiredArticles()
{
setNotificationMode(false);
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
(*it)->slotDeleteExpiredArticles();
setNotificationMode(true, true);
}
void Folder::slotAddToFetchQueue(FetchQueue* queue, bool intervalFetchOnly)
{
TQValueList<TreeNode*>::ConstIterator en = d->tqchildren.end();
for (TQValueList<TreeNode*>::ConstIterator it = d->tqchildren.begin(); it != en; ++it)
(*it)->slotAddToFetchQueue(queue, intervalFetchOnly);
}
void Folder::doArticleNotification()
{
}
void Folder::connectToNode(TreeNode* child)
{
connect(child, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*)));
connect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*)));
connect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
connect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
connect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
}
void Folder::disconnectFromNode(TreeNode* child)
{
disconnect(child, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*)));
disconnect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*)));
disconnect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
disconnect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
disconnect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
}
TreeNode* Folder::next()
{
if ( firstChild() )
return firstChild();
if ( nextSibling() )
return nextSibling();
Folder* p = tqparent();
while (p)
{
if ( p->nextSibling() )
return p->nextSibling();
else
p = p->tqparent();
}
return 0;
}
} // namespace Akregator
#include "folder.moc"