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

Bart Cerneels bart.cerneels at kde.org
Wed Nov 18 12:06:41 CET 2009


PodcastReader creates channels and episode objects from the base class
and then passes this to PodcastProvider::add[Episode|Channel]. It
creates objects from it's own type using the copy constructor and then
returns a pointer to this new object.

They will probably also be used for synchronization between channels.

There are other ways to do this but a copy constructor is certainly
the cleanest.

Bart

On Wed, Nov 18, 2009 at 11:49, Maximilian Kossick
<maximilian.kossick at googlemail.com> wrote:
> 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();
> _______________________________________________
> Amarok-devel mailing list
> Amarok-devel at kde.org
> https://mail.kde.org/mailman/listinfo/amarok-devel
>


More information about the Amarok-devel mailing list