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 
37 namespace Akregator {
38 
39 class 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 
55 bool Folder::accept(TreeNodeVisitor* visitor)
56 {
57  if (visitor->visitFolder(this))
58  return true;
59  else
60  return visitor->visitTreeNode(this);
61 }
62 
63 Folder* 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 
71 Folder::Folder(const TQString& title) : TreeNode(), d(new FolderPrivate)
72 {
73  d->unread = 0;
74  setTitle(title);
75 }
76 
77 Folder::~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 
93 TQStringList 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 
108 TQValueList<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 
118 TQDomElement 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 
133 TQValueList<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 
148 void 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 
230 bool Folder::isOpen() const
231 {
232  return d->open;
233 }
234 
235 void Folder::setOpen(bool open)
236 {
237  d->open = open;
238 }
239 
240 int 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 
256 void 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 
298 void 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 
309 void 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 
318 void 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 TQValueList< Article > articles(const TQString &tag=TQString())=0
Returns a sequence of the articles this node contains.
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
void signalDestroyed(TreeNode *)
Emitted when this object is deleted.