akregator/src

feedlist.cpp
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2004 Frank Osterfeld <frank.osterfeld at kdemail.net>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20  As a special exception, permission is given to link this program
21  with any edition of TQt, and distribute the resulting executable,
22  without including the source code for TQt in the source distribution.
23 */
24 #include "feedlist.h"
25 
26 #include <tqdatetime.h>
27 #include <tqdom.h>
28 #include <tqmap.h>
29 #include <tqvaluelist.h>
30 
31 #include <kdebug.h>
32 #include <tdelocale.h>
33 
34 #include "article.h"
35 #include "feed.h"
36 #include "folder.h"
37 #include "treenode.h"
38 #include "treenodevisitor.h"
39 
40 namespace Akregator {
41 
42 class FeedList::FeedListPrivate
43 {
44  public:
45 
46  TQMap<TQString, TQValueList<Feed*> > urlMap;
47  AddNodeVisitor* addNodeVisitor;
48  RemoveNodeVisitor* removeNodeVisitor;
49 };
50 
51 class FeedList::AddNodeVisitor : public TreeNodeVisitor
52 {
53  public:
54  AddNodeVisitor(FeedList* list) : m_list(list) {}
55  virtual ~AddNodeVisitor() {}
56 
57 
58  virtual bool visitFeed(Feed* node)
59  {
60  m_list->idMap()->insert(node->id(), node);
61  m_list->flatList()->append(node);
62  return true;
63  }
64 
65  private:
66  FeedList* m_list;
67 };
68 
69 class FeedList::RemoveNodeVisitor : public TreeNodeVisitor
70 {
71  public:
72  RemoveNodeVisitor(FeedList* list) : m_list(list) {}
73  virtual ~RemoveNodeVisitor() {}
74 
75  virtual bool visitFeed(Feed* node)
76  {
77  m_list->d->urlMap[node->xmlUrl()].remove(node);
78  return true;
79  }
80 
81  private:
82  FeedList* m_list;
83 };
84 
85 FeedList::FeedList(TQObject *parent, const char *name)
86  : NodeList(parent, name), d(new FeedListPrivate)
87 {
88  d->addNodeVisitor = new AddNodeVisitor(this);
89  d->removeNodeVisitor = new RemoveNodeVisitor(this);
90 
91  Folder* rootNode = new Folder(i18n("All Feeds"));
92  rootNode->setId(1);
93  setRootNode(rootNode);
94  addNode(rootNode, true);
95 }
96 
97 void FeedList::addNode(TreeNode* node, bool preserveID)
98 {
99  NodeList::addNode(node, preserveID);
100  d->addNodeVisitor->visit(node);
101 }
102 
103 void FeedList::removeNode(TreeNode* node)
104 {
105  NodeList::removeNode(node);
106  d->removeNodeVisitor->visit(node);
107 }
108 
109 void FeedList::parseChildNodes(TQDomNode &node, Folder* parent)
110 {
111  TQDomElement e = node.toElement(); // try to convert the node to an element.
112 
113  if( !e.isNull() )
114  {
115  TQString title = e.hasAttribute("text") ? e.attribute("text") : e.attribute("title");
116 
117  if (e.hasAttribute("xmlUrl") || e.hasAttribute("xmlurl") || e.hasAttribute("xmlURL") )
118  {
119  Feed* feed = Feed::fromOPML(e);
120  if (feed)
121  {
122  if (!d->urlMap[feed->xmlUrl()].contains(feed))
123  d->urlMap[feed->xmlUrl()].append(feed);
124  parent->appendChild(feed);
125  }
126  }
127  else
128  {
129  Folder* fg = Folder::fromOPML(e);
130  parent->appendChild(fg);
131 
132  if (e.hasChildNodes())
133  {
134  TQDomNode child = e.firstChild();
135  while(!child.isNull())
136  {
137  parseChildNodes(child, fg);
138  child = child.nextSibling();
139  }
140  }
141  }
142  }
143 }
144 
145 bool FeedList::readFromXML(const TQDomDocument& doc)
146 {
147  TQDomElement root = doc.documentElement();
148 
149  kdDebug() << "loading OPML feed " << root.tagName().lower() << endl;
150 
151  kdDebug() << "measuring startup time: START" << endl;
152  TQTime spent;
153  spent.start();
154 
155  if (root.tagName().lower() != "opml")
156  {
157  return false;
158  }
159  TQDomNode bodyNode = root.firstChild();
160 
161  while (!bodyNode.isNull() && bodyNode.toElement().tagName().lower() != "body")
162  bodyNode = bodyNode.nextSibling();
163 
164 
165  if (bodyNode.isNull())
166  {
167  kdDebug() << "Failed to acquire body node, markup broken?" << endl;
168  return false;
169  }
170 
171  TQDomElement body = bodyNode.toElement();
172 
173  TQDomNode i = body.firstChild();
174 
175  while( !i.isNull() )
176  {
177  parseChildNodes(i, rootNode());
178  i = i.nextSibling();
179  }
180 
181  for (TreeNode* i = rootNode()->firstChild(); i && i != rootNode(); i = i->next() )
182  if (i->id() == 0)
183  {
184  uint id = generateID();
185  i->setId(id);
186  idMap()->insert(id, i);
187  }
188 
189  kdDebug() << "measuring startup time: STOP, " << spent.elapsed() << "ms" << endl;
190  kdDebug() << "Number of articles loaded: " << rootNode()->totalCount() << endl;
191  return true;
192 }
193 
194 FeedList::~FeedList()
195 {
196  emit signalDestroyed(this);
197  setRootNode(0);
198  delete d->addNodeVisitor;
199  delete d->removeNodeVisitor;
200  delete d;
201  d = 0;
202 }
203 
204 Feed* FeedList::findByURL(const TQString& feedURL) const
205 {
206  if (d->urlMap[feedURL].isEmpty())
207  return 0;
208  else
209  return *(d->urlMap[feedURL].begin());
210 }
211 
212 Article FeedList::findArticle(const TQString& feedURL, const TQString& guid) const
213 {
214  Feed* feed = findByURL(feedURL);
215 
216  return feed ? feed->findArticle(guid) : Article();
217 }
218 
219 void FeedList::append(FeedList* list, Folder* parent, TreeNode* after)
220 {
221  if ( list == this )
222  return;
223 
224  if ( !flatList()->contains(parent) )
225  parent = rootNode();
226 
227  TQValueList<TreeNode*> children = list->rootNode()->children();
228 
229  TQValueList<TreeNode*>::ConstIterator end( children.end() );
230  for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
231  {
232  list->rootNode()->removeChild(*it);
233  parent->insertChild(*it, after);
234  after = *it;
235  }
236 }
237 
238 TQDomDocument FeedList::toXML() const
239 {
240  TQDomDocument doc;
241  doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
242 
243  TQDomElement root = doc.createElement( "opml" );
244  root.setAttribute( "version", "1.0" );
245  doc.appendChild( root );
246 
247  TQDomElement head = doc.createElement( "head" );
248  root.appendChild( head );
249 
250  TQDomElement ti = doc.createElement( "text" );
251  head.appendChild( ti );
252 
253  TQDomText t = doc.createTextNode( title() );
254  ti.appendChild( t );
255 
256  TQDomElement body = doc.createElement( "body" );
257  root.appendChild( body );
258 
259  TQValueList<TreeNode*> children = rootNode()->children();
260 
261  TQValueList<TreeNode*>::ConstIterator end( children.end() );
262 
263  for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
264  body.appendChild( (*it)->toOPML(body, doc) );
265 
266  return doc;
267 }
268 
269 } // namespace Akregator
270 #include "feedlist.moc"
A proxy class for RSS::Article with some additional methods to assist sorting.
Definition: article.h:58
The model of a feed tree, represents an OPML document.
Definition: feedlist.h:45
represents a feed
Definition: feed.h:63
virtual Article findArticle(const TQString &guid) const
returns the article with the given guid, or a null article if it not exists
Definition: feed.cpp:187
Represents a folder (containing feeds and/or other folders)
Definition: folder.h:45
virtual void insertChild(TreeNode *node, TreeNode *after)
inserts node as child after child node after.
Definition: folder.cpp:138
Abstract base class for all kind of elements in the feed tree, like feeds and feed groups (and search...
Definition: treenode.h:52