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 <body> 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 <body> element contains
+ * the most detailed description followed by
<itunes:summary> and the standard
+ * <description>. */
+ 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