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, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*)));
312  connect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*)));
313  connect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
314  connect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
315  connect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
316 }
317 
318 void Folder::disconnectFromNode(TreeNode* child)
319 {
320  disconnect(child, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotChildChanged(TreeNode*)));
321  disconnect(child, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotChildDestroyed(TreeNode*)));
322  disconnect(child, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)));
323  disconnect(child, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
324  disconnect(child, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_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"