application/src/PodcastFeedView.cpp
changeset 2 29cda98b007e
child 5 ba42cd6670b8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/application/src/PodcastFeedView.cpp	Thu Feb 25 14:29:19 2010 +0000
@@ -0,0 +1,918 @@
+/*
+* Copyright (c) 2007-2010 Sebastian Brannstrom, Lars Persson, EmbedDev AB
+*
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* EmbedDev AB - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include "PodcastFeedView.h"
+#include "PodcastAppUi.h"
+#include "ShowEngine.h"
+#include "SettingsEngine.h"
+#include "PodcastApp.h"
+#include "PodcastUtils.h"
+#include "PodcastFeedViewUpdater.h"
+#include "Podcast.hrh"
+#include <caknfileselectiondialog.h> 
+#include <podcast.rsg>
+#include <podcast.mbg>
+#include <gulicon.h>
+#include <aknquerydialog.h>
+#include <caknmemoryselectiondialog.h> 
+#include <caknfilenamepromptdialog.h> 
+#include <BAUTILS.H> 
+#include <pathinfo.h> 
+
+const TInt KMaxFeedNameLength = 100;
+const TInt KMaxUnplayedFeedsLength =64;
+const TInt KADayInHours = 24;
+const TInt KDefaultGran = 5;
+const TInt KNumberOfFilesMaxLength = 4;
+#define KMaxMessageLength 200
+#define KMaxTitleLength 100
+const TInt KMimeBufLength = 100;
+
+_LIT(KFeedFormat, "%d\t%S\t%S%S");
+enum 
+{
+ EFeedIcon
+};
+
+CPodcastFeedView* CPodcastFeedView::NewL(CPodcastModel& aPodcastModel)
+    {
+    CPodcastFeedView* self = CPodcastFeedView::NewLC(aPodcastModel);
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+CPodcastFeedView* CPodcastFeedView::NewLC(CPodcastModel& aPodcastModel)
+    {
+    CPodcastFeedView* self = new ( ELeave ) CPodcastFeedView(aPodcastModel);
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+CPodcastFeedView::CPodcastFeedView(CPodcastModel& aPodcastModel):iPodcastModel(aPodcastModel)
+	{
+	iFirstActivateAfterLaunch = ETrue;
+	}
+#define KAsterisk iEikonEnv->EikAppUi()->Application()->BitmapStoreName()
+void CPodcastFeedView::ConstructL()
+	{
+	DP("CPodcastFeedView::ConstructL BEGIN");
+	//_LIT(KAsterisk, "*");
+	BaseConstructL(R_PODCAST_FEEDVIEW);
+	iNeverUpdated = iEikonEnv->AllocReadResourceL(R_PODCAST_FEEDS_NEVER_UPDATED);
+	iFeedsFormat = iEikonEnv->AllocReadResourceL(R_PODCAST_FEEDS_STATUS_FORMAT);
+	CPodcastListView::ConstructL();
+	iPodcastModel.FeedEngine().AddObserver(this);
+	CArrayPtr< CGulIcon >* icons = new(ELeave) CArrayPtrFlat< CGulIcon >(1);
+	CleanupStack::PushL( icons );
+	
+	CFbsBitmap* bitmap = NULL;
+	CFbsBitmap* mask = NULL;
+	// Load the bitmap for empty icon	
+	TFileName fname = KAsterisk;
+	TParsePtr parser(fname);
+
+	SetEmptyTextL(R_PODCAST_NO_FEEDS);
+	
+	// Load svg.-image and mask with a single call
+		AknIconUtils::CreateIconL(bitmap,
+		                          mask,
+		                          iEikonEnv->EikAppUi()->Application()->BitmapStoreName(),
+		                          EMbmPodcastFeed,
+		                          EMbmPodcastFeed_mask);
+	    
+	/*bitmap = iEikonEnv->CreateBitmapL(KAsterisk,EMbmPodcastFeed_40x40);
+	 * */
+	CleanupStack::PushL( bitmap );		
+	// Load the mask for feed icon	
+	//mask = iEikonEnv->CreateBitmapL(KAsterisk,EMbmPodcastFeed_40x40m );	
+	CleanupStack::PushL( mask );
+	// Append the feed icon to icon array
+	icons->AppendL( CGulIcon::NewL( bitmap, mask ) );
+	CleanupStack::Pop(2); // bitmap, mask
+	
+	iListContainer->Listbox()->ItemDrawer()->FormattedCellData()->SetIconArrayL( icons );
+	CleanupStack::Pop(icons); // icons
+
+	iListContainer->Listbox()->SetListBoxObserver(this);
+	
+    iStylusPopupMenu = CAknStylusPopUpMenu::NewL( this , TPoint(0,0));
+    TResourceReader reader;
+    iCoeEnv->CreateResourceReaderLC(reader,R_FEEDVIEW_POPUP_MENU);
+    iStylusPopupMenu->ConstructFromResourceL(reader);
+    CleanupStack::PopAndDestroy();
+    
+    iUpdater = CPodcastFeedViewUpdater::NewL(*this);
+	DP("CPodcastFeedView::ConstructL END");
+	}
+    
+CPodcastFeedView::~CPodcastFeedView()
+    {
+	iPodcastModel.FeedEngine().RemoveObserver(this);
+	delete iFeedsFormat;
+	delete iNeverUpdated;
+	delete iStylusPopupMenu;
+	delete iUpdater;
+    }
+
+void CPodcastFeedView::UpdateItemL(TInt aIndex)
+	{
+	_LIT(KPanicCategory, "CPodcastFeedView::UpdateItemL");
+	__ASSERT_DEBUG(iListContainer->IsVisible(), User::Panic(KPanicCategory, 0));
+	__ASSERT_ALWAYS(iItemIdArray.Count() > aIndex, User::Panic(KPanicCategory, 1));
+
+	const RFeedInfoArray& sortedItems = iPodcastModel.FeedEngine().GetSortedFeeds();
+	__ASSERT_ALWAYS(sortedItems.Count() > aIndex, User::Panic(KPanicCategory, 2));
+
+	// Update UID of for the feed at aIndex
+	iItemIdArray[aIndex] = sortedItems[aIndex]->Uid();
+	
+	// Prepare data to update the listbox item with
+	FormatFeedInfoListBoxItemL(*sortedItems[aIndex], EFalse);
+	
+	// If nothing has changed, we are done here
+	if (iListboxFormatbuffer == iItemArray->MdcaPoint(aIndex))
+		{
+		return;
+		}
+
+	// Something has changed, update the listbox item
+	TListItemProperties itemProps;			
+	itemProps.SetDimmed(EFalse);	
+	iItemArray->Delete(aIndex);	
+	iItemArray->InsertL(aIndex, iListboxFormatbuffer);
+	iListContainer->Listbox()->ItemDrawer()->SetPropertiesL(aIndex, itemProps);
+	// If item is visible, redraw it
+	if (iListContainer->Listbox()->TopItemIndex() <= aIndex
+			&& iListContainer->Listbox()->BottomItemIndex() >= aIndex)
+		{
+		iListContainer->Listbox()->DrawItem(aIndex);
+		}
+	}
+
+TUid CPodcastFeedView::Id() const
+	{
+	return KUidPodcastFeedViewID;
+	}
+		
+void CPodcastFeedView::DoActivateL(const TVwsViewId& aPrevViewId,
+	                                  TUid aCustomMessageId,
+	                                  const TDesC8& aCustomMessage)
+	{
+	UpdateToolbar();
+	
+	CPodcastListView::DoActivateL(aPrevViewId, aCustomMessageId, aCustomMessage);
+	
+	if (iFirstActivateAfterLaunch)
+		{
+		iFirstActivateAfterLaunch = EFalse;
+		}
+	}
+
+void CPodcastFeedView::DoDeactivate()
+	{
+	iUpdater->StopUpdate();
+	CPodcastListView::DoDeactivate();
+	}
+
+
+void CPodcastFeedView::HandleListBoxEventL(CEikListBox* /* aListBox */, TListBoxEvent aEventType)
+	{
+	DP("CPodcastFeedView::HandleListBoxEventL BEGIN");
+
+	switch(aEventType)
+		{
+	case EEventEnterKeyPressed:
+	case EEventItemDoubleClicked:
+	case EEventItemActioned:
+			{
+			const RFeedInfoArray* sortedItems = NULL;
+			TInt index = iListContainer->Listbox()->CurrentItemIndex();
+			sortedItems = &iPodcastModel.FeedEngine().GetSortedFeeds();
+
+			if(index >= 0 && index < sortedItems->Count())
+				{
+				iPodcastModel.ActiveShowList().Reset();
+				iPodcastModel.SetActiveFeedInfo((*sortedItems)[index]);			
+
+				AppUi()->ActivateLocalViewL(KUidPodcastShowsViewID,  TUid::Uid(0), KNullDesC8());
+				}
+			}
+		break;
+	default:
+		break;
+		}
+	DP("CPodcastFeedView::HandleListBoxEventL END");
+	}
+
+void CPodcastFeedView::FeedUpdateAllCompleteL(TFeedState /*aState*/)
+	{
+	iUpdatingAllRunning = EFalse;
+	UpdateToolbar();
+	}
+
+void CPodcastFeedView::FeedDownloadStartedL(TFeedState /*aState*/, TUint aFeedUid)
+	{
+	// Update status text
+	UpdateFeedInfoStatusL(aFeedUid, ETrue);
+	
+	UpdateToolbar();
+	}
+
+void CPodcastFeedView::FeedDownloadFinishedL(TFeedState aState,TUint aFeedUid, TInt aError)
+	{
+	switch(aError)
+		{
+		case KErrCouldNotConnect:
+			{
+			if(aState == MFeedEngineObserver::EFeedManualUpdate)
+				{
+				TBuf<KMaxMessageLength> message;
+				iEikonEnv->ReadResourceL(message, R_PODCAST_CONNECTION_ERROR);
+				ShowErrorMessage(message);
+				}
+			}
+			break;
+		default: // Do nothing
+			break;
+		}
+	UpdateFeedInfoStatusL(aFeedUid, EFalse);
+	}
+
+void CPodcastFeedView::UpdateFeedInfoStatusL(TUint aFeedUid, TBool aIsUpdating)
+	{
+	const RFeedInfoArray& feeds = iPodcastModel.FeedEngine().GetSortedFeeds();
+
+	// Find the index for the feed i both the feed-array and the listbox 
+	TInt feedsIdx = KErrNotFound;
+	TInt listboxIdx = KErrNotFound;
+	for (TInt i = 0; i < feeds.Count(); i++)
+		{
+		if (feeds[i]->Uid() == aFeedUid)
+			{
+			feedsIdx = i;
+			break;
+			}
+		}
+	for (TInt j = 0; j < iItemIdArray.Count(); j++)
+		{
+		if (iItemIdArray[j] == aFeedUid)
+			{
+			listboxIdx = j;
+			break;
+			}
+		}
+		
+	if (feedsIdx != KErrNotFound && listboxIdx != KErrNotFound)
+		{
+		// TODO In the long run we want to move the sorting resposibility from
+		// CFeedEngine to CPodcastFeedView.
+		// Hackish fix to make sure the listbox is sorted.
+		if (listboxIdx != feedsIdx)
+			{
+			iItemIdArray.Remove(listboxIdx);
+			iItemIdArray.InsertL(aFeedUid, feedsIdx);
+			iItemArray->Delete(listboxIdx);
+			iItemArray->InsertL(feedsIdx, KNullDesC);
+			iListContainer->Listbox()->HandleItemAdditionL();
+			}
+		// Update the listbox info
+		UpdateFeedInfoDataL(feeds[feedsIdx], feedsIdx, aIsUpdating);
+		//TODO sort the listbox after update
+		}
+		// Update all visible listbox items that are affected by sorting and update.
+		TInt minIdx = Max(Min(feedsIdx, listboxIdx), iListContainer->Listbox()->TopItemIndex());
+		TInt maxIdx = Min(Max(feedsIdx, listboxIdx), iListContainer->Listbox()->BottomItemIndex());
+		for (TInt k = minIdx; k <= maxIdx; k++)
+			{
+			iListContainer->Listbox()->DrawItem(k);
+			}
+	}
+
+void CPodcastFeedView::FormatFeedInfoListBoxItemL(CFeedInfo& aFeedInfo, TBool aIsUpdating)
+	{
+	TBuf<KMaxShortDateFormatSpec*2> updatedDate;
+	TBuf<KMaxUnplayedFeedsLength> unplayedShows;
+	TUint unplayedCount = 0;
+	TUint showCount = 0;
+	TInt iconIndex = EFeedIcon;
+	
+	if(aIsUpdating)
+		{
+		iEikonEnv->ReadResourceL(updatedDate, R_PODCAST_FEEDS_IS_UPDATING);
+		unplayedShows = KNullDesC();			
+		}
+	else
+		{
+		iPodcastModel.FeedEngine().GetStatsByFeed(aFeedInfo.Uid(), showCount, unplayedCount);	
+		
+		if (unplayedCount) {
+			unplayedShows.Format(*iFeedsFormat, unplayedCount);
+		} else {
+			unplayedShows.Zero();
+		}
+		
+		if (aFeedInfo.LastUpdated().Int64() == 0) 
+			{
+			updatedDate.Copy(*iNeverUpdated);					
+			unplayedShows.Zero();
+			}
+		else 
+			{
+			TTime now;
+			TTimeIntervalHours interval;
+			now.HomeTime();
+			now.HoursFrom(aFeedInfo.LastUpdated(), interval);
+			if (interval.Int() < KADayInHours) 
+				{
+				aFeedInfo.LastUpdated().FormatL(updatedDate, KTimeFormat());
+				}
+			else 
+				{
+				aFeedInfo.LastUpdated().FormatL(updatedDate, KDateFormatShort());
+				}
+			}
+		}
+	CArrayPtr<CGulIcon>* icons = iListContainer->Listbox()->ItemDrawer()->FormattedCellData()->IconArray();
+	
+	if (aFeedInfo.FeedIconIndex() != -1) {
+		iconIndex = aFeedInfo.FeedIconIndex();
+	} else {
+		if(aFeedInfo.FeedIcon() != NULL && 
+				aFeedInfo.FeedIcon()->SizeInPixels().iHeight > 0 &&
+				aFeedInfo.FeedIcon()->SizeInPixels().iWidth > 0)
+			{
+			// Hopefully temporary haxx to prevent double delete. I would prefer if
+			// this could be solved with a little better design.
+			CFbsBitmap* bmpCopy = new (ELeave) CFbsBitmap;
+			CleanupStack::PushL(bmpCopy);
+			bmpCopy->Duplicate(aFeedInfo.FeedIcon()->Handle());
+			icons->AppendL( CGulIcon::NewL(bmpCopy, NULL));
+			CleanupStack::Pop(bmpCopy);
+			iconIndex = icons->Count()-1;
+			aFeedInfo.SetFeedIconIndex(iconIndex);
+			}
+		else {
+			if(BaflUtils::FileExists(iPodcastModel.FsSession(), aFeedInfo.ImageFileName()))
+			{
+			// If this fails, no reason to worry
+			TRAP_IGNORE(iPodcastModel.ImageHandler().LoadFileAndScaleL(aFeedInfo.FeedIcon(), aFeedInfo.ImageFileName(), TSize(64,56), *this));
+			}
+		}
+	}
+	
+	if (unplayedShows.Length() > 0) {
+		unplayedShows.Insert(0,_L(", "));
+	}
+	
+	iListboxFormatbuffer.Format(KFeedFormat(), iconIndex, &(aFeedInfo.Title()), &updatedDate,  &unplayedShows);
+	}
+
+void CPodcastFeedView::ImageOperationCompleteL(TInt aError)
+	{
+	if (aError == KErrNone) {
+		UpdateListboxItemsL();
+	}
+	}
+
+void CPodcastFeedView::UpdateFeedInfoDataL(CFeedInfo* aFeedInfo, TInt aIndex, TBool aIsUpdating )
+	{			
+	TListItemProperties itemProps;			
+	itemProps.SetDimmed(aIsUpdating);	
+	FormatFeedInfoListBoxItemL(*aFeedInfo, aIsUpdating);
+	
+	TPtrC compareTo((*iItemArray)[aIndex]);
+	
+	if (iListboxFormatbuffer.Compare(compareTo) != 0) {
+		iItemArray->Delete(aIndex);
+		if(aIndex>= iItemArray->MdcaCount())
+				{
+				iItemArray->AppendL(iListboxFormatbuffer);
+				}
+			else
+				{
+				iItemArray->InsertL(aIndex, iListboxFormatbuffer);
+				}
+	}
+	iListContainer->Listbox()->ItemDrawer()->SetPropertiesL(aIndex, itemProps);
+	}
+
+
+void CPodcastFeedView::UpdateListboxItemsL()
+	{
+	// No reason to do any work if it isn't going to show..
+	if(!iListContainer->IsVisible())
+		{
+		return;
+		}
+	
+	TInt nbrItems = iPodcastModel.FeedEngine().GetSortedFeeds().Count();
+	if (nbrItems > 0)
+		{
+		// Ensure that there are as many elements in iItemIdArray as in FeedEngine
+		while (iItemIdArray.Count() < nbrItems)
+			{
+			iItemIdArray.AppendL(0);
+			}
+		while (iItemIdArray.Count() > nbrItems)
+			{
+			iItemIdArray.Remove(iItemIdArray.Count() - 1);
+			}
+		
+		// Ensure that there are as many elements in iItemArray as in FeedEngine
+		while (iItemArray->Count() < nbrItems)
+			{
+			iItemArray->AppendL(KNullDesC);
+			TListItemProperties itemProps;
+			iListContainer->Listbox()->ItemDrawer()->SetPropertiesL(iItemArray->Count() - 1, itemProps);
+			}
+		while (iItemArray->Count() > nbrItems)
+			{
+			iItemArray->Delete(iItemArray->Count() - 1);
+			}
+		iUpdater->StartUpdate(nbrItems);
+		}
+	else
+		{
+		// No feeds at all in the list , add dummy list item
+		TBuf<KMaxFeedNameLength> itemName;
+		iEikonEnv->ReadResourceL(itemName, R_PODCAST_FEEDS_NO_FEEDS);
+		iItemArray->Reset();
+		iItemIdArray.Reset();
+	
+		TListItemProperties itemProps;
+		itemProps.SetDimmed(ETrue);
+		itemProps.SetHiddenSelection(ETrue);								
+		iListContainer->Listbox()->ItemDrawer()->SetPropertiesL(0, itemProps);
+		}
+	iListContainer->Listbox()->HandleItemAdditionL();		
+	}
+
+/** 
+ * Command handling function intended for overriding by sub classes. 
+ * Default implementation is empty.  
+ * @param aCommand ID of the command to respond to. 
+ */
+void CPodcastFeedView::HandleCommandL(TInt aCommand)
+	{
+	//CloseToolbarExtension();
+	switch(aCommand)
+		{
+        case EPodcastHide:
+			AppUi()->HandleCommandL(EEikCmdExit);
+			break;
+		case EPodcastAddFeed:
+			HandleAddFeedL();
+			break;
+		case EPodcastImportFeeds:
+			HandleImportFeedsL();
+			break;
+		case EPodcastExportFeeds:
+			HandleExportFeedsL();
+			break;
+		case EPodcastEditFeed:
+			HandleEditFeedL();
+			break;
+		case EPodcastDeleteFeedHardware:
+		case EPodcastDeleteFeed:
+			HandleRemoveFeedL();
+			break;
+		case EPodcastUpdateAllFeeds:
+			{
+			iUpdatingAllRunning = ETrue;			
+			iPodcastModel.FeedEngine().UpdateAllFeedsL();
+			UpdateToolbar();
+			}break;
+		case EPodcastUpdateFeed:
+			{
+			HandleUpdateFeedL();
+			}break;
+		case EPodcastCancelUpdateAllFeeds:
+			{
+			if(iUpdatingAllRunning)
+				{
+				iUpdatingAllRunning = EFalse;
+				iPodcastModel.FeedEngine().CancelUpdateAllFeeds();
+				}
+			}break;
+		case EAknSoftkeyExit:
+			{
+			RShowInfoArray dlQueue;
+			iPodcastModel.ShowEngine().GetShowsDownloadingL(dlQueue);
+			TUint queueCount = dlQueue.Count();
+			dlQueue.ResetAndDestroy();
+			dlQueue.Close();
+			
+			if (queueCount > 0 && !iPodcastModel.SettingsEngine().DownloadSuspended())
+				{
+				TBuf<KMaxMessageLength> message;
+				iEikonEnv->ReadResourceL(message, R_EXIT_SHOWS_DOWNLOADING);
+				if(ShowQueryMessage(message))
+					{
+					// pass it on to AppUi, which will exit for us
+					CPodcastListView::HandleCommandL(aCommand);
+					}
+				} 
+			else
+				{
+					// nothing in queue, or downloading suspended
+					CPodcastListView::HandleCommandL(aCommand);
+				}
+			}
+			break;
+		default:
+			CPodcastListView::HandleCommandL(aCommand);
+			break;
+		}
+	UpdateToolbar();
+	}
+
+void CPodcastFeedView::UpdateToolbar()
+{
+	CAknToolbar* toolbar = Toolbar();
+	
+	if (toolbar)
+		{
+		toolbar->HideItem(EPodcastUpdateAllFeeds, iUpdatingAllRunning, ETrue);
+		toolbar->HideItem(EPodcastCancelUpdateAllFeeds, !iUpdatingAllRunning, ETrue );
+		toolbar->SetItemDimmed(EPodcastAddFeed, iUpdatingAllRunning, ETrue );
+		toolbar->SetItemDimmed(EPodcastSettings, iUpdatingAllRunning, ETrue );
+		}
+}
+
+void CPodcastFeedView::HandleAddFeedL()
+	{
+	TBuf<KFeedUrlLength> url;
+	url.Copy(_L("http://"));
+	CAknTextQueryDialog * dlg =CAknTextQueryDialog::NewL(url);
+	dlg->PrepareLC(R_PODCAST_ADD_FEED_DLG);
+	HBufC* prompt = iEikonEnv->AllocReadResourceLC(R_PODCAST_ADDFEED_PROMPT);
+	dlg->SetPromptL(*prompt);
+	CleanupStack::PopAndDestroy(prompt);
+	
+	if(dlg->RunLD())
+		{
+		
+		// if no :// we do a search
+		if (url.Find(_L("://")) == KErrNotFound)
+			{
+			HBufC *waitText = iEikonEnv->AllocReadResourceLC(R_SEARCHING);
+			ShowWaitDialogL(*waitText);
+			CleanupStack::PopAndDestroy(waitText);	
+	
+			iOpmlState = EOpmlSearching;
+			iPodcastModel.FeedEngine().SearchForFeedL(url);
+			}
+		else
+			{
+			PodcastUtils::FixProtocolsL(url);
+	
+			CFeedInfo* newFeedInfo = CFeedInfo::NewL();
+			CleanupStack::PushL(newFeedInfo);
+			newFeedInfo->SetUrlL(url);
+			newFeedInfo->SetTitleL(newFeedInfo->Url());
+			
+			TBool added = iPodcastModel.FeedEngine().AddFeedL(*newFeedInfo);
+			
+			if (added)
+				{
+				UpdateListboxItemsL();
+				
+				// ask if users wants to update it now
+				TBuf<KMaxMessageLength> message;
+				iEikonEnv->ReadResourceL(message, R_ADD_FEED_SUCCESS);
+				if(ShowQueryMessage(message))
+					{
+					CFeedInfo *info = iPodcastModel.FeedEngine().GetFeedInfoByUid(newFeedInfo->Uid());
+					
+					iPodcastModel.ActiveShowList().Reset();
+					iPodcastModel.SetActiveFeedInfo(info);			
+					AppUi()->ActivateLocalViewL(KUidPodcastShowsViewID,  TUid::Uid(0), KNullDesC8());
+					iPodcastModel.FeedEngine().UpdateFeedL(newFeedInfo->Uid());
+					}
+				}
+			else
+				{
+				TBuf<KMaxMessageLength> message;
+				iEikonEnv->ReadResourceL(message, R_ADD_FEED_EXISTS);
+				ShowErrorMessage(message);
+				}		
+			
+			CleanupStack::PopAndDestroy(newFeedInfo);
+			}
+		}
+	}
+
+void CPodcastFeedView::HandleEditFeedL()
+	{
+	TInt index = iListContainer->Listbox()->CurrentItemIndex();
+	
+	if(index < iItemArray->MdcaCount() && index >= 0)
+		{
+		CFeedInfo *info = iPodcastModel.FeedEngine().GetSortedFeeds()[index];
+
+		TBuf<KFeedTitleLength> title;
+		title.Copy(info->Title());
+		TBuf<KFeedUrlLength> url;
+		url.Copy(info->Url());
+		CAknMultiLineDataQueryDialog  *dlg = CAknMultiLineDataQueryDialog ::NewL(title, url);
+	
+		if (dlg->ExecuteLD(R_PODCAST_EDIT_FEED_DLG)) 
+			{
+			
+			if(info->Url().Compare(url) != 0)
+				{
+				TBuf<KMaxMessageLength> dlgMessage;
+				iEikonEnv->ReadResourceL(dlgMessage, R_ADD_FEED_REPLACE);
+
+				// Ask the user if it is OK to remove all shows
+				if ( ShowQueryMessage(dlgMessage))
+					{
+					PodcastUtils::FixProtocolsL(url);
+					
+					//----- HACK ---- //
+					CFeedInfo* temp = CFeedInfo::NewLC();
+					temp->SetUrlL(url);
+					TBool added = iPodcastModel.FeedEngine().AddFeedL(*temp);
+					if (added) {
+						// The Feed URL did not exist
+						// Remove the temp entry so that the correct entry could be changed
+						iPodcastModel.FeedEngine().RemoveFeedL(temp->Uid());	
+						
+						// user has accepted that shows will be deleted
+						iPodcastModel.ShowEngine().DeleteAllShowsByFeedL(info->Uid());
+
+						// update URL
+						info->SetUrlL(url);	
+					
+						if (info->Title().Compare(title) != 0)
+							{
+							info->SetTitleL(title);
+							info->SetCustomTitle();	
+							}
+						iPodcastModel.FeedEngine().UpdateFeed(info);
+						UpdateListboxItemsL();
+					} else {
+						// the feed existed. Object deleted in AddFeed.	
+						TBuf<KMaxMessageLength> dlgMessage;
+						iEikonEnv->ReadResourceL(dlgMessage, R_ADD_FEED_EXISTS);
+						ShowErrorMessage(dlgMessage);
+					}
+					CleanupStack::PopAndDestroy(temp);
+				}
+			} else { // no url change, maybe title?
+				// Update the title
+				if (info->Title().Compare(title) != 0)
+				{
+					info->SetTitleL(title);
+					info->SetCustomTitle();	
+					iPodcastModel.FeedEngine().UpdateFeed(info);
+					UpdateListboxItemsL();
+				}
+			}
+		}
+		}
+	}
+
+void CPodcastFeedView::HandleRemoveFeedL()
+	{
+	if(iListContainer->Listbox() != NULL)
+		{
+		TInt index = iListContainer->Listbox()->CurrentItemIndex();
+	
+		if(index < iItemArray->MdcaCount() && index >= 0)
+			{
+			CFeedInfo *info = iPodcastModel.FeedEngine().GetFeedInfoByUid(iItemIdArray[index]);
+			TBuf<KMaxMessageLength> templ;
+			TBuf<KMaxMessageLength> message;
+			iEikonEnv->ReadResourceL(templ, R_PODCAST_REMOVE_FEED_PROMPT);
+			message.Format(templ, &info->Title());					
+			if(ShowQueryMessage(message))
+				{
+				iPodcastModel.FeedEngine().RemoveFeedL(iItemIdArray[index]);
+				iItemArray->Delete(index);
+				iItemIdArray.Remove(index);
+				iListContainer->Listbox()->HandleItemRemovalL();
+				iListContainer->Listbox()->DrawNow();
+				}					
+			}
+		UpdateListboxItemsL();
+		}
+	}
+
+void CPodcastFeedView::HandleUpdateFeedL()
+	{
+	TInt index = iListContainer->Listbox()->CurrentItemIndex();
+	
+	if(index < iItemArray->MdcaCount() && index >= 0)
+		{
+		CFeedInfo *info = iPodcastModel.FeedEngine().GetSortedFeeds()[index];
+		iPodcastModel.FeedEngine().UpdateFeedL(info->Uid());
+		}
+	}
+
+void CPodcastFeedView::HandleImportFeedsL()
+	{
+	CAknMemorySelectionDialog* memDlg = 
+		CAknMemorySelectionDialog::NewL(ECFDDialogTypeNormal, ETrue);
+	CleanupStack::PushL(memDlg);
+	CAknMemorySelectionDialog::TMemory memory = 
+		CAknMemorySelectionDialog::EPhoneMemory;
+
+	if (memDlg->ExecuteL(memory))
+		{
+		TFileName importName;
+	
+		if (memory==CAknMemorySelectionDialog::EMemoryCard)
+		{
+			importName = PathInfo:: MemoryCardRootPath();
+		}
+		else
+		{
+			importName = PathInfo:: PhoneMemoryRootPath();
+		}
+
+		CAknFileSelectionDialog* dlg = CAknFileSelectionDialog::NewL(ECFDDialogTypeNormal, R_PODCAST_IMPORT_PODCAST);
+		CleanupStack::PushL(dlg);
+
+		dlg->SetDefaultFolderL(importName);
+		
+		if(dlg->ExecuteL(importName))
+			{
+			if(importName.Length()>0)
+				{
+				HBufC *waitText = iEikonEnv->AllocReadResourceLC(R_IMPORTING);
+				iOpmlState = EOpmlImporting;
+				ShowWaitDialogL(*waitText);
+				CleanupStack::PopAndDestroy(waitText);	
+
+				TRAPD(err, iPodcastModel.FeedEngine().ImportFeedsL(importName));
+									
+				if (err != KErrNone) {
+					TBuf<KMaxMessageLength> message;
+					iEikonEnv->ReadResourceL(message, R_IMPORT_FEED_FAILURE);
+					ShowErrorMessage(message);
+					}
+				}
+				
+			}
+		CleanupStack::PopAndDestroy(dlg);
+		}
+	CleanupStack::PopAndDestroy(memDlg);
+	}
+
+void CPodcastFeedView::HandleExportFeedsL()
+	{
+	CAknMemorySelectionDialog* memDlg = 
+		CAknMemorySelectionDialog::NewL(ECFDDialogTypeSave, ETrue);
+	CleanupStack::PushL(memDlg);
+	CAknMemorySelectionDialog::TMemory memory = 
+		CAknMemorySelectionDialog::EPhoneMemory;
+
+	if (memDlg->ExecuteL(memory))
+		{
+		TFileName pathName;
+		
+		if (memory==CAknMemorySelectionDialog::EMemoryCard)
+		{
+			pathName = PathInfo::MemoryCardRootPath();
+		}
+		else
+		{
+			pathName = PathInfo::PhoneMemoryRootPath();
+		}
+
+		CAknFileSelectionDialog* dlg = CAknFileSelectionDialog::NewL(ECFDDialogTypeSave, R_PODCAST_EXPORT_FEEDS);
+		CleanupStack::PushL(dlg);
+								
+		if(dlg->ExecuteL(pathName))
+			{
+			CAknFileNamePromptDialog *fileDlg = CAknFileNamePromptDialog::NewL(R_PODCAST_FILENAME_PROMPT_DIALOG);
+			CleanupStack::PushL(fileDlg);
+			fileDlg->SetPathL(pathName);
+			TFileName fileName;
+			if (fileDlg->ExecuteL(fileName) && fileName.Length() > 0)
+				{
+				pathName.Append(fileName);
+				TFileName temp;
+				TRAPD(err, iPodcastModel.FeedEngine().ExportFeedsL(temp));						
+				BaflUtils::CopyFile(iEikonEnv->FsSession(), temp, pathName);
+				BaflUtils::DeleteFile(iEikonEnv->FsSession(),temp);	
+				if (err == KErrNone) 
+					{
+					UpdateListboxItemsL();
+					TInt numFeeds = iPodcastModel.FeedEngine().GetSortedFeeds().Count();
+									
+					TBuf<KMaxMessageLength> message;
+					TBuf<KMaxMessageLength> templ;
+					iEikonEnv->ReadResourceL(templ, R_EXPORT_FEED_SUCCESS);
+					message.Format(templ, numFeeds);
+					ShowOkMessage(message);
+					} 
+				else 
+					{
+					TBuf<KMaxMessageLength> message;
+					iEikonEnv->ReadResourceL(message, R_EXPORT_FEED_FAILURE);
+					ShowErrorMessage(message);
+					}
+				}
+			CleanupStack::PopAndDestroy(fileDlg);
+			}
+		CleanupStack::PopAndDestroy(dlg);
+	}
+	CleanupStack::PopAndDestroy(memDlg);									
+	}
+
+void CPodcastFeedView::CheckResumeDownload()
+	{
+	// if there are shows queued for downloading, ask if we should resume now
+	RShowInfoArray showsDownloading;
+	iPodcastModel.ShowEngine().GetShowsDownloadingL(showsDownloading);
+
+	if (showsDownloading.Count() > 0)
+		{
+		TBuf<KMaxMessageLength> msg;
+		iEikonEnv->ReadResourceL(msg, R_PODCAST_ENABLE_DOWNLOADS_PROMPT);
+	
+		if (ShowQueryMessage(msg))
+			{
+			// need to suspend downloads before ResumeDownloadL will work :)
+			iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+			// resume downloading if user says yes
+			iPodcastModel.ShowEngine().ResumeDownloadsL();
+			}
+		else
+			{
+			// we disable downloading if user says no
+			iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+			}
+		}
+	
+	// if no shows in queue, we keep whichever state suspend is in
+	showsDownloading.ResetAndDestroy();
+	}
+
+void CPodcastFeedView::OpmlParsingComplete(TUint aNumFeedsImported)
+	{
+	DP("CPodcastFeedView::OpmlParsingComplete BEGIN");
+	
+	switch (iOpmlState)
+		{
+		case EOpmlIdle:
+			break;
+		case EOpmlImporting:
+			{
+			UpdateListboxItemsL();
+			delete iWaitDialog;
+			iOpmlState = EOpmlIdle;
+				
+			TBuf<KMaxMessageLength> message;
+			TBuf<KMaxMessageLength> templ;
+			iEikonEnv->ReadResourceL(templ, R_IMPORT_FEED_SUCCESS);
+			message.Format(templ, aNumFeedsImported);
+			
+			if(ShowQueryMessage(message))
+				{
+				HandleCommandL(EPodcastUpdateAllFeeds);
+				}
+			}
+			break;
+		case EOpmlSearching:
+			delete iWaitDialog;
+			if (iPodcastModel.FeedEngine().GetSearchResults().Count() == 0)
+				{
+				TBuf<KMaxMessageLength> message;
+				iEikonEnv->ReadResourceL(message, R_SEARCH_NORESULTS);
+				ShowErrorMessage(message);
+				}
+			else
+				{
+				AppUi()->ActivateLocalViewL(KUidPodcastSearchViewID,  TUid::Uid(0), KNullDesC8());
+				}
+			iOpmlState = EOpmlIdle;
+		default:
+			break;
+		}
+	
+	DP("CPodcastFeedView::OpmlParsingComplete END");
+	}
+
+void CPodcastFeedView::DialogDismissedL(TInt /*aButtonId*/)
+	{
+	iPodcastModel.FeedEngine().CancelUpdateAllFeeds();
+	}