src/NPRStoryListBox.cpp
changeset 0 0049171ecffb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/NPRStoryListBox.cpp	Fri Jul 24 08:46:02 2009 +0100
@@ -0,0 +1,496 @@
+/*
+ ============================================================================
+ Name	: NPRStoryListBox.cpp
+ Author	: Symsource
+ 
+ Copyright (c) 2009 Symbian Foundation Ltd
+ 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:
+ - Symsource
+ 
+ Contributors:
+ - Symsource
+ 
+ Description : Container for Series60 double style list box to show the NPR's story list
+ ============================================================================
+ */
+
+#include <barsread.h>
+#include <aknlists.h>
+#include <akniconarray.h>
+#include <NPR_0xEEB0E481.rsg>
+#include <list_icons.mbg>
+
+#include "NPRStoryListBox.h"
+#include "NPRStoryListBoxView.h"
+#include "NPR.hrh"
+#include "NPRAppUi.h"
+#include "NPRAppEngine.h"
+#include "NPRHtmlCreator.h"
+
+_LIT(KStringHeader, "%d\t%S\t%S" );
+_LIT(KTestUiFile, "\\resource\\apps\\list_icons.mbm");
+				
+/**
+ * Construct the control (first phase).
+ *  Creates an instance and initializes it.
+ *  Instance is not left on cleanup stack.
+ * @param aRect bounding rectangle
+ * @param aParent owning parent, or NULL
+ * @param aCommandObserver command observer
+ * @return initialized instance of CNPRStoryListBox
+ */
+CNPRStoryListBox* CNPRStoryListBox::NewL( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver )
+	{
+	CNPRStoryListBox* self = CNPRStoryListBox::NewLC( 
+			aRect, 
+			aParent, 
+			aCommandObserver );
+	CleanupStack::Pop( self );
+	return self;
+	}
+
+/**
+ * Construct the control (first phase).
+ *  Creates an instance and initializes it.
+ *  Instance is left on cleanup stack.
+ * @param aRect The rectangle for this window
+ * @param aParent owning parent, or NULL
+ * @param aCommandObserver command observer
+ * @return new instance of CNPRStoryListBox
+ */
+CNPRStoryListBox* CNPRStoryListBox::NewLC( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver )
+	{
+	CNPRStoryListBox* self = new ( ELeave ) CNPRStoryListBox();
+	CleanupStack::PushL( self );
+	self->ConstructL( aRect, aParent, aCommandObserver );
+	return self;
+	}
+			
+/**
+ * First phase of Symbian two-phase construction. Should not 
+ * contain any code that could leave.
+ */
+CNPRStoryListBox::CNPRStoryListBox()
+	{
+	iListBox = NULL;
+	iStoryArray = static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())->Engine().Stories();
+	}
+/** 
+ * Destroy child controls.
+ */
+CNPRStoryListBox::~CNPRStoryListBox()
+	{
+	delete iHtmlCreator;
+	delete iListBox;
+	iListBox = NULL;
+	}
+
+/**
+ * Construct the control (second phase).
+ *  Creates a window to contain the controls and activates it.
+ * @param aRect bounding rectangle
+ * @param aCommandObserver command observer
+ * @param aParent owning parent, or NULL
+ */ 
+void CNPRStoryListBox::ConstructL( 
+		const TRect& aRect, 
+		const CCoeControl* aParent, 
+		MEikCommandObserver* aCommandObserver )
+	{
+	if ( aParent == NULL )
+	    {
+		CreateWindowL();
+	    }
+	else
+	    {
+	    SetContainerWindowL( *aParent );
+	    }
+	iFocusControl = NULL;
+	iCommandObserver = aCommandObserver;
+	iHtmlCreator = CNPRHtmlCreator::NewL();	
+	
+	InitializeControlsL();
+	SetRect( aRect );
+	ActivateL();
+	}
+			
+/**
+* Return the number of controls in the container (override)
+* @return count
+*/
+TInt CNPRStoryListBox::CountComponentControls() const
+	{
+	return ( int ) ELastControl;
+	}
+				
+/**
+* Get the control with the given index (override)
+* @param aIndex Control index [0...n) (limited by #CountComponentControls)
+* @return Pointer to control
+*/
+CCoeControl* CNPRStoryListBox::ComponentControl( TInt aIndex ) const
+	{
+	switch(aIndex)
+		{
+	case EListBox:
+		return iListBox;
+		}
+	return NULL;
+	}
+				
+/**
+ *	Handle resizing of the container. This implementation will lay out
+ *  full-sized controls like list boxes for any screen size, and will layout
+ *  labels, editors, etc. to the size they were given in the UI designer.
+ *  This code will need to be modified to adjust arbitrary controls to
+ *  any screen size.
+ */				
+void CNPRStoryListBox::SizeChanged()
+	{
+	CCoeControl::SizeChanged();
+	LayoutControls();
+	}
+				
+/**
+ * Layout components as specified in the UI Designer
+ */
+void CNPRStoryListBox::LayoutControls()
+	{
+	iListBox->SetExtent( TPoint( 0, 0 ), iListBox->MinimumSize() );
+	}
+
+/**
+ *	Handle key events.
+ */				
+TKeyResponse CNPRStoryListBox::OfferKeyEventL( 
+		const TKeyEvent& aKeyEvent, 
+		TEventCode aType )
+	{
+	if ( aKeyEvent.iCode == EKeyLeftArrow 
+		|| aKeyEvent.iCode == EKeyRightArrow )
+		{
+		// Listbox takes all events even if it doesn't use them
+		return EKeyWasNotConsumed;
+		}
+
+	if ( iFocusControl != NULL && aKeyEvent.iCode == EKeyDevice3)
+		{
+		ShowSelectedStoryL();
+		return EKeyWasConsumed;
+		}
+
+	if ( iFocusControl != NULL
+		&& iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
+		{
+		return EKeyWasConsumed;
+		}
+	return CCoeControl::OfferKeyEventL( aKeyEvent, aType );
+	}
+				
+/**
+ *	Initialize each control upon creation.
+ */				
+void CNPRStoryListBox::InitializeControlsL()
+	{
+	iListBox = new ( ELeave ) CAknDoubleLargeStyleListBox;
+	iListBox->SetContainerWindowL( *this );
+		{
+		TResourceReader reader;
+		iEikonEnv->CreateResourceReaderLC( reader, R_NPRSTORY_LIST_BOX_LIST_BOX );
+		iListBox->ConstructFromResourceL( reader );
+		CleanupStack::PopAndDestroy(); // reader internal state
+		}
+	// the listbox owns the items in the list and will free them
+	iListBox->Model()->SetOwnershipType( ELbmOwnsItemArray );
+    iListBox->CreateScrollBarFrameL(ETrue);
+    iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOn, CEikScrollBarFrame::EAuto);
+	
+	SetupListBoxIconsL();
+	// add list items
+	for(TInt i=0; i<iStoryArray->Count(); i++)
+		{
+		HBufC* story = HBufC::NewLC(KStringHeader().Length()
+				+ (*iStoryArray)[i]->Title().Length()
+				+ (*iStoryArray)[i]->Teaser().Length()
+				);
+		TPtr storyPtr = story->Des();
+		CreateListBoxItemL(storyPtr, TInt(0), (*iStoryArray)[i]->Title(), (*iStoryArray)[i]->Teaser());
+		AddListBoxItemL(iListBox, storyPtr);
+		CleanupStack::PopAndDestroy(story);
+		}
+	
+	iListBox->SetFocus( ETrue );
+	iFocusControl = iListBox;	
+	}
+
+/** 
+ * Handle global resource changes, such as scalable UI or skin events (override)
+ */
+void CNPRStoryListBox::HandleResourceChange( TInt aType )
+	{
+	CCoeControl::HandleResourceChange( aType );
+	SetRect( iAvkonViewAppUi->View( TUid::Uid( ENPRStoryListBoxViewId ) )->ClientRect() );
+	}
+				
+/**
+ *	Draw container contents.
+ */				
+void CNPRStoryListBox::Draw( const TRect& aRect ) const
+	{
+	CWindowGc& gc = SystemGc();
+	gc.Clear( aRect );
+	}
+				
+/**
+ *	Add a list box item to a list.
+ */
+void CNPRStoryListBox::AddListBoxItemL( 
+		CEikTextListBox* aListBox,
+		const TDesC& aString )
+	{
+	CTextListBoxModel* model = aListBox->Model();
+	CDesCArray* itemArray = static_cast< CDesCArray* > ( model->ItemTextArray() );
+	itemArray->AppendL( aString );
+	aListBox->HandleItemAdditionL();
+	}
+
+/**
+ * Get the array of selected item indices, with respect to the list model.
+ * The array is sorted in ascending order.
+ * The array should be destroyed with two calls to CleanupStack::PopAndDestroy(),
+ * the first with no argument (referring to the internal resource) and the
+ * second with the array pointer.
+ * @return newly allocated array, which is left on the cleanup stack;
+ *	or NULL for empty list. 
+ */
+RArray< TInt >* CNPRStoryListBox::GetSelectedListBoxItemsLC( CEikTextListBox* aListBox )
+	{
+	CAknFilteredTextListBoxModel* model = 
+		static_cast< CAknFilteredTextListBoxModel *> ( aListBox->Model() );
+	if ( model->NumberOfItems() == 0 )
+		return NULL;
+		
+	// get currently selected indices
+	const CListBoxView::CSelectionIndexArray* selectionIndexes =
+		aListBox->SelectionIndexes();
+	TInt selectedIndexesCount = selectionIndexes->Count();
+	if ( selectedIndexesCount == 0 )
+		return NULL;
+		
+	// copy the indices and sort numerically
+	RArray<TInt>* orderedSelectedIndices = 
+		new (ELeave) RArray< TInt >( selectedIndexesCount );
+	
+	// push the allocated array
+	CleanupStack::PushL( orderedSelectedIndices );
+	
+	// dispose the array resource
+	CleanupClosePushL( *orderedSelectedIndices );
+	
+	// see if the search field is enabled
+	CAknListBoxFilterItems* filter = model->Filter();
+	if ( filter != NULL )
+		{
+		// when filtering enabled, translate indices back to underlying model
+		for ( TInt idx = 0; idx < selectedIndexesCount; idx++ )
+			{
+			TInt filteredItem = ( *selectionIndexes ) [ idx ];
+			TInt actualItem = filter->FilteredItemIndex ( filteredItem );
+			orderedSelectedIndices->InsertInOrder( actualItem );
+			}
+		}
+	else
+		{
+		// the selection indices refer directly to the model
+		for ( TInt idx = 0; idx < selectedIndexesCount; idx++ )
+			orderedSelectedIndices->InsertInOrder( ( *selectionIndexes ) [ idx ] );
+		}	
+		
+	return orderedSelectedIndices;
+	}
+
+/**
+ * Delete the selected item or items from the list box.
+ */
+void CNPRStoryListBox::DeleteSelectedListBoxItemsL( CEikTextListBox* aListBox )
+	{
+	CAknFilteredTextListBoxModel* model = 
+		static_cast< CAknFilteredTextListBoxModel *> ( aListBox->Model() );
+	if ( model->NumberOfItems() == 0 )
+		return;
+	
+	RArray< TInt >* orderedSelectedIndices = GetSelectedListBoxItemsLC( aListBox );		
+	if ( !orderedSelectedIndices )
+		return;
+		
+	// Delete selected items from bottom up so indices don't change on us
+	CDesCArray* itemArray = static_cast< CDesCArray* > ( model->ItemTextArray() );
+	TInt currentItem = 0;
+	
+	for ( TInt idx = orderedSelectedIndices->Count(); idx-- > 0; ) 
+		{
+		currentItem = ( *orderedSelectedIndices )[ idx ];
+		itemArray->Delete ( currentItem );
+		}
+	
+	// dispose the array resources
+	CleanupStack::PopAndDestroy();
+	
+	// dispose the array pointer
+	CleanupStack::PopAndDestroy( orderedSelectedIndices );
+	
+	// refresh listbox's cursor now that items are deleted
+	AknListBoxUtils::HandleItemRemovalAndPositionHighlightL(
+		aListBox, currentItem, ETrue );
+	}
+
+/**
+ *	Get the listbox.
+ */
+CAknDoubleLargeStyleListBox* CNPRStoryListBox::ListBox()
+	{
+	return iListBox;
+	}
+
+/**
+ *	Create a list box item with the given column values.
+ */
+void CNPRStoryListBox::CreateListBoxItemL( TDes& aBuffer, 
+		TInt aIconIndex,
+		const TDesC& aMainText,
+		const TDesC& aSecondaryText )
+	{
+	
+	aBuffer.Format( KStringHeader(), aIconIndex, &aMainText, &aSecondaryText);
+	} 
+				
+/**
+ *	Add an item to the list by reading the text items from the array resource
+ *	and setting a single image property (if available) from an index
+ *	in the list box's icon array.
+ *	@param aResourceId id of an ARRAY resource containing the textual
+ *	items in the columns
+ *	@param aIconIndex the index in the icon array, or -1
+ */
+void CNPRStoryListBox::AddListBoxResourceArrayItemL( TInt aResourceId, TInt aIconIndex )
+	{
+	CDesCArray* array = iCoeEnv->ReadDesCArrayResourceL( aResourceId );
+	CleanupStack::PushL( array );
+	// This is intended to be large enough, but if you get 
+	// a USER 11 panic, consider reducing string sizes.
+	TBuf<512> listString; 
+	CreateListBoxItemL( listString, aIconIndex, (*array) [0], (*array )[1]);
+	AddListBoxItemL( iListBox, listString );
+	CleanupStack::PopAndDestroy( array );
+	} 
+				
+/**
+ *	Set up the list's icon array.
+ */
+void CNPRStoryListBox::SetupListBoxIconsL()
+	{
+	CArrayPtr< CGulIcon >* icons = new (ELeave) CAknIconArray( 1 );
+	CleanupStack::PushL( icons );
+	
+	icons->AppendL(LoadAndScaleIconL(KTestUiFile,
+									 EMbmList_iconsNpr_symbian_generic,
+									 EMbmList_iconsNpr_symbian_generic_mask,
+									 NULL, EAspectRatioPreserved ));
+
+	CleanupStack::Pop( icons );
+
+	if ( icons != NULL )
+		{
+		iListBox->ItemDrawer()->ColumnData()->SetIconArray( icons );
+		}
+	}
+
+/** 
+ *	Handle commands relating to markable lists.
+ */
+TBool CNPRStoryListBox::HandleMarkableListCommandL(TInt /*aCommand*/)
+	{
+	return EFalse;
+	}
+
+/**
+ *	This routine loads and scales a bitmap or icon.
+ *
+ *	@param aFileName the MBM or MIF filename
+ *	@param aBitmapId the bitmap id
+ *	@param aMaskId the mask id or -1 for none
+ *	@param aSize the TSize for the icon, or NULL to use real size
+ *	@param aScaleMode one of the EAspectRatio* enums when scaling
+ *
+ */
+CGulIcon* CNPRStoryListBox::LoadAndScaleIconL( 
+		const TDesC& aFileName,
+		TInt aBitmapId, 
+		TInt aMaskId, 
+		TSize* aSize, 
+		TScaleMode aScaleMode )
+	{
+	CFbsBitmap* bitmap;
+	CFbsBitmap* mask;
+	TRAPD(err, AknIconUtils::CreateIconL( bitmap, mask, aFileName, aBitmapId, aMaskId ));
+	
+	TSize size;
+	if ( aSize == NULL )
+		{
+		// Use size from the image header.  In case of SVG,
+		// we preserve the image data for a while longer, since ordinarily
+		// it is disposed at the first GetContentDimensions() or SetSize() call.
+		AknIconUtils::PreserveIconData( bitmap );
+		AknIconUtils::GetContentDimensions( bitmap, size );
+		}
+	else
+		{
+		size = *aSize;
+		}
+	
+	AknIconUtils::SetSize( bitmap, size, aScaleMode );
+	AknIconUtils::SetSize( mask, size, aScaleMode );
+	
+	if ( aSize == NULL )
+		{
+		AknIconUtils::DestroyIconData( bitmap );
+		}
+	
+	return CGulIcon::NewL( bitmap, mask );
+	}
+
+TInt CNPRStoryListBox::CurrentItemIndex()
+	{
+	return iListBox->CurrentItemIndex();
+	}
+
+void CNPRStoryListBox::ShowSelectedStoryL()
+	{
+//	TInt index = CurrentItemIndex();
+//	static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())->
+//	ActivateLocalViewL(TUid::Uid(ENPRStoryViewerContainerViewId), TUid::Uid(index),KNullDesC8);//TO DO use custum message instead of custum command
+
+	TInt currentItem = iListBox->CurrentItemIndex();
+	if (currentItem==-1)
+		{
+		return;
+		}
+	
+	CNPRStory* story=(*iStoryArray)[currentItem];
+	
+	//TODO - Move this code into the browser container, so it is seperate from the listbox	
+	iHtmlCreator->CreateHtmlFileL(story);
+
+	static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())->ActivateLocalViewL(TUid::Uid(ENPRBrowserViewId));
+	}