akregator/src

folder.cpp
1/*
2 This file is part of Akregator.
3
4 Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5 2004-2005 Frank Osterfeld <frank.osterfeld@kdemail.net>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of TQt, and distribute the resulting executable,
23 without including the source code for TQt in the source distribution.
24*/
25#include "article.h"
26#include "folder.h"
27#include "fetchqueue.h"
28#include "treenodevisitor.h"
29
30#include <tqlistview.h>
31#include <tqdom.h>
32#include <tqstringlist.h>
33#include <tqvaluelist.h>
34
35#include <kdebug.h>
36
37namespace Akregator {
38
39class Folder::FolderPrivate
40{
41 public:
43 TQValueList<TreeNode*> children;
45 int unread;
47 bool open;
48
50 TQValueList<Article> addedArticlesNotify;
52 TQValueList<Article> removedArticlesNotify;
53};
54
55bool Folder::accept(TreeNodeVisitor* visitor)
56{
57 if (visitor->visitFolder(this))
58 return true;
59 else
60 return visitor->visitTreeNode(this);
61}
62
63Folder* Folder::fromOPML(TQDomElement e)
64{
65 Folder* fg = new Folder(e.hasAttribute(TQString::fromLatin1("text")) ? e.attribute(TQString::fromLatin1("text")) : e.attribute(TQString::fromLatin1("title")));
66 fg->setOpen( e.attribute(TQString::fromLatin1("isOpen")) != TQString::fromLatin1(("false")));
67 fg->setId( e.attribute(TQString::fromLatin1("id")).toUInt() );
68 return fg;
69}
70
71Folder::Folder(const TQString& title) : TreeNode(), d(new FolderPrivate)
72{
73 d->unread = 0;
75}
76
77Folder::~Folder()
78{
79 TreeNode* tmp = 0;
80 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != d->children.end(); ++it)
81 {
82 delete tmp;
83 tmp = *it;
84 }
85 delete tmp;
86
87 emitSignalDestroyed();
88
89 delete d;
90 d = 0;
91}
92
93TQStringList Folder::tags() const
94{
95 TQStringList t;
96 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
97 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
98 {
99 // intersect tag sets instead of appending lists, to avoid dupes. This sucks. Definitely. I want TQSet. Now.
100 TQStringList t2 = (*it)->tags();
101 for (TQStringList::ConstIterator it2 = t2.begin(); it2 != t2.end(); ++it2)
102 if (!t.contains(*it2))
103 t.append(*it2);
104 }
105 return t;
106}
107
108TQValueList<Article> Folder::articles(const TQString& tag)
109{
110 TQValueList<Article> seq;
111 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
112 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
113 seq += (*it)->articles(tag);
114
115 return seq;
116}
117
118TQDomElement Folder::toOPML( TQDomElement parent, TQDomDocument document ) const
119{
120 TQDomElement el = document.createElement( "outline" );
121 el.setAttribute( "text", title() );
122 parent.appendChild( el );
123 el.setAttribute("isOpen", d->open ? "true" : "false");
124 el.setAttribute( "id", TQString::number(id()) );
125
126 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
127 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
128 el.appendChild( (*it)->toOPML(el, document) );
129
130 return el;
131}
132
133TQValueList<TreeNode*> Folder::children() const
134{
135 return d->children;
136}
137
139{
140 int pos = d->children.findIndex(after);
141
142 if (pos < 0)
143 prependChild(node);
144 else
145 insertChild(pos+1, node);
146}
147
148void Folder::insertChild(uint index, TreeNode* node)
149{
150// kdDebug() << "enter Folder::insertChild(int, node) " << node->title() << endl;
151 if (node)
152 {
153 if (index >= d->children.size())
154 d->children.append(node);
155 else
156 d->children.insert(d->children.at(index), node);
157 node->setParent(this);
158 connectToNode(node);
159 updateUnreadCount();
160 emit signalChildAdded(node);
161 d->addedArticlesNotify += node->articles();
163 nodeModified();
164 }
165// kdDebug() << "leave Folder::insertChild(int, node) " << node->title() << endl;
166}
167
169{
170// kdDebug() << "enter Folder::appendChild() " << node->title() << endl;
171 if (node)
172 {
173 d->children.append(node);
174 node->setParent(this);
175 connectToNode(node);
176 updateUnreadCount();
177 emit signalChildAdded(node);
178 d->addedArticlesNotify += node->articles();
180 nodeModified();
181 }
182// kdDebug() << "leave Folder::appendChild() " << node->title() << endl;
183}
184
186{
187// kdDebug() << "enter Folder::prependChild() " << node->title() << endl;
188 if (node)
189 {
190 d->children.prepend(node);
191 node->setParent(this);
192 connectToNode(node);
193 updateUnreadCount();
194 emit signalChildAdded(node);
195 d->addedArticlesNotify += node->articles();
197 nodeModified();
198 }
199// kdDebug() << "leave Folder::prependChild() " << node->title() << endl;
200}
201
203{
204// kdDebug() << "enter Folder::removeChild() node:" << (node ? node->title() : "null") << endl;
205 if (node && d->children.contains(node))
206 {
207 node->setParent(0);
208 d->children.remove(node);
209 disconnectFromNode(node);
210 updateUnreadCount();
211 emit signalChildRemoved(this, node);
212 d->removedArticlesNotify += node->articles();
213 articlesModified(); // articles were removed, TODO: add guids to a list
214 nodeModified();
215 }
216// kdDebug() << "leave Folder::removeChild() node: " << (node ? node->title() : "null") << endl;
217}
218
219
221{
222 return d->children.isEmpty() ? 0 : d->children.first();
223}
224
226{
227 return d->children.isEmpty() ? 0 : d->children.last();
228}
229
230bool Folder::isOpen() const
231{
232 return d->open;
233}
234
235void Folder::setOpen(bool open)
236{
237 d->open = open;
238}
239
240int Folder::unread() const
241{
242 return d->unread;
243}
244
246{
247 int totalCount = 0;
248
249 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
250 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
251 totalCount += (*it)->totalCount();
252
253 return totalCount;
254}
255
256void Folder::updateUnreadCount()
257{
258 int unread = 0;
259
260 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
261 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
262 unread += (*it)->unread();
263
264 d->unread = unread;
265}
266
268{
269 setNotificationMode(false);
270 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
271 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
272 (*it)->slotMarkAllArticlesAsRead();
273 setNotificationMode(true, true);
274}
275
277{
278 updateUnreadCount();
279 nodeModified();
280}
281
283{
284 d->children.remove(node);
285 updateUnreadCount();
286 nodeModified();
287}
288
290{
291 setNotificationMode(false);
292 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
293 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
294 (*it)->slotDeleteExpiredArticles();
295 setNotificationMode(true, true);
296}
297
298void Folder::slotAddToFetchQueue(FetchQueue* queue, bool intervalFetchOnly)
299{
300 TQValueList<TreeNode*>::ConstIterator en = d->children.end();
301 for (TQValueList<TreeNode*>::ConstIterator it = d->children.begin(); it != en; ++it)
302 (*it)->slotAddToFetchQueue(queue, intervalFetchOnly);
303}
304
306{
307}
308
309void Folder::connectToNode(TreeNode* child)
310{
311 connect(child, TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotChildChanged(TreeNode*)));
312 connect(child, TQ_SIGNAL(signalDestroyed(TreeNode*)), this, TQ_SLOT(slotChildDestroyed(TreeNode*)));
313 connect(child, TQ_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
314 connect(child, TQ_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
315 connect(child, TQ_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
316}
317
318void Folder::disconnectFromNode(TreeNode* child)
319{
320 disconnect(child, TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotChildChanged(TreeNode*)));
321 disconnect(child, TQ_SIGNAL(signalDestroyed(TreeNode*)), this, TQ_SLOT(slotChildDestroyed(TreeNode*)));
322 disconnect(child, TQ_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
323 disconnect(child, TQ_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
324 disconnect(child, TQ_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQ_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
325}
326
328{
329 if ( firstChild() )
330 return firstChild();
331
332 if ( nextSibling() )
333 return nextSibling();
334
335 Folder* p = parent();
336 while (p)
337 {
338 if ( p->nextSibling() )
339 return p->nextSibling();
340 else
341 p = p->parent();
342 }
343 return 0;
344}
345
346} // namespace Akregator
347#include "folder.moc"
Represents a folder (containing feeds and/or other folders)
Definition: folder.h:45
static Folder * fromOPML(TQDomElement e)
creates a feed group parsed from a XML dom element.
Definition: folder.cpp:63
Folder(const TQString &title=TQString())
Creates a new folder with a given title.
Definition: folder.cpp:71
virtual bool isOpen() const
returns whether the feed group is opened or not.
Definition: folder.cpp:230
virtual TQValueList< Article > articles(const TQString &tag=TQString())
returns recursively concatenated articles of children
Definition: folder.cpp:108
virtual void doArticleNotification()
reimplement this in subclasses to do the actual notification called by articlesModified
Definition: folder.cpp:305
virtual void insertChild(TreeNode *node, TreeNode *after)
inserts node as child after child node after.
Definition: folder.cpp:138
virtual void slotDeleteExpiredArticles()
Delete expired articles recursively.
Definition: folder.cpp:289
virtual void prependChild(TreeNode *node)
inserts node as first child
Definition: folder.cpp:185
virtual TreeNode * next()
returns the next node in the tree.
Definition: folder.cpp:327
virtual void slotMarkAllArticlesAsRead()
Mark articles of children recursively as read.
Definition: folder.cpp:267
virtual TQValueList< TreeNode * > children() const
returns the (direct) children of this node.
Definition: folder.cpp:133
virtual TreeNode * firstChild()
returns the first child of the group, 0 if none exist
Definition: folder.cpp:220
virtual void removeChild(TreeNode *node)
remove node from children.
Definition: folder.cpp:202
void signalChildRemoved(Folder *, TreeNode *)
emitted when a child was removed
virtual int unread() const
returns the number of unread articles in all children
Definition: folder.cpp:240
virtual void slotAddToFetchQueue(FetchQueue *queue, bool intervalFetchesOnly=false)
enqueues children recursively for fetching
Definition: folder.cpp:298
virtual void appendChild(TreeNode *node)
inserts node as last child
Definition: folder.cpp:168
virtual TQDomElement toOPML(TQDomElement parent, TQDomDocument document) const
converts the feed group into OPML format for save and export and appends it to node parent in documen...
Definition: folder.cpp:118
virtual TreeNode * lastChild()
returns the last child of the group, 0 if none exist
Definition: folder.cpp:225
virtual void slotChildChanged(TreeNode *node)
Called when a child was modified.
Definition: folder.cpp:276
virtual int totalCount() const
returns the number of articles in all children
Definition: folder.cpp:245
virtual void setOpen(bool open)
open/close the feed group (display it as expanded/collapsed in the tree view).
Definition: folder.cpp:235
virtual TQStringList tags() const
returns a list of all tags occurring in the subtree of this folder
Definition: folder.cpp:93
void signalChildAdded(TreeNode *)
emitted when a child was added
virtual void slotChildDestroyed(TreeNode *node)
Called when a child was destroyed.
Definition: folder.cpp:282
Abstract base class for all kind of elements in the feed tree, like feeds and feed groups (and search...
Definition: treenode.h:52
virtual TreeNode * nextSibling() const
Get the next sibling.
Definition: treenode.cpp:92
virtual void setTitle(const TQString &title)
Sets the title of the node.
Definition: treenode.cpp:82
void signalArticlesAdded(TreeNode *node, const TQValueList< Article > &guids)
emitted when new articles were added to this node or any node in the subtree (for folders).
virtual void setNotificationMode(bool doNotify, bool notifyOccurredChanges=true)
Definition: treenode.cpp:125
TreeNode()
Standard constructor.
Definition: treenode.cpp:48
void signalArticlesUpdated(TreeNode *, const TQValueList< Article > &guids)
emitted when articles were updated
virtual void articlesModified()
call this if the articles in the node were changed.
Definition: treenode.cpp:163
void signalChanged(TreeNode *)
Notification mechanism: emitted, when the node was modified and notification is enabled.
void signalArticlesRemoved(TreeNode *, const TQValueList< Article > &guids)
emitted when articles were removed from this subtree.
virtual void setId(uint id)
sets the ID
Definition: treenode.cpp:150
virtual const TQString & title() const
Get title of node.
Definition: treenode.cpp:77
virtual void setParent(Folder *parent)
Sets parent node; Don't call this directly, is done automatically by insertChild-methods in Folder.
Definition: treenode.cpp:120
virtual void nodeModified()
call this if you modified the actual node (title, unread count).
Definition: treenode.cpp:155
virtual Folder * parent() const
Returns the parent node.
Definition: treenode.cpp:115
virtual TQValueList< Article > articles(const TQString &tag=TQString())=0
Returns a sequence of the articles this node contains.
void signalDestroyed(TreeNode *)
Emitted when this object is deleted.