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
40namespace Akregator {
41
42class FeedList::FeedListPrivate
43{
44 public:
45
46 TQMap<TQString, TQValueList<Feed*> > urlMap;
47 AddNodeVisitor* addNodeVisitor;
48 RemoveNodeVisitor* removeNodeVisitor;
49};
50
51class 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
69class 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
85FeedList::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
97void FeedList::addNode(TreeNode* node, bool preserveID)
98{
99 NodeList::addNode(node, preserveID);
100 d->addNodeVisitor->visit(node);
101}
102
103void FeedList::removeNode(TreeNode* node)
104{
105 NodeList::removeNode(node);
106 d->removeNodeVisitor->visit(node);
107}
108
109void 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
145bool 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
194FeedList::~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
204Feed* 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
212Article 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
219void 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
238TQDomDocument 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