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 Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 #include "feedlist.h"
00025 
00026 #include <qdatetime.h>
00027 #include <qdom.h>
00028 #include <qmap.h>
00029 #include <qvaluelist.h>
00030 
00031 #include <kdebug.h>
00032 #include <klocale.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         QMap<QString, QValueList<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 
00056 
00057         virtual bool visitFeed(Feed* node)
00058         {
00059             m_list->idMap()->insert(node->id(), node);
00060             m_list->flatList()->append(node);
00061             return true;
00062         }
00063 
00064     private:
00065         FeedList* m_list;
00066 };
00067 
00068 class FeedList::RemoveNodeVisitor : public TreeNodeVisitor
00069 {
00070     public:
00071         RemoveNodeVisitor(FeedList* list) : m_list(list) {}
00072 
00073         virtual bool visitFeed(Feed* node)
00074         {
00075             m_list->d->urlMap[node->xmlUrl()].remove(node);
00076             return true;
00077         }
00078 
00079     private:
00080         FeedList* m_list;
00081 };
00082 
00083 FeedList::FeedList(QObject *parent, const char *name)
00084     : NodeList(parent, name), d(new FeedListPrivate)
00085 {
00086     d->addNodeVisitor = new AddNodeVisitor(this);
00087     d->removeNodeVisitor = new RemoveNodeVisitor(this);
00088 
00089     Folder* rootNode = new Folder(i18n("All Feeds"));
00090     rootNode->setId(1);
00091     setRootNode(rootNode);
00092     addNode(rootNode, true);
00093 }
00094 
00095 void FeedList::addNode(TreeNode* node, bool preserveID)
00096 {
00097     NodeList::addNode(node, preserveID);
00098     d->addNodeVisitor->visit(node);
00099 }
00100 
00101 void FeedList::removeNode(TreeNode* node)
00102 {
00103    NodeList::removeNode(node);
00104    d->removeNodeVisitor->visit(node);
00105 }
00106 
00107 void FeedList::parseChildNodes(QDomNode &node, Folder* parent)
00108 {
00109     QDomElement e = node.toElement(); // try to convert the node to an element.
00110 
00111     if( !e.isNull() )
00112     {
00113         QString title = e.hasAttribute("text") ? e.attribute("text") : e.attribute("title");
00114 
00115         if (e.hasAttribute("xmlUrl") || e.hasAttribute("xmlurl"))
00116         {
00117             Feed* feed = Feed::fromOPML(e);
00118             if (feed)
00119             {
00120                 if (!d->urlMap[feed->xmlUrl()].contains(feed))
00121                     d->urlMap[feed->xmlUrl()].append(feed);
00122                 parent->appendChild(feed);
00123             }
00124         }
00125         else
00126         {
00127             Folder* fg = Folder::fromOPML(e);
00128             parent->appendChild(fg);
00129 
00130             if (e.hasChildNodes())
00131             {
00132                 QDomNode child = e.firstChild();
00133                 while(!child.isNull())
00134                 {
00135                     parseChildNodes(child, fg);
00136                     child = child.nextSibling();
00137                 }
00138             }
00139         }
00140     }
00141 }
00142 
00143 bool FeedList::readFromXML(const QDomDocument& doc)
00144 {
00145     QDomElement root = doc.documentElement();
00146 
00147     kdDebug() << "loading OPML feed " << root.tagName().lower() << endl;
00148 
00149     kdDebug() << "measuring startup time: START" << endl;
00150     QTime spent;
00151     spent.start();
00152 
00153     if (root.tagName().lower() != "opml")
00154     {
00155         return false;
00156     }
00157     QDomNode bodyNode = root.firstChild();
00158 
00159     while (!bodyNode.isNull() && bodyNode.toElement().tagName().lower() != "body")
00160         bodyNode = bodyNode.nextSibling();
00161 
00162 
00163     if (bodyNode.isNull())
00164     {
00165         kdDebug() << "Failed to acquire body node, markup broken?" << endl;
00166         return false;
00167     }
00168 
00169     QDomElement body = bodyNode.toElement();
00170 
00171     QDomNode i = body.firstChild();
00172 
00173     while( !i.isNull() )
00174     {
00175         parseChildNodes(i, rootNode());
00176         i = i.nextSibling();
00177     }
00178 
00179     for (TreeNode* i = rootNode()->firstChild(); i && i != rootNode(); i = i->next() )
00180         if (i->id() == 0)
00181     {
00182             uint id = generateID();
00183             i->setId(id);
00184             idMap()->insert(id, i);
00185     }
00186 
00187     kdDebug() << "measuring startup time: STOP, " << spent.elapsed() << "ms" << endl;
00188     kdDebug() << "Number of articles loaded: " << rootNode()->totalCount() << endl;
00189     return true;
00190 }
00191 
00192 FeedList::~FeedList()
00193 {
00194     emit signalDestroyed(this);
00195     setRootNode(0);
00196     delete d->addNodeVisitor;
00197     delete d->removeNodeVisitor;
00198     delete d;
00199     d = 0;
00200 }
00201 
00202 Feed* FeedList::findByURL(const QString& feedURL) const
00203 {
00204     if (d->urlMap[feedURL].isEmpty())
00205         return 0;
00206     else
00207         return *(d->urlMap[feedURL].begin());
00208 }
00209 
00210 Article FeedList::findArticle(const QString& feedURL, const QString& guid) const
00211 {
00212     Feed* feed = findByURL(feedURL);
00213 
00214     return feed ? feed->findArticle(guid) : Article();
00215 }
00216 
00217 void FeedList::append(FeedList* list, Folder* parent, TreeNode* after)
00218 {
00219     if ( list == this )
00220         return;
00221 
00222     if ( !flatList()->contains(parent) )
00223         parent = rootNode();
00224 
00225     QValueList<TreeNode*> children = list->rootNode()->children();
00226 
00227     QValueList<TreeNode*>::ConstIterator end(  children.end() );
00228     for (QValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
00229     {
00230         list->rootNode()->removeChild(*it);
00231         parent->insertChild(*it, after);
00232         after = *it;
00233     }
00234 }
00235 
00236 QDomDocument FeedList::toXML() const
00237 {
00238     QDomDocument doc;
00239     doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
00240 
00241     QDomElement root = doc.createElement( "opml" );
00242     root.setAttribute( "version", "1.0" );
00243     doc.appendChild( root );
00244 
00245     QDomElement head = doc.createElement( "head" );
00246     root.appendChild( head );
00247 
00248     QDomElement ti = doc.createElement( "text" );
00249     head.appendChild( ti );
00250 
00251     QDomText t = doc.createTextNode( title() );
00252     ti.appendChild( t );
00253 
00254     QDomElement body = doc.createElement( "body" );
00255     root.appendChild( body );
00256 
00257     QValueList<TreeNode*> children = rootNode()->children();
00258 
00259     QValueList<TreeNode*>::ConstIterator end(  children.end() );
00260 
00261     for (QValueList<TreeNode*>::ConstIterator it = children.begin(); it != end; ++it)
00262         body.appendChild( (*it)->toOPML(body, doc) );
00263 
00264     return doc;
00265 }
00266 
00267 } // namespace Akregator
00268 #include "feedlist.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys