Fwd: [Amarok] [BAD EMAIL] fix SqlPodcastMeta copy constructor, partial rewri

Maximilian Kossick maximilian.kossick at googlemail.com
Wed Nov 18 11:49:56 CET 2009


bart, why do these classes have a copy constructor at all?


---------- Forwarded message ----------
From: .mail.kde.org Mathias Panzenböck <panzi at panzi>
Date: Wed, Nov 18, 2009 at 10:51 AM
Subject: [Amarok] [BAD EMAIL]  fix SqlPodcastMeta copy constructor,
partial rewri
To: kde-commits at kde.org


commit 6569866efd63a698a63ecefbb381cff03fd8f3dd
Author:     Mathias Panzenböck <panzi at panzi.(none)>
AuthorDate: Sun Nov 15 19:07:39 2009 +0100
Commit:     Mathias Panzenböck <panzi at panzi.(none)>
CommitDate: Sun Nov 15 19:07:39 2009 +0100

   fix SqlPodcastMeta copy constructor, partial rewrite of PodcastReader

   In the copy constructor of SqlPodcastMeta where not all fields copied.
   Started a partial rewrite of PodcastReader. Currently there is a strange
   bug where the subscriptions are doubled on each feed update.
   Made HTML generated by PodcastCategory more nice.

diff --git a/src/browsers/playlistbrowser/PodcastCategory.cpp
b/src/browsers/playlistbrowser/PodcastCategory.cpp
index a72db3c..969de87 100644
--- a/src/browsers/playlistbrowser/PodcastCategory.cpp
+++ b/src/browsers/playlistbrowser/PodcastCategory.cpp
@@ -40,6 +40,7 @@
 #include <QToolBar>
 #include <QVBoxLayout>
 #include <QWebFrame>
+#include <QTextDocument>
 #include <qnamespace.h>

 #include <KAction>
@@ -154,12 +155,30 @@ PodcastCategory::~PodcastCategory()
 void
 PodcastCategory::showInfo( const QModelIndex & index )
 {
-    QString description = index.data( ShortDescriptionRole ).toString();
-    description.replace( QRegExp("\n "), "\n" );
-    description.replace( QRegExp("\n+"), "\n" );
+    QString title = index.data( Qt::DisplayRole ).toString();
+    QString description =
+               "<html>"
+               "    <head>"
+               "        <title>";
+       description += Qt::escape(title);
+       description += "</title>"
+               "        <style type=\"text/css\">h1
{text-align:center; font-size: 1em;}</style>"
+               "    </head>"
+               "    <body>"
+               "        <h1>";
+       description += Qt::escape(title);
+       description += "</h1>";
+       description += index.data( ShortDescriptionRole ).toString();
+       description +=
+               "    </body>"
+               "</html>";
+
+       qDebug("\n");
+       qDebug() << description;
+       qDebug("\n");

    QVariantMap map;
-    map["service_name"] = "Podcasts";
+    map["service_name"] = title;
    map["main_info"] = description;
    The::infoProxy()->setInfo( map );
 }
diff --git a/src/context/applets/info/InfoApplet.cpp
b/src/context/applets/info/InfoApplet.cpp
index 7c58812..01f483e 100644
--- a/src/context/applets/info/InfoApplet.cpp
+++ b/src/context/applets/info/InfoApplet.cpp
@@ -90,11 +90,9 @@ void InfoApplet::dataUpdated( const QString& name,
const Plasma::DataEngine::Dat

    if  ( m_initialized )
    {
-        if ( !data[ "main_info" ].toString().isEmpty() )
+               QString currentHtml = data[ "main_info" ].toString();
+        if ( !currentHtml.isEmpty() )
        {
-
-            QString currentHtml = data[ "main_info" ].toString();
-
            QColor highlight( App::instance()->palette().highlight().color() );
            highlight.setHsvF( highlight.hueF(), 0.3, .95, highlight.alphaF() );
            currentHtml = currentHtml.replace( "{text_color}",
App::instance()->palette().brush( QPalette::Text ).color().name() );
@@ -106,9 +104,9 @@ void InfoApplet::dataUpdated( const QString& name,
const Plasma::DataEngine::Dat
        }
        else
        {
-            QString html = s_defaultHtml;
-            html = html.replace( "%%SUBJECT_NAME%%", data[
"subject_name" ].toString() );
-            m_webView->setHtml( html );
+            currentHtml = s_defaultHtml;
+            currentHtml = currentHtml.replace( "%%SUBJECT_NAME%%",
data[ "subject_name" ].toString() );
+            m_webView->setHtml( currentHtml );
        }

        m_webView->page()->setLinkDelegationPolicy(
QWebPage::DelegateAllLinks );
diff --git a/src/podcasts/PodcastReader.cpp b/src/podcasts/PodcastReader.cpp
index 9b503b7..042413f 100644
--- a/src/podcasts/PodcastReader.cpp
+++ b/src/podcasts/PodcastReader.cpp
@@ -23,6 +23,7 @@
 #include <kurl.h>
 #include <KDateTime>

+#include <QTextDocument>
 #include <QDate>
 #include <time.h>

@@ -33,8 +34,6 @@ PodcastReader::PodcastReader( PodcastProvider *
podcastProvider )
        , m_feedType( UnknownFeedType )
        , m_podcastProvider( podcastProvider )
        , m_transferJob( 0 )
-        , m_current( 0 )
-        , m_parsingImage( false )
 {}

 PodcastReader::~PodcastReader()
@@ -61,7 +60,7 @@ PodcastReader::read( const KUrl &url )
    connect( m_transferJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
             SLOT( slotAddData( KIO::Job *, const QByteArray & ) ) );

-    connect( m_transferJob, SIGNAL(  result( KJob * ) ),
+    connect( m_transferJob, SIGNAL( result( KJob * ) ),
             SLOT( downloadResult( KJob * ) ) );

    connect( m_transferJob, SIGNAL( redirection( KIO::Job *, const KUrl & ) ),
@@ -96,7 +95,6 @@ PodcastReader::update( PodcastChannelPtr channel )
 {
    DEBUG_BLOCK
    m_channel = channel;
-    m_current = static_cast<PodcastMetaCommon *>(channel.data());

    return read( m_channel->url() );
 }
@@ -107,9 +105,7 @@ PodcastReader::slotAddData( KIO::Job *job, const
QByteArray &data )
    DEBUG_BLOCK
    Q_UNUSED( job )

-    QXmlStreamReader::addData( data );
-    //parse some more data
-    read();
+    qxml::addData( data );
 }

 void
@@ -146,206 +142,369 @@ PodcastReader::downloadResult( KJob * job )

        The::statusBar()->longMessage( errorMessage, StatusBar::Sorry );
    }
-    //parse some more data
+
+    // parse data
    read();
 }

-bool
-PodcastReader::read()
+QString
+PodcastReader::readInnerXml()
 {
-    DEBUG_BLOCK
-    bool result = true;
+       QString xml;
+       int level = 1;

    while ( !atEnd() )
    {
-        if( !error() )
-        {
-            readNext();
-        }
-        else if ( error() == PrematureEndOfDocumentError )
-        {
-            debug() << "recovering from PrematureEndOfDocumentError for "
-                    << QXmlStreamReader::name().toString() << " at "
-                    << QXmlStreamReader::lineNumber();
-            readNext();
-        }
-        else
-        {
-            debug() << "some other error occurred: " << errorString();
-            m_transferJob->kill();
-            m_transferJob = 0;
-            emit finished( this );
-        }
+               switch ( nextToken() ) {
+               case Invalid:
+                       // this should not happen
+                       debug() << "*** Invalid *** " << errorString();
+                       return xml;
+
+               case StartElement:
+                       ++ level;
+                       xml += QString("<%1").arg(qxml::name().toString());
+
+                       foreach( const QXmlStreamAttribute& attr,
attributes() ) {
+                               xml += QString(" %1=\"%2\"")
+                                       .arg(attr.name().toString())
+
.arg(Qt::escape(attr.value().toString()));
+                       }
+                       xml += '>';
+                       break;
+
+               case EndElement:
+                       -- level;
+                       if (level == 0)
+                               return xml;
+                       xml += QString("</%1>").arg(qxml::name().toString());
+                       break;
+
+               case Characters:
+                       xml += text();
+
+               default:
+                       break;
+               }
+       }
+
+       return xml;
+}

-        if( m_feedType == UnknownFeedType )
-        {
-            //Pre Channel
-            if( isStartElement() )
-            {
-                debug() << "Initial StartElement: " <<
QXmlStreamReader::name().toString();
-                debug() << "version: " << attributes().value (
"version" ).toString();
-                if( QXmlStreamReader::name() == "rss" &&
attributes().value ( "version" ) == "2.0" )
-                {
-                    m_feedType = Rss20FeedType;
-                }
-                else if( QXmlStreamReader::name() == "html" )
-                {
-                    m_feedType = ErrorPageType;
-                    raiseError( i18n( "An HTML page was received.
Expected an RSS 2.0 feed" ) );
-                    result = false;
-                    break;
-                }
-                else
-                {
-                    //TODO: change this string once we support more
-                    raiseError( i18n( "%1 is not an RSS version 2.0
feed.", m_url.url() ) );
-                    result = false;
-                    break;
-                }
-            }
-            else if( tokenType() != QXmlStreamReader::StartDocument )
-            {
-                debug() << "some weird thing happend at line: "
-                        << QXmlStreamReader::lineNumber();
-                debug() << "\terror: " << QXmlStreamReader::name().toString();
-                debug() << "\ttoken type: " << tokenString();
-            }
-        }
-        else
-        {
-            if( isStartElement() )
-            {
-                if( QXmlStreamReader::name() == "item" )
-                {
-                    debug() << "new episode";
-                    m_current = new Meta::PodcastEpisode( m_channel );
-                }
-                else if( QXmlStreamReader::name() == "enclosure" )
-                {
-                    m_urlString =
QXmlStreamReader::attributes().value( QString(), QString("url")
).toString();
-                }
-                else if( QXmlStreamReader::name() == "image" )
-                {
-                    m_parsingImage = true;
-                }
-                else if( QXmlStreamReader::name() == "channel" )
-                {
-                    if( !m_current )
-                    {
-                        debug() << "new channel";
-                        m_channel = new Meta::PodcastChannel();
-                        m_channel->setUrl( m_url );
-                        m_channel->setSubscribeDate( QDate::currentDate() );
-                        /* add this new channel to the provider, we
get a pointer to a
-                        * PodcastChannelPtr of the correct type which
we will use from now on.
-                        */
-                        m_channel = m_podcastProvider->addChannel( m_channel );
-
-                        m_current =
static_cast<Meta::PodcastMetaCommon *>( m_channel.data() );
-                    }
-                }
-                m_currentTag = QXmlStreamReader::name().toString();
-            }
-            else if( isEndElement() )
-            {
-                if (QXmlStreamReader::name() == "item")
-                {
-                    commitEpisode();
-                }
-                else if( QXmlStreamReader::name() == "channel" )
-                {
-                    commitChannel();
-                    emit finished( this );
-                    break;
-                }
-                else if( QXmlStreamReader::name() == "title")
-                {
-                    if( !m_parsingImage )
-                    {
-                        // Remove redundant whitespace from the title.
-                        m_current->setTitle( m_titleString.simplified() );
-                    }
-                    //TODO save image data
-                    m_titleString.clear();
-                }
-                else if( QXmlStreamReader::name() == "description" )
-                {
-                    m_current->setDescription( m_descriptionString );
-                    m_descriptionString.clear();
-                }
-                else if( QXmlStreamReader::name() == "guid" )
-                {
-                    static_cast<PodcastEpisode
*>(m_current)->setGuid( m_guidString );
-                    m_guidString.clear();
-                }
-                else if( QXmlStreamReader::name() == "enclosure" )
-                {
-                    static_cast<PodcastEpisode
*>(m_current)->setUidUrl( KUrl( m_urlString ) );
-                    m_urlString.clear();
-                }
-                else if( QXmlStreamReader::name() == "link" )
-                {
-                    if( !m_parsingImage )
-                        m_channel->setWebLink( KUrl( m_linkString ) );
-                    //TODO save image data
-                    m_linkString.clear();
-                }
-                else if( QXmlStreamReader::name() == "pubDate")
-                {
-                    PodcastEpisode * episode =
dynamic_cast<PodcastEpisode *>(m_current);
-                    if( episode )
-                        episode->setPubDate( parsePubDate( m_pubDateString ) );
-                    m_pubDateString.clear();
-                }
-                else if( QXmlStreamReader::name() == "image" )
-                {
-                    m_parsingImage = false;
-                }
-                else if( QXmlStreamReader::name() == "url" && m_parsingImage )
-                {
-                    if( m_channel )
-                        m_channel->setImageUrl( KUrl( m_urlString ) );
-                    m_urlString.clear();
-                }
-            }
-            else if( isCharacters() && !isWhitespace() )
-            {
-                if( m_currentTag == "title" )
-                    m_titleString += text().toString();
-                else if( m_currentTag == "link" )
-                    m_linkString += text().toString();
-                else if( m_currentTag == "description" )
-                    m_descriptionString += text().toString();
-                else if( m_currentTag == "pubDate" )
-                    m_pubDateString += text().toString();
-                else if( m_currentTag == "guid" )
-                    m_guidString += text().toString();
-                else if( m_currentTag == "url" )
-                    m_urlString += text().toString();
-            }
-        }
-    }
+QXmlStreamReader::TokenType
+PodcastReader::nextRawToken()
+{
+       TokenType token = NoToken;
+
+       for (int repeat = 0; repeat < 3; ++ repeat) {
+               token = readNext();

-    if ( error() )
-    {
-        if ( error() == QXmlStreamReader::PrematureEndOfDocumentError)
-        {
-            debug() << "waiting for data at line " << lineNumber();
-        }
-        else
-        {
-            debug() << "XML ERROR: " << error() << " at line: " << lineNumber()
-                    << ": " << columnNumber()
-                    << "\n\t" << errorString();
-            debug() << "\tname = " << QXmlStreamReader::name().toString()
-                    << " tokenType = " << tokenString();
-
-            if( m_channel )
-                commitChannel();
-            emit finished( this );
-        }
-    }
-    return result;
+               if ( error() != PrematureEndOfDocumentError )
+                       break;
+
+               debug() << "recovering from PrematureEndOfDocumentError for "
+                << qxml::name().toString() << " at "
+                << qxml::lineNumber();
+       }
+
+       if( error() ) {
+               throw XmlParseError( errorString() );
+       }
+
+       return token;
+}
+
+QXmlStreamReader::TokenType
+PodcastReader::nextToken()
+{
+       TokenType token = NoToken;
+
+       do {
+               token = nextRawToken();
+
+               switch ( token ) {
+               case Invalid:
+               case StartDocument:
+               case EndDocument:
+               case StartElement:
+               case EndElement:
+                       return token;
+
+               case Characters:
+                       if ( !isWhitespace() )
+                               return token;
+                       break;
+
+               case NoToken:
+               case Comment:
+               case DTD:
+               case EntityReference:
+               case ProcessingInstruction:
+                       // ignore
+                       break;
+               }
+       } while ( !atEnd() );
+
+       return token;
+}
+
+void
+PodcastReader::expect(TokenType expected, TokenType got) {
+       if ( got != expected )
+               throw ParseError( i18n( "expected token %1, but got
token %2", expected, got ) );
+}
+
+void
+PodcastReader::expect(TokenType expected) {
+       expect( expected, nextToken() );
+}
+
+void
+PodcastReader::expectName(const QString& name) {
+       if ( qxml::name() != name )
+               throw ParseError( i18n( "expected element name %1, but
got element name %2",
+                       name, qxml::name().toString() ) );
+}
+
+void
+PodcastReader::expectStart(const QString& name) {
+       expect(StartElement);
+       expectName(name);
+}
+
+void
+PodcastReader::expectEnd(const QString& name) {
+       expect(EndElement);
+       expectName(name);
+}
+
+QString
+PodcastReader::readTextContent() {
+       QString text = readElementText();
+
+       if ( error() )
+               throw ParseError( errorString() );
+
+       return text;
+}
+
+bool
+PodcastReader::read()
+{
+       DEBUG_BLOCK
+
+       try {
+               m_feedType = UnknownFeedType;
+
+               expect(StartDocument);
+               expect(StartElement);
+
+               QStringRef version = attributes().value( "version" );
+
+               debug() << "Initial StartElement: " << qxml::name().toString();
+               debug() << "version: " << version.toString();
+
+               if ( qxml::name() == "rss" && version == "2.0" ) {
+                       m_feedType = Rss20FeedType;
+               }
+               else if ( qxml::name() == "html" || qxml::name() == "HTML" ) {
+                       m_feedType = ErrorPageType;
+                       throw ParseError( i18n( "An HTML page was
received. Expected an RSS 2.0 feed" ) );
+               }
+               else {
+                       // TODO: change this string once we support more
+                       throw ParseError( i18n( "%1 is not an RSS
version 2.0 feed.", m_url.url() ) );
+               }
+
+               // rss 2.0 specifies exactly one channel element per feed
+               readChannel();
+
+               expect(EndElement);
+               expect(EndDocument);
+       }
+       catch (XmlParseError& e) {
+               debug() << "XML ERROR: " << error() << " at line: " <<
lineNumber()
+                       << ": " << columnNumber()
+                       << "\n\t" << errorString();
+               debug() << "\tname = " << qxml::name().toString()
+                       << " tokenType = " << tokenString();
+
+               if (m_transferJob) {
+                       m_transferJob->kill();
+                       m_transferJob = NULL;
+               }
+
+               emit finished( this );
+               return false;
+       }
+       catch (ParseError& e) {
+               debug() << "error parsing podcast feed: " << e.message();
+
+               raiseError( e.message() );
+
+               if (m_transferJob) {
+                       m_transferJob->kill();
+                       m_transferJob = NULL;
+               }
+
+               emit finished( this );
+               return false;
+       }
+
+       emit finished( this );
+       return true;
+}
+
+KUrl
+PodcastReader::readImage() {
+       expectName("image");
+
+       KUrl url;
+
+       for (TokenType token = nextToken(); token != EndElement; token
= nextToken()) {
+               // elements: url, title, link
+               expect( token, StartElement );
+
+               if ( qxml::name() == "url" ) {
+                       url = KUrl( readTextContent() );
+               }
+               else if ( qxml::name() == "link" || qxml::name() == "title" ) {
+                       // not supported but well known
+                       skipElement();
+               }
+               else {
+                       debug() << "skipping unsupported image
element: " << qxml::name().toString();
+                       skipElement();
+               }
+       }
+       expectName("image");
+
+       return url;
+}
+
+void
+PodcastReader::readChannel() {
+       DEBUG_BLOCK
+
+       expectStart("channel");
+
+       DescriptionType hasDescription = NoDescription;
+       m_channel = new Meta::PodcastChannel();
+       m_channel->setUrl( m_url );
+    m_channel->setSubscribeDate( QDate::currentDate() );
+    /* add this new channel to the provider, we get a pointer to a
+     * PodcastChannelPtr of the correct type which we will use from now on.
+     */
+    m_channel = m_podcastProvider->addChannel( m_channel );
+
+       for (TokenType token = nextToken(); token != EndElement; token
= nextToken()) {
+               // required elements: title, link, description
+               // optional elements: language, copyright, pubDate,
category, image, ...
+
+               expect( token, StartElement );
+
+               if ( qxml::name() == "title" ) {
+                       // Remove redundant whitespace from the title.
+                       m_channel->setTitle( readTextContent().simplified() );
+               }
+               else if ( qxml::name() == "description" ) {
+                       if ( hasDescription <= RssDescription ) {
+                               m_channel->setDescription( readTextContent() );
+                               hasDescription = RssDescription;
+                       }
+               }
+               else if ( qxml::name() == "summary" && namespaceUri()
== "http://www.itunes.com/dtds/podcast-1.0.dtd" ) {
+                       if ( hasDescription <= ItunesSummary ) {
+                               m_channel->setDescription( readTextContent() );
+                               hasDescription = ItunesSummary;
+                       }
+               }
+               else if ( qxml::name() == "body" ) {
+                       if ( hasDescription <= HtmlBody ) {
+                               m_channel->setDescription( readInnerXml() );
+                               hasDescription = HtmlBody;
+                       }
+               }
+               else if ( qxml::name() == "link" ) {
+                       m_channel->setWebLink( KUrl( readTextContent() ) );
+               }
+               else if ( qxml::name() == "image" ) {
+                       // TODO save image data
+                       m_channel->setImageUrl( readImage() );
+               }
+               else if ( qxml::name() == "item" ) {
+                       Meta::PodcastEpisodePtr item = readItem();
+
+                       if (
!m_podcastProvider->possiblyContainsTrack( item->uidUrl() ) ) {
+                               Meta::PodcastEpisodePtr episode =
m_channel->addEpisode( item );
+                               // also let the provider know an
episode has been added
+                               // TODO: change into a signal
+                               m_podcastProvider->addEpisode( episode );
+                       }
+               }
+               else {
+                       debug() << "skipping unsupported channel
element: " << qxml::name().toString();
+                       skipElement();
+               }
+       }
+
+       expectName("channel");
+}
+
+Meta::PodcastEpisodePtr
+PodcastReader::readItem() {
+       DEBUG_BLOCK
+
+       expectName("item");
+
+       Meta::PodcastEpisodePtr item( new Meta::PodcastEpisode( m_channel ) );
+       DescriptionType hasDescription = NoDescription;
+
+       for (TokenType token = nextToken(); token != EndElement; token
= nextToken()) {
+               // elements: title, link, description, author, category,
+               //           comments, enclosure, guid, pubDate, source
+               // extension elements: body, itunes:summary
+
+               if ( qxml::name() == "title" ) {
+                       item->setTitle( readTextContent().simplified() );
+               }
+               else if ( qxml::name() == "description" ) {
+                       if ( hasDescription <= RssDescription ) {
+                               item->setDescription( readTextContent() );
+                               hasDescription = RssDescription;
+                       }
+               }
+               else if ( qxml::name() == "summary" && namespaceUri()
== "http://www.itunes.com/dtds/podcast-1.0.dtd" ) {
+                       if ( hasDescription <= ItunesSummary ) {
+                               item->setDescription( readTextContent() );
+                               hasDescription = ItunesSummary;
+                       }
+               }
+               else if ( qxml::name() == "body" ) {
+                       if ( hasDescription <= HtmlBody ) {
+                               item->setDescription( readInnerXml() );
+                               hasDescription = HtmlBody;
+                       }
+               }
+               else if ( qxml::name() == "enclosure" ) {
+                       item->setUidUrl( KUrl( attributes().value(
"url" ).toString() ) );
+                       skipElement();
+               }
+               else if ( qxml::name() == "guid" ) {
+                       item->setGuid( readTextContent() );
+               }
+               else if ( qxml::name() == "pubDate" ) {
+                       item->setPubDate( parsePubDate( readTextContent() ) );
+               }
+               else {
+                       debug() << "skipping unsupported item element:
" << qxml::name().toString();
+                       skipElement();
+               }
+       }
+
+       expectName("item");
+
+       return item;
 }

 QDateTime
@@ -365,23 +524,20 @@ PodcastReader::parsePubDate( const QString &dateString )
 }

 void
-PodcastReader::readUnknownElement()
+PodcastReader::skipElement()
 {
    DEBUG_BLOCK
    Q_ASSERT ( isStartElement() );

-    debug() << "unknown element: " << QXmlStreamReader::name().toString();
-
-    while ( !atEnd() )
-    {
-        readNext();
-
-        if ( isEndElement() )
-            break;
+       int level = 1;

-        if ( isStartElement() )
-            readUnknownElement();
-    }
+       while (level > 0) {
+               switch ( nextToken() ) {
+               case StartElement: ++ level; break;
+               case EndElement:   -- level; break;
+               default: break;
+               }
+       }
 }

 void
@@ -407,43 +563,6 @@ PodcastReader::slotPermanentRedirection( KIO::Job
* job, const KUrl & fromUrl,
        m_channel->setUrl( m_url );
 }

-void
-PodcastReader::commitChannel()
-{
-    Q_ASSERT( m_channel );
-    //TODO: we probably need to notify the provider here to we are
done updating the channel
-//     emit finished( this );
-}
-
-void
-PodcastReader::commitEpisode()
-{
-    DEBUG_BLOCK
-    Q_ASSERT( m_current );
-    PodcastEpisodePtr item = PodcastEpisodePtr(
static_cast<PodcastEpisode *>(m_current) );
-//
-//     PodcastEpisodePtr episodeMatch = podcastEpisodeCheck( item );
-//     if( episodeMatch == item )
-//     {
-//         debug() << "commit episode " << item->title();
-//
-//         Q_ASSERT( m_channel );
-//         //make a copy of the pointer and add that to the channel
-//         m_channel->addEpisode( PodcastEpisodePtr( item ) );
-//     }
-
-    if( !m_podcastProvider->possiblyContainsTrack( item->uidUrl() ) )
-    {
-        Meta::PodcastEpisodePtr episode = PodcastEpisodePtr( item );
-        episode = m_channel->addEpisode( episode );
-        //also let the provider know an episode has been added
-        //TODO: change into a signal
-        m_podcastProvider->addEpisode( episode );
-    }
-
-    m_current = static_cast<PodcastMetaCommon *>( m_channel.data() );
-}
-
 Meta::PodcastEpisodePtr
 PodcastReader::podcastEpisodeCheck( Meta::PodcastEpisodePtr episode )
 {
diff --git a/src/podcasts/PodcastReader.h b/src/podcasts/PodcastReader.h
index 7e58159..939048c 100644
--- a/src/podcasts/PodcastReader.h
+++ b/src/podcasts/PodcastReader.h
@@ -24,6 +24,7 @@
 #include <QXmlStreamReader>
 #include <QObject>

+
 namespace KIO
 {
    class Job;
@@ -63,26 +64,64 @@ class PodcastReader : public QObject, public
QXmlStreamReader
        void downloadResult( KJob * );

    private:
+               typedef QXmlStreamReader qxml;
+
+               /** internally used exception class */
+               class ParseError {
+               public:
+                       ParseError(const QString& message)
+                               : m_message(message) {}
+
+                       const QString& message() const { return m_message; }
+
+               private:
+                       QString m_message;
+               };
+
+               class XmlParseError : public ParseError {
+               public:
+                       XmlParseError(const QString& message)
+                               : ParseError(message) {}
+               };
+
+               /** This method wraps readNext() and tries to fix the
PrematureEndOfDocumentError. */
+               TokenType nextRawToken();
+
+               /** Like nextRawToken() but skips Comments, DTDs,
EntityReferences,
+                * ProcessingInstructions and ignorable whitespaces. */
+               TokenType nextToken();
+
+               static void expect(TokenType expected, TokenType got);
+
+               void expect(TokenType token);
+               void expectName(const QString& name);
+               void expectStart(const QString& name);
+               void expectEnd(const QString& name);
+
+               /** Read the inner xml of an element as a string. This
is used to read the
+                * contents of a &lt;body&gt; element, which contains
xhtml data. */
+               QString readInnerXml();
+
+               /** Read text content of an element. Raises error if
non text content (elements) is read. */
+               QString readTextContent();
+
+               void readChannel();
+               Meta::PodcastEpisodePtr readItem();
+               KUrl readImage();
+
+               /** There usually are 3 kinds of descriptions. Usually
a &lt;body&gt; element contains
+                * the most detailed description followed by
&lt;itunes:summary&gt; and the standard
+                * &lt;description&gt;. */
+               enum DescriptionType { NoDescription = 0,
RssDescription = 1, ItunesSummary = 2, HtmlBody = 3 };
        enum FeedType { UnknownFeedType, ErrorPageType, Rss20FeedType };

        FeedType m_feedType;
        KUrl m_url;
        PodcastProvider * m_podcastProvider;
        KIO::TransferJob *m_transferJob;
-        Meta::PodcastMetaCommon *m_current;
        Meta::PodcastChannelPtr m_channel;

-        QString m_currentTag;
-        QString m_titleString;
-        QString m_linkString;
-        QString m_descriptionString;
-        QString m_urlString;
-        QString m_guidString;
-        QString m_pubDateString;
-
-        bool m_parsingImage;
-
-        void readUnknownElement();
+        void skipElement();

        QDateTime parsePubDate( const QString &datestring );

@@ -92,9 +131,6 @@ class PodcastReader : public QObject, public QXmlStreamReader
        *   same pointer as the argument.
        */
        Meta::PodcastEpisodePtr podcastEpisodeCheck(
Meta::PodcastEpisodePtr episode );
-
-        void commitChannel();
-        void commitEpisode();
 };

 #endif
diff --git a/src/podcasts/sql/SqlPodcastMeta.cpp
b/src/podcasts/sql/SqlPodcastMeta.cpp
index d719ad1..bc25d1c 100644
--- a/src/podcasts/sql/SqlPodcastMeta.cpp
+++ b/src/podcasts/sql/SqlPodcastMeta.cpp
@@ -121,11 +121,11 @@ Meta::SqlPodcastEpisode::SqlPodcastEpisode(
const QStringList &result, Meta::Sql
    }
 }

+// XXX: why do PodcastMetaCommon and PodcastEpisode not have an
apropriate copy constructor?
 Meta::SqlPodcastEpisode::SqlPodcastEpisode( Meta::PodcastEpisodePtr episode )
    : Meta::PodcastEpisode()
    , m_dbId( 0 )
 {
-    m_url = KUrl( episode->uidUrl() );
    m_channel = SqlPodcastChannelPtr::dynamicCast( episode->channel() );

    if ( !m_channel && episode->channel()) {
@@ -133,10 +133,31 @@ Meta::SqlPodcastEpisode::SqlPodcastEpisode(
Meta::PodcastEpisodePtr episode )
        debug() <<  episode->channel()->title();
    }

-    m_localUrl = episode->localUrl();
+       // PodcastMetaCommon
    m_title = episode->title();
+       m_description = episode->description();
+       m_keywords = episode->keywords();
+       m_subtitle = episode->subtitle();
+       m_summary = episode->summary();
+       m_author = episode->author();
+
+       // PodcastEpisode
    m_guid = episode->guid();
+       m_url = KUrl( episode->uidUrl() );
+       m_localUrl = episode->localUrl();
+//     m_mimeType = episode->mimeType();
    m_pubDate = episode->pubDate();
+       m_duration = episode->duration();
+       m_fileSize = episode->filesize();
+       m_sequenceNumber = episode->sequenceNumber();
+       m_isNew = episode->isNew();
+
+       // I'm not sure about this:
+       m_albumPtr = episode->album();
+       m_artistPtr = episode->artist();
+       m_composerPtr = episode->composer();
+       m_genrePtr = episode->genre();
+       m_yearPtr = episode->year();

    //commit to the database
    updateInDb();


More information about the Amarok-devel mailing list