--- a/application/group/Podcast.mmp Wed Jul 07 23:27:49 2010 +0100
+++ b/application/group/Podcast.mmp Fri Jul 09 11:34:00 2010 +0100
@@ -106,5 +106,4 @@
LIBRARY ws32.lib
LIBRARY hlplch.lib
LIBRARY bitgdi.lib
-LIBRARY apmime.lib // TDataType
LIBRARY commonui.lib // CDocumentHandler
--- a/application/src/PodcastFeedView.cpp Wed Jul 07 23:27:49 2010 +0100
+++ b/application/src/PodcastFeedView.cpp Fri Jul 09 11:34:00 2010 +0100
@@ -230,6 +230,7 @@
void CPodcastFeedView::FeedDownloadStartedL(TFeedState /*aState*/, TUint aFeedUid)
{
+ DP("FeedDownloadStartedL");
// Update status text
iUpdatingRunning = ETrue;
UpdateFeedInfoStatusL(aFeedUid, ETrue);
@@ -239,6 +240,7 @@
void CPodcastFeedView::FeedDownloadFinishedL(TFeedState aState,TUint aFeedUid, TInt aError)
{
+ DP("FeedDownloadFinishedL");
switch(aError)
{
case KErrCouldNotConnect:
@@ -255,6 +257,7 @@
break;
}
UpdateFeedInfoStatusL(aFeedUid, EFalse);
+ UpdateToolbar();
}
void CPodcastFeedView::UpdateFeedInfoStatusL(TUint aFeedUid, TBool aIsUpdating)
--- a/engine/inc/FeedEngine.h Wed Jul 07 23:27:49 2010 +0100
+++ b/engine/inc/FeedEngine.h Fri Jul 09 11:34:00 2010 +0100
@@ -47,11 +47,13 @@
const TInt KMaxLineLength = 4096;
const TInt KMaxSearchString = 30;
-enum TClientState {
+enum TFeedEngineState {
EIdle,
- EUpdatingFeed,
- EUpdatingImage,
- ESearching
+ EDownloadingFeed,
+ EParsingFeed,
+ EDownloadingImage,
+ ESearching,
+ EParsingOpml
};
class CFeedEngine : public CBase, public MHttpClientObserver, public MFeedParserObserver
@@ -81,7 +83,7 @@
/**
* Returns the current internal state of the feed engine4
*/
- IMPORT_C TClientState ClientState();
+ IMPORT_C TFeedEngineState ClientState();
/**
* Returns the current updating client UID if clientstate is != ENotUpdateing
@@ -118,7 +120,6 @@
void UpdateNextFeedL();
void NotifyOpmlParsingCompleteL(TInt aError, TUint aNumFeedsAdded);
-
private:
void DBLoadFeedsL();
@@ -132,7 +133,7 @@
private:
CHttpClient* iFeedClient;
- TClientState iClientState;
+ TFeedEngineState iEngineState;
CFeedTimer iFeedTimer;
CPodcastModel& iPodcastModel;
@@ -152,8 +153,8 @@
RArray<MFeedEngineObserver*> iObservers;
// new feeds only add one show to download list when auto downloading
- TBool newFeed;
- TUint showsAdded;
+ TBool iNewFeed;
+ TUint iShowsAdded;
sqlite3& iDB;
--- a/engine/inc/FeedParser.h Wed Jul 07 23:27:49 2010 +0100
+++ b/engine/inc/FeedParser.h Fri Jul 09 11:34:00 2010 +0100
@@ -25,6 +25,7 @@
#include <xml/contenthandler.h> // for Xml::MContentHandler
#include <xml/documentparameters.h>
+
_LIT(KTagItem, "item");
_LIT(KTagTitle, "title");
_LIT(KTagImage, "image");
@@ -62,15 +63,21 @@
const int KBufferLength = 1024;
-class CFeedParser : public CBase, public Xml::MContentHandler
+class CFeedParser : public CActive, public Xml::MContentHandler
{
public:
+ static CFeedParser* NewL(MFeedParserObserver& aCallbacks, RFs& aFs);
+ static CFeedParser* NewLC(MFeedParserObserver& aCallbacks, RFs& aFs);
+ virtual ~CFeedParser();
+
+private:
CFeedParser(MFeedParserObserver& aCallbacks, RFs& aFs);
- virtual ~CFeedParser();
+ void ConstructL();
public:
void ParseFeedL(const TFileName &feedFileName, CFeedInfo *item, TUint aMaxItems);
-
+ void ParseFeedAoL(const TFileName &feedFileName, CFeedInfo *item, TUint aMaxItems);
+
public: // from MContentHandler
void OnStartDocumentL(const Xml::RDocumentParameters& aDocParam, TInt aErrorCode);
void OnEndDocumentL(TInt aErrorCode);
@@ -85,6 +92,12 @@
void OnError(TInt aErrorCode);
TAny* GetExtendedInterface(const TInt32 aUid);
CFeedInfo& ActiveFeed();
+
+private:
+ void DoCancel();
+ void RunL();
+ TInt RunError(TInt aError);
+
private:
MFeedParserObserver& iCallbacks;
TFeedState iFeedState;
@@ -98,7 +111,13 @@
TUint iItemsParsed;
TBool iStoppedParsing;
TEncoding iEncoding;
+
RFs& iRfs;
+ Xml::CParser* iParser;
+ HBufC8* iXmlBuffer;
+ RFile iFile;
+ TFileName iFileName;
+
};
#endif
--- a/engine/src/FeedEngine.cpp Wed Jul 07 23:27:49 2010 +0100
+++ b/engine/src/FeedEngine.cpp Fri Jul 09 11:34:00 2010 +0100
@@ -41,7 +41,7 @@
void CFeedEngine::ConstructL()
{
- iParser = new (ELeave) CFeedParser(*this, iPodcastModel.FsSession());
+ iParser = CFeedParser::NewLC(*this, iPodcastModel.FsSession());
iFeedClient = CHttpClient::NewL(iPodcastModel, *this);
iFeedTimer.ConstructL();
@@ -80,11 +80,12 @@
TRAP_IGNORE(ImportFeedsL(importFile));
}
+ CleanupStack::Pop(iParser);
RunFeedTimer();
}
CFeedEngine::CFeedEngine(CPodcastModel& aPodcastModel)
- : iClientState(EIdle),
+ : iEngineState(EIdle),
iFeedTimer(this),
iPodcastModel(aPodcastModel),
iDB(*aPodcastModel.DB())
@@ -107,9 +108,9 @@
/**
* Returns the current internal state of the feed engine4
*/
-EXPORT_C TClientState CFeedEngine::ClientState()
+EXPORT_C TFeedEngineState CFeedEngine::ClientState()
{
- return iClientState;
+ return iEngineState;
}
@@ -144,7 +145,7 @@
EXPORT_C void CFeedEngine::UpdateAllFeedsL(TBool aAutoUpdate)
{
- if (iClientState != EIdle)
+ if (iEngineState != EIdle)
{
User::Leave(KErrInUse);
}
@@ -169,7 +170,7 @@
EXPORT_C void CFeedEngine::CancelUpdateAllFeeds()
{
- if(iClientState != EIdle)
+ if(iEngineState != EIdle)
{
iCancelRequested = ETrue;
iFeedsUpdating.Reset();
@@ -181,7 +182,7 @@
{
DP1("UpdateNextFeed. %d feeds left to update", iFeedsUpdating.Count());
- if (iClientState != EIdle)
+ if (iEngineState != EIdle)
{
User::Leave(KErrInUse);
}
@@ -216,7 +217,7 @@
}
else
{
- iClientState = EIdle;
+ iEngineState = EIdle;
for (TInt i=0;i<iObservers.Count();i++)
{
TRAP_IGNORE(iObservers[i]->FeedUpdateAllCompleteL(iAutoUpdatedInitiator?MFeedEngineObserver::EFeedAutoUpdate:MFeedEngineObserver::EFeedManualUpdate));
@@ -239,10 +240,10 @@
if (iActiveFeed->LastUpdated() == 0)
{
- newFeed = ETrue;
+ iNewFeed = ETrue;
}
- showsAdded = 0;
+ iShowsAdded = 0;
iActiveFeed->SetLastError(KErrNone);
DBUpdateFeedL(*iActiveFeed);
@@ -254,7 +255,7 @@
_LIT(KFileNameFormat, "%lu.xml");
iUpdatingFeedFileName.AppendFormat(KFileNameFormat, aFeedUid);
- iClientState = EUpdatingFeed;
+ iEngineState = EDownloadingFeed;
for (TInt i=0;i<iObservers.Count();i++)
{
@@ -284,24 +285,24 @@
aItem.SetDescriptionL(*description);
CleanupStack::PopAndDestroy(description);
- if (newFeed) {
+ if (iNewFeed) {
// for new feeds, set all shows played
aItem.SetPlayState(EPlayed);
// except the first one
- if (showsAdded == 0) {
+ if (iShowsAdded == 0) {
aItem.SetPlayState(ENeverPlayed);
}
}
TRAPD(err, iPodcastModel.ShowEngine().AddShowL(aItem));
-
+
if (err == KErrNone && aItem.PlayState() == ENeverPlayed &&
iPodcastModel.SettingsEngine().DownloadAutomatically())
{
iPodcastModel.ShowEngine().AddDownloadL(aItem);
+ iShowsAdded++;
}
- showsAdded++;
}
void CFeedEngine::GetFeedImageL(CFeedInfo *aFeedInfo)
@@ -327,7 +328,7 @@
if(iFeedClient->GetL(aFeedInfo->ImageUrl(), filePath, ETrue))
{
- iClientState = EUpdatingImage;
+ iEngineState = EDownloadingImage;
}
}
@@ -527,6 +528,7 @@
TBuf<KMaxLineLength> title;
title.Copy(item->Title());
item->SetTitleL(title); // if this leaves we are out of memory
+ CompleteL(NULL, KErrNone);
}
@@ -555,26 +557,32 @@
void CFeedEngine::CompleteL(CHttpClient* /*aClient*/, TInt aError)
{
- DP2("CFeedEngine::CompleteL BEGIN, iClientState=%d, aSuccessful=%d", iClientState, aError);
+ DP2("CFeedEngine::CompleteL BEGIN, iEngineState=%d, aSuccessful=%d", iEngineState, aError);
- switch(iClientState)
+ switch(iEngineState)
{
- case EUpdatingFeed:
+ case EDownloadingFeed:
{
- iClientState = EIdle;
switch (aError)
{
case KErrCancel:
{
iFeedsUpdating.Reset();
+ iEngineState = EIdle;
}
break;
case KErrCouldNotConnect:
iFeedsUpdating.Reset();
+ iEngineState = EIdle;
break;
default:
{
- if (!iCancelRequested) {
+ if (iCancelRequested)
+ {
+ iEngineState = EIdle;
+ }
+ else
+ {
iActiveFeed->SetLastError(aError);
TTime time;
time.HomeTime();
@@ -585,60 +593,64 @@
// Parse the feed. We need to trap this call since it could leave and then
// the whole update chain will be broken
// change client state
- TRAPD(parserErr, iParser->ParseFeedL(iUpdatingFeedFileName, iActiveFeed, iPodcastModel.SettingsEngine().MaxListItems()));
+ TRAPD(parserErr, iParser->ParseFeedAoL(iUpdatingFeedFileName, iActiveFeed, iPodcastModel.SettingsEngine().MaxListItems()));
if(parserErr)
{
// we do not need to any special action on this error.
iActiveFeed->SetLastError(parserErr);
DP1("CFeedEngine::Complete()\t Failed to parse feed. Leave with error code=%d", parserErr);
+ iEngineState = EIdle;
}
-
- // delete the downloaded XML file as it is no longer needed
- BaflUtils::DeleteFile(iPodcastModel.FsSession(),iUpdatingFeedFileName);
-
- // if the feed has specified a image url. download it if we dont already have it
- if((iActiveFeed->ImageUrl().Length() > 0))
+ else
{
- if ( (iActiveFeed->ImageFileName().Length() == 0) ||
- (iActiveFeed->ImageFileName().Length() > 0 &&
- !BaflUtils::FileExists(iPodcastModel.FsSession(),
- iActiveFeed->ImageFileName()) )
- )
- {
- TRAPD(error, GetFeedImageL(iActiveFeed));
- if (error)
- {
- // we have failed in a very early stage to fetch the image.
- // continue with next Feed update
- iActiveFeed->SetLastError(parserErr);
- iClientState = EIdle;
- }
- }
+ iEngineState = EParsingFeed;
}
}
else
{
// even if it fails, this will allow us to move on
- iClientState = EIdle;
+ iEngineState = EIdle;
}
}
- iCancelRequested = EFalse;
}break;
}
- DBUpdateFeedL(*iActiveFeed);
NotifyFeedUpdateComplete(iActiveFeed->Uid(), aError);
-
- // we will wait until the image has been downloaded to start the next feed update.
- if (iClientState == EIdle)
+ }
+ break;
+ case EParsingFeed:
+ {
+ // if the feed has specified a image url. download it if we dont already have it
+ if((iActiveFeed->ImageUrl().Length() > 0))
{
- UpdateNextFeedL();
+ if ( (iActiveFeed->ImageFileName().Length() == 0) ||
+ (iActiveFeed->ImageFileName().Length() > 0 &&
+ !BaflUtils::FileExists(iPodcastModel.FsSession(),
+ iActiveFeed->ImageFileName()) )
+ )
+ {
+ TRAPD(error, GetFeedImageL(iActiveFeed));
+ if (error)
+ {
+ // we have failed in a very early stage to fetch the image.
+ // continue with next Feed update
+ iActiveFeed->SetLastError(error);
+ iEngineState = EIdle;
+ NotifyFeedUpdateComplete(iActiveFeed->Uid(), error);
+ }
+ }
+ else
+ {
+ iEngineState = EIdle;
+ NotifyFeedUpdateComplete(iActiveFeed->Uid(), aError);
+ }
}
- }break;
- case EUpdatingImage:
+ }
+ break;
+ case EDownloadingImage:
{
// change client state to not updating
- iClientState = EIdle;
+ iEngineState = EIdle;
if(aError == KErrNone)
{
// now the image has been downloaded, so we set it again in the FeedInfo to start
@@ -647,13 +659,11 @@
TRAP_IGNORE(iActiveFeed->SetImageFileNameL(*fileNameCopy, &iPodcastModel));
CleanupStack::PopAndDestroy(fileNameCopy);
}
- DBUpdateFeedL(*iActiveFeed);
NotifyFeedUpdateComplete(iActiveFeed->Uid(), aError);
- UpdateNextFeedL();
}break;
case ESearching:
{
- iClientState = EIdle;
+ iEngineState = EIdle;
DP2("Search complete, results in %S with error %d", &iSearchResultsFileName, aError);
if(aError == KErrNone)
@@ -685,7 +695,16 @@
void CFeedEngine::NotifyFeedUpdateComplete(TInt aFeedUid, TInt aError)
{
- DP("CFeedEngine::NotifyFeedUpdateComplete");
+ DP("CFeedEngine::NotifyFeedUpdateComplete");
+
+ DBUpdateFeedL(*iActiveFeed);
+
+ // we will wait until the image has been downloaded to start the next feed update.
+ if (iEngineState == EIdle)
+ {
+ UpdateNextFeedL();
+ }
+
for (TInt i=0;i<iObservers.Count();i++)
{
TRAP_IGNORE(iObservers[i]->FeedDownloadFinishedL(MFeedEngineObserver::EFeedAutoUpdate, aFeedUid, aError));
@@ -1084,7 +1103,7 @@
{
DP1("FeedEngine::SearchForFeedL BEGIN, aSearchString=%S", &aSearchString);
- if (iClientState != EIdle) {
+ if (iEngineState != EIdle) {
User::Leave(KErrInUse);
}
TBuf<KMaxURLLength> ssBuf;
@@ -1107,11 +1126,11 @@
// run search
if(iFeedClient->GetL(*url, iSearchResultsFileName, iPodcastModel.SettingsEngine().SpecificIAP()))
{
- iClientState = ESearching;
+ iEngineState = ESearching;
}
else
{
- iClientState = EIdle;
+ iEngineState = EIdle;
User::Leave(KErrAbort);
}
--- a/engine/src/FeedParser.cpp Wed Jul 07 23:27:49 2010 +0100
+++ b/engine/src/FeedParser.cpp Fri Jul 09 11:34:00 2010 +0100
@@ -28,24 +28,73 @@
#include "podcastutils.h"
using namespace Xml;
+
const TInt KMaxParseBuffer = 1024;
const TInt KMaxStringBuffer = 100;
+const TInt KFileBufferSize = 1024; // buffer size for file reading
+_LIT8( KXmlMimeType, "text/xml" );
-CFeedParser::CFeedParser(MFeedParserObserver& aCallbacks, RFs& aFs) : iCallbacks(aCallbacks), iRfs(aFs)
+CFeedParser* CFeedParser::NewL(MFeedParserObserver& aCallbacks, RFs& aFs)
+ {
+ CFeedParser* self = CFeedParser::NewLC(aCallbacks, aFs);
+ CleanupStack::Pop();
+ return self;
+ }
+
+CFeedParser* CFeedParser::NewLC(MFeedParserObserver& aCallbacks, RFs& aFs)
+ {
+ CFeedParser* self = new ( ELeave ) CFeedParser(aCallbacks, aFs);
+ CleanupStack::PushL( self);
+ self->ConstructL();
+ return self;
+ }
+
+CFeedParser::CFeedParser(MFeedParserObserver& aCallbacks, RFs& aFs) : CActive(EPriorityLow),
+ iCallbacks(aCallbacks), iRfs(aFs)
{
+ CActiveScheduler::Add( this);
}
CFeedParser::~CFeedParser()
{
}
+void CFeedParser::ParseFeedAoL(const TFileName &feedFileName, CFeedInfo *item, TUint aMaxItems)
+ {
+ DP("CFeedParser::ParseFeedAoL BEGIN");
+ // Remember to cancel any outstanding request first.
+ if ( IsActive())
+ {
+ Cancel();
+ }
+
+ iActiveFeed = item;
+ iFeedState = EStateRoot;
+ iActiveShow = NULL;
+ iItemsParsed = 0;
+ iMaxItems = aMaxItems;
+ iStoppedParsing = EFalse;
+ iEncoding = ELatin1;
+ iFileName.Copy(feedFileName);
+
+ User::LeaveIfError( iFile.Open( iRfs, feedFileName, EFileRead));
+
+ delete iXmlBuffer;
+ iXmlBuffer = 0;
+ iXmlBuffer = HBufC8::NewL( KFileBufferSize);
+ TPtr8 bufferPtr( iXmlBuffer->Des());
+ iFile.Read( bufferPtr, KFileBufferSize, iStatus);
+ SetActive();
+
+ iParser->ParseBeginL();
+ DP("CFeedParser::ParseFeedAoL END");
+ }
+
+
void CFeedParser::ParseFeedL(const TFileName &feedFileName, CFeedInfo *info, TUint aMaxItems)
{
- //DP1("ParseFeedL BEGIN: %S", &feedFileName);
-
- _LIT8(KXmlMimeType, "text/xml");
- // Contruct the parser object
- CParser* parser = CParser::NewLC(KXmlMimeType, *this);
+ DP1("ParseFeedL BEGIN: %S", &feedFileName);
+
iActiveFeed = info;
iFeedState = EStateRoot;
iActiveShow = NULL;
@@ -53,12 +102,14 @@
iMaxItems = aMaxItems;
iStoppedParsing = EFalse;
iEncoding = ELatin1;
+ iFileName.Copy(feedFileName);
+ CParser* parser = CParser::NewLC(KXmlMimeType, *this);
ParseL(*parser, iRfs, feedFileName);
CleanupStack::PopAndDestroy(parser);
- //DP("ParseFeedL END");
+ DP("ParseFeedL END");
}
// from MContentHandler
@@ -81,7 +132,7 @@
void CFeedParser::OnEndDocumentL(TInt /*aErrorCode*/)
{
- //DP("OnEndDocumentL()");
+ DP("OnEndDocumentL()");
iCallbacks.ParsingCompleteL(iActiveFeed);
}
@@ -94,7 +145,7 @@
TBuf<KMaxStringBuffer> str;
str.Copy(aElement.LocalName().DesC());
- //DP2("OnStartElementL START state=%d, element=%S", iFeedState, &str);
+ DP2("OnStartElementL START state=%d, element=%S", iFeedState, &str);
iBuffer.Zero();
switch (iFeedState) {
case EStateRoot:
@@ -219,7 +270,7 @@
TBuf<KMaxStringBuffer> str;
str.Copy(aElement.LocalName().DesC());
- //DP2("OnEndElementL START state=%d, element=%S", iFeedState, &str);
+ DP2("OnEndElementL START state=%d, element=%S", iFeedState, &str);
switch (iFeedState) {
case EStateChannelTitle:
@@ -449,3 +500,52 @@
{
return *iActiveFeed;
}
+
+void CFeedParser::ConstructL()
+ {
+ iParser = CParser::NewL( KXmlMimeType, *this);
+ }
+
+void CFeedParser::DoCancel()
+ {
+
+ }
+
+void CFeedParser::RunL()
+ {
+ if ( KErrNone == iStatus.Int())
+ {
+ if ( iXmlBuffer->Length()== 0) // end of the file.
+ {
+ iParser->ParseEndL();
+ iFile.Close();
+ BaflUtils::DeleteFile(iRfs,iFileName);
+
+ delete iXmlBuffer;
+ iXmlBuffer = 0;
+ }
+ else
+ {// Otherwise, we continue reading the next chunk of the XML file.
+ // Parse the next "part" of the XML document.
+ iParser->ParseL( *iXmlBuffer);
+
+ // Read the next chunk of the file.
+ TPtr8 bufferPtr( iXmlBuffer->Des());
+ iFile.Read( bufferPtr, KFileBufferSize, iStatus);
+
+ // Don't forget to call this... :)
+ SetActive();
+ }
+ }
+ else
+ {
+ // Do something if error happens.
+ }
+ }
+
+TInt CFeedParser::RunError(TInt aError)
+ {
+
+ }
+
+