akregator/src

feedlist.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Frank Osterfeld <frank.osterfeld at kdemail.net>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of TQt, and distribute the resulting executable,
00022     without including the source code for TQt in the source distribution.
00023 */
00024 #include "feedlist.h"
00025 
00026 #include <tqdatetime.h>
00027 #include <tqdom.h>
00028 #include <tqmap.h>
00029 #include <tqvaluelist.h>
00030 
00031 #include <kdebug.h>
00032 #include <tdelocale.h>
00033 
00034 #include "article.h"
00035 #include "feed.h"
00036 #include "folder.h"
00037 #include "treenode.h"
00038 #include "treenodevisitor.h"
00039 
00040 namespace Akregator {
00041 
00042 class FeedList::FeedListPrivate
00043 {
00044     public:
00045 
00046         TQMap<TQString, TQValueList<Feed*> > urlMap;
00047         AddNodeVisitor* addNodeVisitor;
00048         RemoveNodeVisitor* removeNodeVisitor;
00049 };
00050 
00051 class FeedList::AddNodeVisitor : public TreeNodeVisitor
00052 {
00053     public:
00054         AddNodeVisitor(FeedList* list) : m_list(list) {}
00055         virtual ~AddNodeVisitor() {}
00056 
00057 
00058         virtual bool visitFeed(Feed* node)
00059         {
00060             m_list->idMap()->insert(node->id(), node);
00061             m_list->flatList()->append(node);
00062             return true;
00063         }
00064 
00065     private:
00066         FeedList* m_list;
00067 };
00068 
00069 class FeedList::RemoveNodeVisitor : public TreeNodeVisitor
00070 {
00071     public:
00072         RemoveNodeVisitor(FeedList* list) : m_list(list) {}
00073         virtual ~RemoveNodeVisitor() {}
00074 
00075         virtual bool visitFeed(Feed* node)
00076         {
00077             m_list->d->urlMap[node->xmlUrl()].remove(node);
00078             return true;
00079         }
00080 
00081     private:
00082         FeedList* m_list;
00083 };
00084 
00085 FeedList::FeedList(TQObject *parent, const char *name)
00086     : NodeList(parent, name), d(new FeedListPrivate)
00087 {
00088     d->addNodeVisitor = new AddNodeVisitor(this);
00089     d->removeNodeVisitor = new RemoveNodeVisitor(this);
00090 
00091     Folder* rootNode = new Folder(i18n("All Feeds"));
00092     rootNode->setId(1);
00093     setRootNode(rootNode);
00094     addNode(rootNode, true);
00095 }
00096 
00097 void FeedList::addNode(TreeNode* node, bool preserveID)
00098 {
00099     NodeList::addNode(node, preserveID);
00100     d->addNodeVisitor->visit(node);
00101 }
00102 
00103 void FeedList::removeNode(TreeNode* node)
00104 {
00105    NodeList::removeNode(node);
00106    d->removeNodeVisitor->visit(node);
00107 }
00108 
00109 void FeedList::parseChildNodes(TQDomNode &node, Folder* parent)
00110 {
00111     TQDomElement e = node.toElement(); // try to convert the node to an element.
00112 
00113     if( !e.isNull() )
00114     {
00115         TQString title = e.hasAttribute("text") ? e.attribute("text") : e.attribute("title");
00116 
00117         if (e.hasAttribute("xmlUrl") || e.hasAttribute("xmlurl") || e.hasAttribute("xmlURL") )
00118         {
00119             Feed* feed = Feed::fromOPML(e);
00120             if (feed)
00121             {
00122                 if (!d->urlMap[feed->xmlUrl()].contains(feed))
00123                     d->urlMap[feed->xmlUrl()].append(feed);
00124                 parent->appendChild(feed);
00125             }
00126         }
00127         else
00128         {
00129             Folder* fg = Folder::fromOPML(e);
00130             parent->appendChild(fg);
00131 
00132             if (e.hasChildNodes())
00133             {
00134                 TQDomNode child = e.firstChild();
00135                 while(!child.isNull())
00136                 {
00137                     parseChildNodes(child, fg);
00138                     child = child.nextSibling();
00139                 }
00140             }
00141         }
00142     }
00143 }
00144 
00145 bool FeedList::readFromXML(const TQDomDocument& doc)
00146 {
00147     TQDomElement root = doc.documentElement();
00148 
00149     kdDebug() << "loading OPML feed " << root.tagName().lower() << endl;
00150 
00151     kdDebug() << "measuring startup time: START" << endl;
00152     TQTime spent;
00153     spent.start();
00154 
00155     if (root.tagName().lower() != "opml")
00156     {
00157         return false;
00158     }
00159     TQDomNode bodyNode = root.firstChild();
00160 
00161     while (!bodyNode.isNull() && bodyNode.toElement().tagName().lower() != "body")
00162         bodyNode = bodyNode.nextSibling();
00163 
00164 
00165     if (bodyNode.isNull())
00166     {
00167         kdDebug() << "Failed to acquire body node, markup broken?" << endl;
00168         return false;
00169     }
00170 
00171     TQDomElement body = bodyNode.toElement();
00172 
00173     TQDomNode i = body.firstChild();
00174 
00175     while( !i.isNull() )
00176     {
00177         parseChildNodes(i, rootNode());
00178         i = i.nextSibling();
00179     }
00180 
00181     for (TreeNode* i = rootNode()->firstChild(); i && i != rootNode(); i = i->next() )
00182         if (i->id() == 0)
00183     {
00184             uint id = generateID();
00185             i->setId(id);
00186             idMap()->insert(id, i);
00187     }
00188 
00189     kdDebug() << "measuring startup time: STOP, " << spent.elapsed() << "ms" << endl;
00190     kdDebug() << "Number of articles loaded: " << rootNode()->totalCount() << endl;
00191     return true;
00192 }
00193 
00194 FeedList::~FeedList()
00195 {
00196     emit signalDestroyed(this);
00197     setRootNode(0);
00198     delete d->addNodeVisitor;
00199     delete d->removeNodeVisitor;
00200     delete d;
00201     d = 0;
00202 }
00203 
00204 Feed* FeedList::findByURL(const TQString& feedURL) const
00205 {
00206     if (d->urlMap[feedURL].isEmpty())
00207         return 0;
00208     else
00209         return *(d->urlMap[feedURL].begin());
00210 }
00211 
00212 Article FeedList::findArticle(const TQString& feedURL, const TQString& guid) const
00213 {
00214     Feed* feed = findByURL(feedURL);
00215 
00216     return feed ? feed->findArticle(guid) : Article();
00217 }
00218 
00219 void FeedList::append(FeedList* list, Folder* parent, TreeNode* after)
00220 {
00221     if ( list == this )
00222         return;
00223 
00224     if ( !flatList()->contains(parent) )
00225         parent = rootNode();
00226 
00227     TQValueList<TreeNode*> children = list->rootNode()->children();
00228 
00229     TQValueList<TreeNode*>::ConstIterator end(  children.end() );
00230     for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
00231     {
00232         list->rootNode()->removeChild(*it);
00233         parent->insertChild(*it, after);
00234         after = *it;
00235     }
00236 }
00237 
00238 TQDomDocument FeedList::toXML() const
00239 {
00240     TQDomDocument doc;
00241     doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
00242 
00243     TQDomElement root = doc.createElement( "opml" );
00244     root.setAttribute( "version", "1.0" );
00245     doc.appendChild( root );
00246 
00247     TQDomElement head = doc.createElement( "head" );
00248     root.appendChild( head );
00249 
00250     TQDomElement ti = doc.createElement( "text" );
00251     head.appendChild( ti );
00252 
00253     TQDomText t = doc.createTextNode( title() );
00254     ti.appendChild( t );
00255 
00256     TQDomElement body = doc.createElement( "body" );
00257     root.appendChild( body );
00258 
00259     TQValueList<TreeNode*> children = rootNode()->children();
00260 
00261     TQValueList<TreeNode*>::ConstIterator end(  children.end() );
00262 
00263     for (TQValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
00264         body.appendChild( (*it)->toOPML(body, doc) );
00265 
00266     return doc;
00267 }
00268 
00269 } // namespace Akregator
00270 #include "feedlist.moc"