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 <klocale.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 
56 
57  virtual bool visitFeed(Feed* node)
58  {
59  m_list->idMap()->insert(node->id(), node);
60  m_list->flatList()->append(node);
61  return true;
62  }
63 
64  private:
65  FeedList* m_list;
66 };
67 
68 class FeedList::RemoveNodeVisitor : public TreeNodeVisitor
69 {
70  public:
71  RemoveNodeVisitor(FeedList* list) : m_list(list) {}
72 
73  virtual bool visitFeed(Feed* node)
74  {
75  m_list->d->urlMap[node->xmlUrl()].remove(node);
76  return true;
77  }
78 
79  private:
80  FeedList* m_list;
81 };
82 
83 FeedList::FeedList(TQObject *parent, const char *name)
84  : NodeList(parent, name), d(new FeedListPrivate)
85 {
86  d->addNodeVisitor = new AddNodeVisitor(this);
87  d->removeNodeVisitor = new RemoveNodeVisitor(this);
88 
89  Folder* rootNode = new Folder(i18n("All Feeds"));
90  rootNode->setId(1);
91  setRootNode(rootNode);
92  addNode(rootNode, true);
93 }
94 
95 void FeedList::addNode(TreeNode* node, bool preserveID)
96 {
97  NodeList::addNode(node, preserveID);
98  d->addNodeVisitor->visit(node);
99 }
100 
101 void FeedList::removeNode(TreeNode* node)
102 {
103  NodeList::removeNode(node);
104  d->removeNodeVisitor->visit(node);
105 }
106 
107 void FeedList::parseChildNodes(TQDomNode &node, Folder* parent)
108 {
109  TQDomElement e = node.toElement(); // try to convert the node to an element.
110 
111  if( !e.isNull() )
112  {
113  TQString title = e.hasAttribute("text") ? e.attribute("text") : e.attribute("title");
114 
115  if (e.hasAttribute("xmlUrl") || e.hasAttribute("xmlurl") || e.hasAttribute("xmlURL") )
116  {
117  Feed* feed = Feed::fromOPML(e);
118  if (feed)
119  {
120  if (!d->urlMap[feed->xmlUrl()].contains(feed))
121  d->urlMap[feed->xmlUrl()].append(feed);
122  parent->appendChild(feed);
123  }
124  }
125  else
126  {
127  Folder* fg = Folder::fromOPML(e);
128  parent->appendChild(fg);
129 
130  if (e.hasChildNodes())
131  {
132  TQDomNode child = e.firstChild();
133  while(!child.isNull())
134  {
135  parseChildNodes(child, fg);
136  child = child.nextSibling();
137  }
138  }
139  }
140  }
141 }
142 
143 bool FeedList::readFromXML(const TQDomDocument& doc)
144 {
145  TQDomElement root = doc.documentElement();
146 
147  kdDebug() << "loading OPML feed " << root.tagName().lower() << endl;
148 
149  kdDebug() << "measuring startup time: START" << endl;
150  TQTime spent;
151  spent.start();
152 
153  if (root.tagName().lower() != "opml")
154  {
155  return false;
156  }
157  TQDomNode bodyNode = root.firstChild();
158 
159  while (!bodyNode.isNull() && bodyNode.toElement().tagName().lower() != "body")
160  bodyNode = bodyNode.nextSibling();
161 
162 
163  if (bodyNode.isNull())
164  {
165  kdDebug() << "Failed to acquire body node, markup broken?" << endl;
166  return false;
167  }
168 
169  TQDomElement body = bodyNode.toElement();
170 
171  TQDomNode i = body.firstChild();
172 
173  while( !i.isNull() )
174  {
175  parseChildNodes(i, rootNode());
176  i = i.nextSibling();
177  }
178 
179  for (TreeNode* i = rootNode()->firstChild(); i && i != rootNode(); i = i->next() )
180  if (i->id() == 0)
181  {
182  uint id = generateID();
183  i->setId(id);
184  idMap()->insert(id, i);
185  }
186 
187  kdDebug() << "measuring startup time: STOP, " << spent.elapsed() << "ms" << endl;
188  kdDebug() << "Number of articles loaded: " << rootNode()->totalCount() << endl;
189  return true;
190 }
191 
193 {
194  emit signalDestroyed(this);
195  setRootNode(0);
196  delete d->addNodeVisitor;
197  delete d->removeNodeVisitor;
198  delete d;
199  d = 0;
200 }
201 
202 Feed* FeedList::findByURL(const TQString& feedURL) const
203 {
204  if (d->urlMap[feedURL].isEmpty())
205  return 0;
206  else
207  return *(d->urlMap[feedURL].begin());
208 }
209 
210 Article FeedList::findArticle(const TQString& feedURL, const TQString& guid) const
211 {
212  Feed* feed = findByURL(feedURL);
213 
214  return feed ? feed->findArticle(guid) : Article();
215 }
216 
217 void FeedList::append(FeedList* list, Folder* parent, TreeNode* after)
218 {
219  if ( list == this )
220  return;
221 
222  if ( !flatList()->contains(parent) )
223  parent = rootNode();
224 
225  TQValueList<TreeNode*> children = list->rootNode()->children();
226 
227  TQValueList<TreeNode*>::ConstIterator end( children.end() );
228  for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
229  {
230  list->rootNode()->removeChild(*it);
231  parent->insertChild(*it, after);
232  after = *it;
233  }
234 }
235 
236 TQDomDocument FeedList::toXML() const
237 {
238  TQDomDocument doc;
239  doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
240 
241  TQDomElement root = doc.createElement( "opml" );
242  root.setAttribute( "version", "1.0" );
243  doc.appendChild( root );
244 
245  TQDomElement head = doc.createElement( "head" );
246  root.appendChild( head );
247 
248  TQDomElement ti = doc.createElement( "text" );
249  head.appendChild( ti );
250 
251  TQDomText t = doc.createTextNode( title() );
252  ti.appendChild( t );
253 
254  TQDomElement body = doc.createElement( "body" );
255  root.appendChild( body );
256 
257  TQValueList<TreeNode*> children = rootNode()->children();
258 
259  TQValueList<TreeNode*>::ConstIterator end( children.end() );
260 
261  for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
262  body.appendChild( (*it)->toOPML(body, doc) );
263 
264  return doc;
265 }
266 
267 } // namespace Akregator
268 #include "feedlist.moc"