diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/src/akngrid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/src/akngrid.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,2200 @@ +/* +* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: This is a concrete class for the handling of a grid. +* The class handles a rectangular grid arrangement of items +* held in any linear ordering i.e. cells ordered top to +* bottom and left, left to right and down etc. +* +*/ + + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +//formatted listbox +#include +#include + +#include +#include +#include +#include "layoutmetadata.cdl.h" +#include + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + #include + #include +#endif //RD_UI_TRANSITION_EFFECTS_LIST + +#include +#include "akntrace.h" + +const TInt KDefaultLineHeightForHorizontalGrid = 10; + +const TInt KEikListBoxPointerRepeatInterval = 100000; // 0.1 seconds in micro seconds + +const TInt KEikListBoxInvalidIndex = -1; + +enum TGridOrientation + { + EGridOrientationHorizontal, + EGridOrientationVertical + }; +enum TGridHorizontal + { + EGridHorizontalRightToLeft, + EGridHorizontalLeftToRight, + EGridHorizontalWritingDirection, + EGridHorizontalAntiWritingDirection + }; +enum TGridVertical + { + EGridVerticalBottomToTop, + EGridVerticalTopToBottom + }; + + +/** +* Local Panic Function and Panic Codes +*/ +enum TAknGridPanicCodes + { + EAknPanicGridGeneralPanic, + EAknPanicGridModelAlreadyExists, + EAknPanicGridInvalidNumberOfPrimaryItems, + EAknPanicGridNoView + }; + + +enum TAknGridStateFlags + { + EAknGridStateButton1DownInGrid = 0x01 + }; + +// ================= Extension class ======================== +NONSHARABLE_CLASS(CAknGridExtension) : public CBase + { + public: + CAknGridExtension(); + ~CAknGridExtension(); + TInt GetScrollingSpeed( TBool aIsOverItem, TInt aItemIndex, CAknGridView& aView, + const TPoint& aPoint ) const; + + + public: // data + TInt iFlags; + // EMMA-7A8B9F.Ugly hack. Prevent MopSupplyObject being invoked + // from CEikListBox::MopGetObject() + TBool iIsFromBaseClass; + TPoint iLastPoint; + TBool iKineticScrolling; + TBool iSingleClickEnabled; + }; + +CAknGridExtension::CAknGridExtension() + : + iFlags(0), + iIsFromBaseClass( EFalse ), + iLastPoint( 0, 0 ), + iKineticScrolling( CAknPhysics::FeatureEnabled() ), + iSingleClickEnabled( iAvkonAppUi->IsSingleClickCompatible() ) + { + } + +CAknGridExtension::~CAknGridExtension() + { + } + +TInt CAknGridExtension::GetScrollingSpeed( TBool aIsOverItem, TInt aItemIndex, + CAknGridView& aView, const TPoint& aPoint ) const + { + TInt itemCountInRow = aView.NumberOfColsInView(); + TInt speed = 0; + TInt y = aPoint.iY - iLastPoint.iY; + if ( aIsOverItem ) + { + if ( aView.BottomItemIndex() - aItemIndex < itemCountInRow + && y> 0 ) + { + speed = 1; + } + else if ( aItemIndex - aView.TopItemIndex() < itemCountInRow + && y < 0 ) + { + speed = -1; + } + } + else + { + speed = 0; + } + return speed; + } + + +// ================= CAknGrid class ======================== + +GLDEF_C void Panic(TAknGridPanicCodes aPanic) + { + _LIT(KPanicCat,"AknGrid"); + User::Panic(KPanicCat, aPanic); + } + + +EXPORT_C CAknGrid::CAknGrid() + { + } + +EXPORT_C CAknGrid::~CAknGrid() + { + delete iExtension; + } + +/** +* This function must only be called before ConstructL() +*/ +EXPORT_C void CAknGrid::SetModel(CAknGridM* aModel) + { + __ASSERT_ALWAYS(!iModel, Panic(EAknPanicGridModelAlreadyExists)); + iModel = aModel; + } + +EXPORT_C void CAknGrid::ConstructL(const CCoeControl* aParent, TInt aFlags) + { + _AKNTRACE_FUNC_ENTER; + if (!iModel) + { + iModel = new(ELeave) CAknGridM; + } + + GridModel()->ConstructL(); + + CreateItemDrawerL(); + ItemDrawer()->FormattedCellData()->SetControl(this); + CEikListBox::ConstructL(aParent, aFlags); + + if ( !iExtension ) + { + iExtension = new (ELeave) CAknGridExtension; + } + + // the default scrolling method is follows items + SetPrimaryScrollingType( CAknGridView::EScrollFollowsItemsAndLoops ); + SetSecondaryScrollingType( CAknGridView::EScrollFollowsItemsAndLoops ); + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::ConstructFromResourceL(TResourceReader& aReader) + { + _AKNTRACE_FUNC_ENTER; + RestoreCommonListBoxPropertiesL(aReader); + TInt requiredCellCharWidth=aReader.ReadInt16(); + + if (!iModel) + iModel = new(ELeave) CAknGridM; + + TInt items=aReader.ReadInt32(); + if (!items) + { + STATIC_CAST(CAknGridM*,iModel)->ConstructL(); + } + else + { + CDesCArray* desArray=iCoeEnv->ReadDesCArrayResourceL(items); + CleanupStack::PushL(desArray); + + STATIC_CAST(CAknGridM*,iModel)->ConstructL(desArray); + CleanupStack::Pop( desArray ); + } + + CreateItemDrawerL(); + iItemDrawer->SetDrawMark(EFalse); + ItemDrawer()->FormattedCellData()->SetControl(this); + STATIC_CAST(CFormattedCellListBoxItemDrawer*,iItemDrawer)->SetCellWidthInChars(requiredCellCharWidth); + CreateViewL(); + + // empty text + HBufC* emptyGridText = aReader.ReadHBufCL(); + if (emptyGridText) + { + CleanupStack::PushL(emptyGridText); + SetEmptyGridTextL(*emptyGridText); + CleanupStack::PopAndDestroy( emptyGridText ); + } + + TInt gridStyle=aReader.ReadInt32(); + + TResourceReader reader; + if (!gridStyle) + { + iEikonEnv->CreateResourceReaderLC(reader,R_AVKON_GRID_STYLE_DEFAULT); + } + else + { + iEikonEnv->CreateResourceReaderLC(reader,gridStyle); + } + + SetLayoutFromResourceL(reader); + CleanupStack::PopAndDestroy(); // reader + + if ( !iExtension ) + { + iExtension = new (ELeave) CAknGridExtension; + } + _AKNTRACE_FUNC_EXIT; + } + +/** +* This routine assumes that SetLayoutL has been called to set +* up the grid. +*/ +EXPORT_C void CAknGrid::SizeChanged() + { + _AKNTRACE_FUNC_ENTER; + TRect clientRect = iBorder.InnerRect(Rect()); + + TInt currentDataIndex = 0; + CAknGridView* gridView = GridView(); + + // reset item offset + gridView->SetItemOffsetInPixels( 0 ); + + if (iCurrentIsValid) // appshell does not call HandleItemAddition! + { // so this is never called. See CAknAppStyleGrid::SizeChanged() + // remember current position + currentDataIndex = gridView->CurrentDataIndex(); + } + + TRect rect(clientRect); + rect.SetRect(rect.iTl.iX + ListBoxMargins().iLeft, rect.iTl.iY + ListBoxMargins().iTop, + rect.iBr.iX - ListBoxMargins().iRight, rect.iBr.iY - ListBoxMargins().iBottom); + iView->SetViewRect(rect); + _AKNTRACE( "The rect of grid are ( %d, %d ) ( %d, %d )", + rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX, rect.iBr.iY ); + TRAPD(err1, HandleViewRectSizeChangeL()); + if (err1) + { + if (iSBFrameOwned == ENotOwnedExternally) + { + delete iSBFrame; + iSBFrame = 0; + } + } + + // check grid orientated to show current focus (item height + // change may have moved the focus to a new page) + if (iCurrentIsValid) + { + gridView->SetCurrentDataIndex(currentDataIndex); + } + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + TRgb color; + + TInt error = AknsUtils::GetCachedColor( skin, + color, + KAknsIIDQsnTextColors, + EAknsCIQsnTextColorsCG11 ); + if (!error) + { + ItemDrawer()->SetHighlightedTextColor( color ); + } + _AKNTRACE_FUNC_EXIT; + } + +/** +* Protected routine used by functions to check/alter the dimensions +* of the grid as data items are added or removed or the +* size of the items are altered. +* This routine assumes that SetLayoutL has been called. +* This will not leave if scrollbars have both been turned off. +*/ +EXPORT_C void CAknGrid::CalcGridSizeL() + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + + CAknGridView* gridView = GridView(); + TSize gridSize = gridView->GridCellDimensions(); + + TInt definedItems = GridModel()->IndexOfLastDataItem() + 1; + + if (definedItems > 0) + { + // item height determines iHeight + if (iItemHeight < 1) + { + // item height must exist - so set to default value + // for now + CEikListBox::SetItemHeightL(KDefaultLineHeightForHorizontalGrid); + } + + if(iOrientationFlags.IsSet(EGridOrientationVertical)) + { + gridSize.iHeight = iNumOfRowsInView; + gridSize.iWidth = definedItems / gridSize.iHeight; + if (definedItems % gridSize.iHeight) + gridSize.iWidth++; + } + else + { + gridSize.iWidth = iNumOfColsInView; + gridSize.iHeight = definedItems / gridSize.iWidth; + if (definedItems % gridSize.iWidth) + gridSize.iHeight++; + } + } + else + { + //no defined items so grid empty + gridSize.iWidth = 1; + gridSize.iHeight = 1; + if (iOrientationFlags.IsSet(EGridOrientationVertical)) + gridSize.iHeight = iNumOfRowsInView; + else + gridSize.iWidth = iNumOfColsInView; + } + // set number of cells in grid + gridView->SetGridCellDimensions(gridSize); + _AKNTRACE_FUNC_EXIT; + } + + +/** +* Creates a formatted list item drawer. +*/ +EXPORT_C void CAknGrid::CreateItemDrawerL() + { + CFormattedCellListBoxData* data=CFormattedCellGridData::NewL(); + CleanupStack::PushL(data); + + data->SetControl( this ); + data->CreatePictographInterfaceL(); + + iItemDrawer=new(ELeave) CFormattedCellListBoxItemDrawer(Model(), iEikonEnv->NormalFont(), data); + CleanupStack::Pop( data ); + } + +/** +* Gives the formatted list item drawer being used by the grid. +*/ +EXPORT_C CFormattedCellListBoxItemDrawer* CAknGrid::ItemDrawer() const + { + return STATIC_CAST(CFormattedCellListBoxItemDrawer*,iItemDrawer); + } + +/** +* Informs the grid that the data in the model has altered. +* It is assumed that the grid has been initialised by a call to SetLayoutL +* before this function is called for the first time. +*/ +EXPORT_C void CAknGrid::HandleItemAdditionL() + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + + if (GridModel()->NumberOfData() <= 0) + return; + + TInt currentDataIndex = 0; + + CAknGridView* gridView = GridView(); + + if (iCurrentIsValid) + { + // remember current position + currentDataIndex = gridView->CurrentDataIndex(); + } + + CalcGridSizeL(); + + CEikListBox::HandleItemAdditionL(); + + // check the current marker is set to the first item in the + // grid if it hasn't been set yet otherwise ensure current marker still + // on cell item before new items were added. + if (!iCurrentIsValid) + SetStartPositionL(PositionAtIndex(0)); + else + gridView->SetCurrentDataIndex(currentDataIndex); + + iCurrentIsValid = ETrue; + + // redraw everything visible since all/most will have been affected + DrawNow(); + UpdateScrollBarsL(); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Informs the grid that the data in the model has altered. +* It is assumed that the grid has been initialised by a call to SetLayoutL +* before this function is called for the first time. +*/ +EXPORT_C void CAknGrid::HandleItemRemovalL() + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + + if (!iCurrentIsValid) + return; + + CAknGridView* gridView = GridView(); + + TInt currentDataIndex = gridView->CurrentDataIndex(); + + CalcGridSizeL(); + + CEikListBox::HandleItemRemovalL(); + + // check if need to reposition current index since may have been + // on one of those just deleted. + CAknGridM* gridModel = GridModel(); + if (!gridModel->IndexContainsData(currentDataIndex)) + currentDataIndex = gridModel->IndexOfLastDataItem(); + + gridView->SetCurrentDataIndex(currentDataIndex); + + // redraw everything visible since all/most will have been affected + DrawNow(); + UpdateScrollBarsL(); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Sets the orientation of the grid, either vertical or horizontal, the +* ordering of the data and the size of the primary dimension of the +* grid. +* Note: The value for the parameter aNumOfItemsInPrimaryOrient must be +* greater than zero since this determines the number of items (be it rows +* or columns) in the primary orientation of the grid. +*/ +EXPORT_C void CAknGrid::SetLayoutL(TBool aVerticalOrientation, + TBool aLeftToRight, + TBool aTopToBottom, + TInt aNumOfItemsInPrimaryOrient, + TInt aNumOfItemsInSecondaryOrient, + TSize aSizeOfItems, + TInt aWidthOfSpaceBetweenItems, + TInt aHeightOfSpaceBetweenItems) + { + _AKNTRACE_FUNC_ENTER; + TGridOrientation gridOrientation = EGridOrientationHorizontal; + if (aVerticalOrientation) + gridOrientation = EGridOrientationVertical; + + TGridHorizontal gridHorizontal = EGridHorizontalWritingDirection; + if (aLeftToRight) + gridHorizontal = EGridHorizontalLeftToRight; + else + gridHorizontal = EGridHorizontalRightToLeft; + + TGridVertical gridVertical = EGridVerticalBottomToTop; + if (aTopToBottom) + gridVertical = EGridVerticalTopToBottom; + + DoSetLayoutL(gridOrientation, + gridHorizontal, + gridVertical, + aNumOfItemsInPrimaryOrient, + aNumOfItemsInSecondaryOrient, + aSizeOfItems, + aWidthOfSpaceBetweenItems, + aHeightOfSpaceBetweenItems); + _AKNTRACE_FUNC_EXIT; + + } + +void CAknGrid::DoSetLayoutL(TInt aOrientation, + TInt aHorizontal, + TInt aVertical, + TInt aNumOfItemsInPrimaryOrient, + TInt aNumOfItemsInSecondaryOrient, + TSize aSizeOfItems, + TInt aWidthOfSpaceBetweenItems, + TInt aHeightOfSpaceBetweenItems) + { + _AKNTRACE_FUNC_ENTER; + // this must be the first method called after the construction of + // the grid + __TEST_INVARIANT; + + // number of primary items must be > 0 + __ASSERT_ALWAYS((aNumOfItemsInPrimaryOrient > 0), Panic(EAknPanicGridInvalidNumberOfPrimaryItems)); + + // store number of items in primary in case of SizeChange + // never used iNumOfItemsInPrimaryOrient = aNumOfItemsInPrimaryOrient; + + iSpaceBetweenItems.iWidth = aWidthOfSpaceBetweenItems; + iSpaceBetweenItems.iHeight = aHeightOfSpaceBetweenItems; + + iOrientationFlags.ClearAll(); + iHorizontalFlags.ClearAll(); + iVerticalFlags.ClearAll(); + TInt gridFlags = 0; + + switch(aOrientation) + { + case EGridOrientationHorizontal: + iOrientationFlags.Set(EGridOrientationHorizontal); + iNumOfRowsInView = aNumOfItemsInSecondaryOrient; + iNumOfColsInView = aNumOfItemsInPrimaryOrient; + break; + case EGridOrientationVertical: // drop through to default + default: // use default to keep BC with old code + iOrientationFlags.Set(EGridOrientationVertical); + gridFlags |= CAknGridView::EPrimaryIsVertical; + iNumOfRowsInView = aNumOfItemsInPrimaryOrient; + iNumOfColsInView = aNumOfItemsInSecondaryOrient; + break; + } + + switch(aHorizontal) + { + case EGridHorizontalRightToLeft: // drop through + case EGridHorizontalLeftToRight: // drop through + case EGridHorizontalWritingDirection: // drop through + case EGridHorizontalAntiWritingDirection: + iHorizontalFlags.Set(aHorizontal); + break; + default: // use default to keep BC with old code + iHorizontalFlags.Set(EGridHorizontalWritingDirection); + break; + } + + TBool isMirrored = AknLayoutUtils::LayoutMirrored(); + if (isMirrored) + { + if (iHorizontalFlags.IsSet(EGridHorizontalAntiWritingDirection) + || iHorizontalFlags.IsSet(EGridHorizontalLeftToRight)) + gridFlags |= CAknGridView::ELeftToRight; + } + else + { + if (iHorizontalFlags.IsSet(EGridHorizontalWritingDirection) + || iHorizontalFlags.IsSet(EGridHorizontalLeftToRight)) + gridFlags |= CAknGridView::ELeftToRight; + } + + switch(aVertical) + { + case EGridVerticalBottomToTop: + iVerticalFlags.Set(EGridVerticalBottomToTop); + break; + case EGridVerticalTopToBottom: // drop through to default + default: // use default to keep BC with old code + iVerticalFlags.Set(EGridVerticalTopToBottom); + gridFlags |= CAknGridView::ETopToBottom; + break; + } + + CAknGridView* gridView = GridView(); + + gridView->SetSpacesBetweenItems(iSpaceBetweenItems); + CAknGridView::SGrid gridDetails; + // define a single cell grid size to start with - the grid will only become + // real after we've added some data and called HandleItemAdditionL. Because + // this method is being called when dynamic layout switch is handled we + // cannot set gridDetails.iGridDimensions = TSize(1,1). Instead, we use the + // grid view's value -> a fully populated grid no longer loses its + // dimension information. Default value TSize(1,1) is now set in grid + // view's constructor. + gridDetails.iGridDimensions = gridView->GridCellDimensions(); + gridDetails.iGridFlags = gridFlags; + gridDetails.iPageSize = iNumOfColsInView*iNumOfRowsInView; + gridDetails.iColsInView = iNumOfColsInView; + gridDetails.iRowsInView = iNumOfRowsInView; + gridDetails.iSizeBetweenItems = iSpaceBetweenItems; + gridDetails.iSizeOfItems = aSizeOfItems; + CalcGridSizeL(); + gridView->SetGridDetails(gridDetails); + + gridView->SetColumnWidth(aSizeOfItems.iWidth); + SetItemHeightL(aSizeOfItems.iHeight); + SetItemsInSingleLine(gridDetails.iColsInView); + + // Create the scroll bars + _AKNTRACE( "Create scroll bar" ); + CreateScrollBarFrameL(ETrue, EFalse, ETrue); + ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto); + UpdateScrollBarsL(); + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::HandlePointerEventL(const TPointerEvent& aPointerEvent) + { + _AKNTRACE_FUNC_ENTER; + if ( AknLayoutUtils::PenEnabled() ) + { + // Scroll bar + // Do not use iSBFrame->VerticalScrollBar()->Rect() to test, + // because of iSBFrame->VerticalScrollBar owning window. + if( iSBFrame && TRect(iSBFrame->VerticalScrollBar()->Position(), + iSBFrame->VerticalScrollBar()->Size()).Contains ( aPointerEvent.iPosition )) + { + if ( !ScrollingDisabled() + && iExtension->iFlags & EAknGridStateButton1DownInGrid ) + { + if ( aPointerEvent.iType == TPointerEvent::EButton1Up ) + { + iExtension->iFlags &= ~EAknGridStateButton1DownInGrid; + } + CEikListBox::HandlePointerEventL( aPointerEvent ); + } + else + { + CCoeControl::HandlePointerEventL( aPointerEvent ); + } + return; + } + else + { + CAknGridView* gridView = GridView(); + TInt itemIndex = 0; + + TRect visibleItemsRect(gridView->ViewRect().iTl, + TSize(gridView->ItemSize(itemIndex).iWidth * iNumOfColsInView, + gridView->ItemSize(itemIndex).iHeight * iNumOfRowsInView)); + + // switch pointer event type and set button 1 down in grid flag on and off depending where event happened. + switch (aPointerEvent.iType) + { + case TPointerEvent::EButton1Down: + iExtension->iLastPoint = aPointerEvent.iPosition; + if ( visibleItemsRect.Contains(aPointerEvent.iPosition) ) + { + iExtension->iFlags |= EAknGridStateButton1DownInGrid; + } + _AKNTRACE( "TPointerEvent::EButton1Down" ); + break; + + case TPointerEvent::EButton1Up: + { + iExtension->iFlags &= ~EAknGridStateButton1DownInGrid; + _AKNTRACE( "TPointerEvent::EButton1Up" ); + break; + } + + default: + { + break; + } + } + + CEikListBox::HandlePointerEventL( aPointerEvent ); // eventually will call CAknGrid::HandleDragEventL if dragged + } + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void* CAknGrid::ExtensionInterface( TUid /*aInterface*/ ) + { + return NULL; + } + +/** +* Sets the layout from a resource. Layout includes orientation +* (either vertical or horizontal), horizontal and vertical direction +* of numbering, the number of items in the primary and secondary +* orientation, and the primary and secondary scrolling types. +*/ +EXPORT_C void CAknGrid::SetLayoutFromResourceL(TResourceReader& aReader) + { + _AKNTRACE_FUNC_ENTER; + TInt layoutFlags = aReader.ReadInt16(); + TInt primaryScroll=aReader.ReadInt16(); + TInt secondaryScroll=aReader.ReadInt16(); + TInt numItemsInPrimaryOrient=aReader.ReadInt16(); + TInt numItemsInSecondaryOrient=aReader.ReadInt16(); + TInt height = aReader.ReadInt16(); + TInt width = aReader.ReadInt16(); + TInt gapWidth = aReader.ReadInt16(); + TInt gapHeight = aReader.ReadInt16(); + + TGridOrientation gridOrientation = EGridOrientationHorizontal; + if (layoutFlags & EAknGridVerticalOrientation) + gridOrientation = EGridOrientationVertical; + + TGridHorizontal gridHorizontal = EGridHorizontalWritingDirection; + if (layoutFlags & EAknGridLeftToRight) + gridHorizontal = EGridHorizontalLeftToRight; + else if (layoutFlags & EAknGridRightToLeft) + gridHorizontal = EGridHorizontalRightToLeft; +// else if (layoutFlags & EAknGridHorizontalAntiWritingDirection) +// gridHorizontal = EGridHorizontalAntiWritingDirection; + else if (layoutFlags & EAknGridLanguageSpecificHorizontalDirection) + gridHorizontal = EGridHorizontalWritingDirection; + + TGridVertical gridVertical = EGridVerticalTopToBottom; + if (layoutFlags & EAknGridBottomToTop) + gridVertical = EGridVerticalBottomToTop; + + CAknGridView::TScrollingType prime = CAknGridView::EScrollFollowsItemsAndLoops; + CAknGridView::TScrollingType second = CAknGridView::EScrollFollowsItemsAndLoops; + + switch(primaryScroll) + { + case EAknGridFollowsItemsAndStops: + prime = CAknGridView::EScrollFollowsItemsAndStops; + break; + case EAknGridFollowsItemsAndLoops: + prime = CAknGridView::EScrollFollowsItemsAndLoops; + break; + case EAknGridFollowsGrid: + prime = CAknGridView::EScrollFollowsGrid; + break; + case EAknGridStops: + prime = CAknGridView::EScrollStops; + break; + case EAknGridIncrementLineAndStops: + prime = CAknGridView::EScrollIncrementLineAndStops; + break; + case EAknGridIncrementLineAndLoops: + prime = CAknGridView::EScrollIncrementLineAndLoops; + break; + default: + break; + } + + switch(secondaryScroll) + { + case EAknGridFollowsItemsAndStops: + second = CAknGridView::EScrollFollowsItemsAndStops; + break; + case EAknGridFollowsItemsAndLoops: + second = CAknGridView::EScrollFollowsItemsAndLoops; + break; + case EAknGridFollowsGrid: + second = CAknGridView::EScrollFollowsGrid; + break; + case EAknGridStops: + second = CAknGridView::EScrollStops; + break; + case EAknGridIncrementLineAndStops: + second = CAknGridView::EScrollIncrementLineAndStops; + break; + case EAknGridIncrementLineAndLoops: + second = CAknGridView::EScrollIncrementLineAndLoops; + break; + default: + break; + } + TSize itemSize(width,height); + DoSetLayoutL(gridOrientation, gridHorizontal, gridVertical, numItemsInPrimaryOrient, numItemsInSecondaryOrient, itemSize, gapWidth, gapHeight); + SetPrimaryScrollingType(prime); + SetSecondaryScrollingType(second); + _AKNTRACE_FUNC_EXIT; + } + + +/** +* Sets the movement of the cursor with respect to scrolling when the +* end item in the current row or column, whichever is the primary +* orientation of the data items, is encountered. The movement maybe +* either stop, loop back to same row or column or move onto the +* next logical data item in the sequence. +*/ +EXPORT_C void CAknGrid::SetPrimaryScrollingType(CAknGridView::TScrollingType aScrollingType) + { + __TEST_INVARIANT; + GridView()->SetPrimaryScrollingType(aScrollingType); + } + +/** +* Sets the movement of the cursor with respect to scrolling when the +* end item in the secondary dimension of the grid is encountered. +* The movement maybe either stop, loop back back to same row or column +* or move onto the next logical data item in the sequence. +*/ +EXPORT_C void CAknGrid::SetSecondaryScrollingType(CAknGridView::TScrollingType aSecondaryScrolling) + { + __TEST_INVARIANT; + GridView()->SetSecondaryScrollingType(aSecondaryScrolling); + } + +/** +* Returns the current grid data index. +* Returns -1 if the grid is empty. +*/ +EXPORT_C TInt CAknGrid::CurrentDataIndex() const + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + if (GridModel()->NumberOfData() < 1) + { + _AKNTRACE( "no data in model, return -1" ); + _AKNTRACE_FUNC_EXIT; + return -1; + } + TInt startOffset = GridModel()->IndexOfFirstDataItem(); + _AKNTRACE_FUNC_EXIT; + return (GridView()->CurrentDataIndex() - startOffset); + } + +/** +* Moves the cursor to the required grid data index. +*/ +EXPORT_C void CAknGrid::SetCurrentDataIndex(TInt aDataIndex) + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + _AKNTRACE( "[%s] aDataIndex = %d", + __FUNCTION__, aDataIndex ); + TInt startOffset = GridModel()->IndexOfFirstDataItem(); + + if (startOffset == -1) + { + _AKNTRACE_FUNC_EXIT; + return; // there is no data yet + } + TInt newIndex = aDataIndex + startOffset; + + GridView()->SetCurrentDataIndex(newIndex); + UpdateScrollBarThumbs(); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Sets the starting position of the data within the grid. +*

+* Note: a blank page cannot be accessed (since cannot move into empty cells) +* so a totally blank page is the same as if the page never existed since +* the user cannot scroll into it. For this reason it is suggested that +* the start position be no more than one page into the grid. +*/ +EXPORT_C void CAknGrid::SetStartPositionL(TPoint aGridStartPosition) + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + + TInt dataIndex; + CAknGridView* gridView = GridView(); + gridView->DataIndexFromLogicalPos(dataIndex,aGridStartPosition.iY,aGridStartPosition.iX); + + // set the number of blank start cells + GridModel()->SetStartCells(dataIndex); + + // need to check grid size + CalcGridSizeL(); + + // check current item position + gridView->SetCurrentDataIndex(dataIndex); + iCurrentIsValid = ETrue; + _AKNTRACE_FUNC_EXIT; + } + +/** +* Gives the data index at the grid position given. +* The position must be given with respect to the top left corner +* of the grid. +* An index value of -1 is given if the grid position given is +* invalid. +*/ +EXPORT_C TInt CAknGrid::IndexOfPosition(TPoint aGridPosition) const + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + + TInt indexValue = -1; + + + CAknGridView* gridView = GridView(); + TSize gridSize = gridView->GridCellDimensions(); + + if ((aGridPosition.iY >= 0)&& + (aGridPosition.iX >= 0)&& + (aGridPosition.iX < gridSize.iWidth)&& + (aGridPosition.iY < gridSize.iHeight)) + { + // grid position is valid + gridView->DataIndexFromLogicalPos(indexValue, aGridPosition.iY, aGridPosition.iX); + + indexValue -= GridModel()->IndexOfFirstDataItem(); + } + + _AKNTRACE_FUNC_EXIT; + return indexValue; + } + +/** +* Gives the position of the data item required. +* The logical position is given with respect to the top left +* hand corner of the grid. +* A position of (-1,-1) is given if the data item is not valid. +*/ +EXPORT_C TPoint CAknGrid::PositionAtIndex(TInt aItemIndex) const + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + _AKNTRACE(" [%s] aItemIndex = %d", + __FUNCTION__, aItemIndex ); + + TPoint gridPosition(-1,-1); + + CAknGridM* gridModel = GridModel(); + + TInt startOffset = gridModel->IndexOfFirstDataItem(); + TInt newIndex = aItemIndex + startOffset; + + if (ItemExists(newIndex)) + { + if (gridModel->IndexContainsData(newIndex)) + { + GridView()-> + LogicalPosFromDataIndex(newIndex, gridPosition.iY, gridPosition.iX); + } + } + + _AKNTRACE_FUNC_EXIT; + return gridPosition; + } + + +EXPORT_C CListBoxView* CAknGrid::MakeViewClassInstanceL() + { + return (new(ELeave) CAknGridView); + } + +/** +* Sets the column width of the grid. +* Column width cannot be set in a horizontal grid since the number +* of columns in the grid is defined by the initialising call to +* SetLayoutL. +* The column width cannot be larger than the width of the viewing +* rectangle. +*/ +EXPORT_C void CAknGrid::SetColumnWidth(TInt aColumnWidth) + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + _AKNTRACE(" [%s] aColumnWidth = %d", + __FUNCTION__, aColumnWidth ); + + if (aColumnWidth < 1) + return; + + TInt currentDataIndex = 0; + + CAknGridView* gridView = GridView(); + if (iCurrentIsValid) + { + // remember current position + currentDataIndex = gridView->CurrentDataIndex(); + } + + // hold the users value in case needed in the method + // HandleItemAdditionL + iMinColWidth = aColumnWidth; + + gridView->SetColumnWidth(aColumnWidth); + + // check grid orientated to show current focus (item height + // change may have moved the focus to a new page) + if (iCurrentIsValid) + gridView->SetCurrentDataIndex(currentDataIndex); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Sets the row height of the grid. +* Row height cannot be set in a vertical grid since the number +* of rows in the grid is defined by the initialising call to +* SetLayoutL. +* The row height cannot be larger than the height of the viewing +* rectangle. +*/ +EXPORT_C void CAknGrid::SetItemHeightL(TInt aHeight) + { + _AKNTRACE_FUNC_ENTER; + __TEST_INVARIANT; + _AKNTRACE(" [%s] aHeight = %d", + __FUNCTION__, aHeight ); + + if (aHeight < 1) + return; + + TInt currentDataIndex = 0; + + CAknGridView* gridView = GridView(); + if (iCurrentIsValid) + { + // remember current position + currentDataIndex = gridView->CurrentDataIndex(); + } + + // this ensures that if user changes the item height then the + // grid details will change in line as well + iItemHeight = aHeight; + + gridView->SetItemHeight(aHeight); + + CalcGridSizeL(); + + // check grid orientated to show current focus (item height + // change may have moved the focus to a new page) + if (iCurrentIsValid) + gridView->SetCurrentDataIndex(currentDataIndex); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Processes the user key events or passes them onto the underlying +* listbox code. +*/ +EXPORT_C TKeyResponse CAknGrid::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) + { + _AKNTRACE_FUNC_ENTER; + // SERIES60 LAF + CListBoxView::TSelectionMode selectionMode = CListBoxView::ENoSelection; + + TBool shiftKeyPressed = (aKeyEvent.iModifiers & EModifierShift); + if (iListBoxFlags & EMultipleSelection) + { + if (shiftKeyPressed && iListBoxFlags & EShiftEnterMarks) + { + View()->SetAnchor(View()->CurrentItemIndex()); + selectionMode = CListBoxView::EDisjointMarkSelection; + } + else + selectionMode = CListBoxView::ENoSelection; + } + + // With single click first key event enables highlight + if ( iExtension->iSingleClickEnabled + && ItemDrawer()->Flags() + & CListItemDrawer::ESingleClickDisabledHighlight ) + { + if ( aKeyEvent.iCode == EKeyUpArrow || + aKeyEvent.iCode == EKeyDownArrow || + aKeyEvent.iCode == EKeyLeftArrow || + aKeyEvent.iCode == EKeyRightArrow || + aKeyEvent.iCode == EKeyEnter || + aKeyEvent.iCode == EKeyOK ) + { + _AKNTRACE_FUNC_EXIT; + return CEikListBox::OfferKeyEventL( aKeyEvent, aType ); + } + } + + switch (aKeyEvent.iCode) + { + case EKeyUpArrow: + iView->MoveCursorL(CListBoxView::ECursorPreviousItem, selectionMode); + ClearMatchBuffer(); + _AKNTRACE( "EKeyUpArrow" ); + break; + case EKeyDownArrow: + iView->MoveCursorL(CListBoxView::ECursorNextItem, selectionMode); + ClearMatchBuffer(); + _AKNTRACE( "EKeyDownArrow" ); + break; + + case EKeyPrevious: + { + const TBool disableRedraw = aKeyEvent.iRepeats; + TBool redrawDisabled = iView->RedrawDisabled(); + if ( disableRedraw ) + { + iView->SetDisableRedraw(ETrue); + } + + ((CAknGridView*)iView)-> + MoveCursorWithRepeatsL( EFalse, selectionMode, 1 + aKeyEvent.iRepeats ); + ClearMatchBuffer(); + + if ( disableRedraw ) + { + iView->SetDisableRedraw(redrawDisabled); + if ( !redrawDisabled ) + { + DrawNow(); + } + } + } + _AKNTRACE( "EKeyPrevious" ); + break; + + case EKeyLeftArrow: + iView->MoveCursorL(CListBoxView::ECursorPreviousColumn, selectionMode); + ClearMatchBuffer(); + _AKNTRACE( "EKeyLeftArrow" ); + break; + + case EKeyNext: + { + const TBool disableRedraw = aKeyEvent.iRepeats; + TBool redrawDisabled = iView->RedrawDisabled(); + if ( disableRedraw ) + { + iView->SetDisableRedraw(ETrue); + } + + ((CAknGridView*)iView)-> + MoveCursorWithRepeatsL( ETrue, selectionMode, 1 + aKeyEvent.iRepeats ); + ClearMatchBuffer(); + + if ( disableRedraw ) + { + iView->SetDisableRedraw(redrawDisabled); + if ( !redrawDisabled ) + { + DrawNow(); + } + } + } + _AKNTRACE( "EKeyNext" ); + break; + + case EKeyRightArrow: + iView->MoveCursorL(CListBoxView::ECursorNextColumn, selectionMode); + ClearMatchBuffer(); + _AKNTRACE( "EKeyRightArrow" ); + break; + +#if defined(_DEBUG) // only needed when debuging + case EKeyPageUp: + iView->MoveCursorL(CListBoxView::ECursorPreviousPage, selectionMode); + ClearMatchBuffer(); + break; + case EKeyPageDown: + iView->MoveCursorL(CListBoxView::ECursorNextPage, selectionMode); + ClearMatchBuffer(); + break; + case EKeyHome: + iView->MoveCursorL(CListBoxView::ECursorFirstItem, selectionMode); + ClearMatchBuffer(); + break; + case EKeyEnd: + iView->MoveCursorL(CListBoxView::ECursorLastItem, selectionMode); + ClearMatchBuffer(); + break; +#endif// end of debug code + default: + _AKNTRACE_FUNC_EXIT; + return CEikListBox::OfferKeyEventL(aKeyEvent,aType); + } + + UpdateScrollBarThumbs(); + + // matcher cursor code maybe needed here if matcher cursors + // supported in future versions, refer to CEikListBox::OfferKeyEventL + + if (iListBoxFlags & EStateChanged) + { + ReportEventL(MCoeControlObserver::EEventStateChanged); + iListBoxFlags &= (~EStateChanged); + } + + _AKNTRACE_FUNC_EXIT; + return EKeyWasConsumed; + } +/** +* @return Model +*/ +EXPORT_C CTextListBoxModel* CAknGrid::Model() const + { + return STATIC_CAST(CTextListBoxModel*,iModel); + } + +/** +* Sets the viewable rect +*/ +EXPORT_C void CAknGrid::SetRect(const TRect& aRect) + { + _AKNTRACE_FUNC_ENTER; + + CCoeControl::SetRect(aRect); + + TRect rect(aRect); + rect.SetRect(rect.iTl.iX + ListBoxMargins().iLeft, rect.iTl.iY + ListBoxMargins().iTop, + rect.iBr.iX - ListBoxMargins().iRight, rect.iBr.iY - ListBoxMargins().iBottom); + _AKNTRACE( "The rect of grid are ( %d, %d ) ( %d, %d )", + rect.iTl.iX, rect.iTl.iY, + rect.iBr.iX, rect.iBr.iY ); + iView->SetViewRect(rect); + + // basically, this is redundant call, but leaving it out breaks at + // least camcorder's colorburstgrid, because SizeChanged() trusts + // margin values + TRAP_IGNORE( HandleViewRectSizeChangeL() ); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Called when the view rect changes size +*/ +EXPORT_C void CAknGrid::HandleViewRectSizeChangeL() + { + _AKNTRACE_FUNC_ENTER; + iView->CalcBottomItemIndex(); + TInt oldTopItemIndex = TopItemIndex();// store old top item index + TInt newTopItemIndex = oldTopItemIndex;// set new same as old + + TInt currentItemIndex = CurrentItemIndex();// get the current item index + + if (currentItemIndex < 0)// check valid + { + _AKNTRACE_FUNC_EXIT; + return; + } + + iNumOfRowsInView = Max(1, iNumOfRowsInView);// make iNumOfRowsInView > 1 + iNumOfColsInView = Max(1, iNumOfColsInView);// make iNumOfColsInView > 1 + + if ( iOrientationFlags.IsClear( EGridOrientationVertical )&& + ( AknLayoutUtils::LayoutMirrored() + ? iHorizontalFlags.IsClear( EGridHorizontalLeftToRight ) + : iHorizontalFlags.IsSet( EGridHorizontalLeftToRight ) ) && + iVerticalFlags.IsSet(EGridVerticalTopToBottom) ) + { + // CAknAppStyleGrid uses this combination of flags + AdjustTopItemIndex(); + } + else + { + // this version is likely to contain bugs. + if (currentItemIndex != oldTopItemIndex) + { + TInt colIndexOfTargetItem = currentItemIndex / iNumOfRowsInView;// iNumOfRowsInView != 0 + TInt adjustment = newTopItemIndex % iNumOfRowsInView;// iNumOfRowsInView != 0 + if (adjustment != 0) + { + // adjust newTopItemIndex till it refers to the index of an item at the top of a column + newTopItemIndex -= adjustment; + } + TInt newBottomItemIndex = newTopItemIndex + (iNumOfColsInView * iNumOfRowsInView) - 1; + if (currentItemIndex < newTopItemIndex) + newTopItemIndex = colIndexOfTargetItem * iNumOfRowsInView; + else if (currentItemIndex > newBottomItemIndex) + { + TInt colIndexOfNewBottomItem = colIndexOfTargetItem; + TInt colIndexOfNewTopItem = colIndexOfNewBottomItem - (iNumOfColsInView - 1); + newTopItemIndex = colIndexOfNewTopItem * iNumOfRowsInView; + } + } + else if ((newTopItemIndex != 0) && (iNumOfRowsInView != 0)) + { + TInt adjustment = newTopItemIndex % iNumOfRowsInView;// iNumOfRowsInView != 0 + if (adjustment != 0) + {// adjust newTopItemIndex till it refers to the index of an item at the top of a column + newTopItemIndex -= adjustment; + } + } + SetTopItemIndex(newTopItemIndex); + } + + iView->CalcDataWidth(); + UpdateScrollBarsL(); + iView->CalcBottomItemIndex(); + _AKNTRACE_FUNC_EXIT; + } + +/** +* Set the empty grid text +*/ +EXPORT_C void CAknGrid::SetEmptyGridTextL(const TDesC& aText) + { + GridView()->SetListEmptyTextL(aText); + } + +///////////////////////////////////////////////////// +///////////////////////////////////////////////////// + +EXPORT_C void CAknGrid::SetTopItemIndex(TInt aItemIndex) const + { + __ASSERT_DEBUG(iView, Panic(EAknPanicGridNoView)); + iView->SetTopItemIndex(aItemIndex); + } + +EXPORT_C void CAknGrid::HandleResourceChange(TInt aType) + { + _AKNTRACE_FUNC_ENTER; + // Need to do this to set up the scroll bar model + TRAP_IGNORE( UpdateScrollBarsL() ); + + if (aType==KEikDynamicLayoutVariantSwitch) + { + CAknGridView* gridView = GridView(); + + gridView->SetItemOffsetInPixels( 0 ); + + TSize sizeOfItems; + sizeOfItems.iWidth = ( Rect().iBr.iX - Rect().iTl.iX ) / iNumOfColsInView; + sizeOfItems.iHeight = ( Rect().iBr.iY - Rect().iTl.iY ) / iNumOfRowsInView; + + CAknGridView::SGrid gridDetails; + gridDetails.iGridDimensions = gridView->GridCellDimensions(); + gridDetails.iPageSize = iNumOfColsInView*iNumOfRowsInView; + + gridDetails.iColsInView = iNumOfColsInView; + gridDetails.iRowsInView = iNumOfRowsInView; + gridDetails.iSizeBetweenItems = iSpaceBetweenItems; + //gridDetails.iSizeOfItems = gridView->ItemSize(); + gridDetails.iSizeOfItems = sizeOfItems; + + gridView->SetColumnWidth(gridDetails.iSizeOfItems.iWidth); + TRAP_IGNORE( SetItemHeightL(gridDetails.iSizeOfItems.iHeight) ); + + gridDetails.iGridFlags = 0; + if (iOrientationFlags.IsSet(EGridOrientationVertical)) + gridDetails.iGridFlags |= CAknGridView::EPrimaryIsVertical; + if (iVerticalFlags.IsSet(EGridVerticalTopToBottom)) + gridDetails.iGridFlags |= CAknGridView::ETopToBottom; + + TBool isMirrored = AknLayoutUtils::LayoutMirrored(); + if (isMirrored) + { + if (iHorizontalFlags.IsSet(EGridHorizontalAntiWritingDirection) + || iHorizontalFlags.IsSet(EGridHorizontalLeftToRight)) + gridDetails.iGridFlags |= CAknGridView::ELeftToRight; + } + else + { + if (iHorizontalFlags.IsSet(EGridHorizontalWritingDirection) + || iHorizontalFlags.IsSet(EGridHorizontalLeftToRight)) + gridDetails.iGridFlags |= CAknGridView::ELeftToRight; + } + gridView->SetGridDetails(gridDetails); + + SetItemsInSingleLine( gridDetails.iColsInView ); + } + + CEikListBox::HandleResourceChange(aType); + + TRAP_IGNORE( ItemDrawer()->FormattedCellData()->SetupSkinContextL()); + // Data extension has animations which will change when skin changes. + ItemDrawer()->FormattedCellData()->HandleResourceChange( aType ); + + // Need to do this to set up the scroll bar model + TRAP_IGNORE( UpdateScrollBarsL() ); + _AKNTRACE_FUNC_EXIT; + } + + +EXPORT_C void CAknGrid::FocusChanged( TDrawNow aDrawNow ) + { + _AKNTRACE_FUNC_ENTER; + CEikListBox::FocusChanged( aDrawNow ); + + // Grid data needs focus change information to control animations. + if( IsFocused() ) + { + ItemDrawer()->FormattedCellData()->FocusGained(); + } + else + { + ItemDrawer()->FormattedCellData()->FocusLost(); + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C TInt CAknGrid::ColumnWidth() const + { + __ASSERT_DEBUG(iView, Panic(EAknPanicGridNoView)); + return ((CAknGridView*)iView)->ColumnWidth(); + } + +EXPORT_C TInt CAknGrid::HorizontalNudgeValue() const + { + return 1; // scroll horizontal by one column when the left/right scroll arrows (i.e. the nudge buttons) are tapped + } + +EXPORT_C TInt CAknGrid::HorizScrollGranularityInPixels() const + { + return ColumnWidth(); // horiz scrollbar model set in columns for snaking list box + } + +EXPORT_C void CAknGrid::AdjustTopItemIndex() const + { + + _AKNTRACE_FUNC_ENTER; + /* + * make sure, that topitemindex points to topmost leftmost visible item + * This hackish solution is only valid for appstyle grid & similar grids + */ + if ( iOrientationFlags.IsClear( EGridOrientationVertical )&& + ( AknLayoutUtils::LayoutMirrored() + ? iHorizontalFlags.IsClear( EGridHorizontalLeftToRight ) + : iHorizontalFlags.IsSet( EGridHorizontalLeftToRight ) ) && + iVerticalFlags.IsSet(EGridVerticalTopToBottom) ) + { + if ( !iNumOfColsInView ) + { // just in case + _AKNTRACE_FUNC_EXIT; + return; + } + + TPoint topIndexPoint = iView->ItemPos( TopItemIndex() ); + TInt bottomOrdinate = topIndexPoint.iY + iItemHeight; + if ( TopItemIndex() % iNumOfColsInView == 0 + && ( bottomOrdinate > 0 + && bottomOrdinate <= ( iView->ViewRect().iTl.iY + iItemHeight ) ) + && iView->ViewRect().Contains( iView->ItemPos( CurrentItemIndex() ) ) ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + // get row of topmost item relative to the whole grid - 0 based indexing + TInt topRow = TopItemIndex() / iNumOfColsInView; + + // get row of current item relative to the whole grid - 0 based indexing + TInt currRow = CurrentItemIndex() / iNumOfColsInView; + + // top item will be col 0 in topmost row - find out new top item's row + TInt newTopRow( topRow ); // prefer minimum adjustment + TInt reminder = iView->ViewRect().Height() % ( iItemHeight + iSpaceBetweenItems.iHeight ); + TInt rowsFitInView = iNumOfRowsInView; + if ( reminder > 0 ) + { + rowsFitInView ++; + } + newTopRow = currRow - rowsFitInView + 1; + newTopRow = Max( 0, newTopRow ); + + // and calculate new top item index + TInt topItemIndex = newTopRow * iNumOfColsInView ; + iView->SetItemOffsetInPixels(0); + SetTopItemIndex(topItemIndex); + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::HandleDragEventL(TPoint aPointerPos) + { + _AKNTRACE_FUNC_ENTER; + // No drag event handling if kinetic scrolling is enabled + if ( !ScrollingDisabled() ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + if ( AknLayoutUtils::PenEnabled() ) + { + if ( !(iExtension->iFlags & EAknGridStateButton1DownInGrid) ) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + CAknGridView* gridView = GridView(); + TRect maxRect(TPoint( KMinTInt, KMinTInt ), TPoint(KMaxTInt, KMaxTInt)); + TRect ignoreDragRect; + TRect viewRect(gridView->ViewRect()); + TInt itemIndex = KEikListBoxInvalidIndex ; + TBool pointerIsOverAnItem = gridView->XYPosToItemIndex(aPointerPos, itemIndex); + // SERIES60 LAF + CListBoxView::TSelectionMode selectionMode = CListBoxView::ENoSelection; + // CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection; + // END OF SERIES60 LAF + TInt speed = iExtension->GetScrollingSpeed( pointerIsOverAnItem, itemIndex, + *gridView, aPointerPos ); + + TInt oldCurrentItemIndex = CurrentItemIndex(); + TRect currentItemRect(gridView->ItemPos(oldCurrentItemIndex), gridView->ItemSize(oldCurrentItemIndex)); + TInt numOfRows = Max(GridView()->GridCellDimensions().iHeight,1); + const TInt placesInGrid = numOfRows * iNumOfColsInView; + TBool currItemIsInLastRow = ((placesInGrid - iNumOfColsInView) <= itemIndex) && (placesInGrid > itemIndex); + TBool currItemIsInFirstRow = itemIndex >= iNumOfColsInView; + + TRect visibleItemsRect(viewRect.iTl, + TPoint(gridView->ItemSize(itemIndex).iWidth * iNumOfColsInView, + gridView->ItemSize(itemIndex).iHeight * iNumOfRowsInView)); + + if ( speed != 0 ) + { + TInt itemCountInRow = iNumOfColsInView; + TInt dest = itemIndex + speed * itemCountInRow; + TInt offset = 0; + TInt newTopIndex = dest / itemCountInRow * itemCountInRow; + TInt upperBound = iModel->NumberOfItems() - 1; + + if ( speed > 0 ) + { + + if ( gridView->ActualDataIndex( dest ) <= upperBound ) + { + offset = -itemCountInRow; + } + else + { + dest = gridView->ListBoxIndex( upperBound ); + offset = itemIndex - dest; // Don't make focus jump. + } + newTopIndex -= ( iNumOfRowsInView - 1) * itemCountInRow ; + } + else if ( speed < 0 ) + { + if ( dest > 0 ) + { + offset = itemCountInRow; + } + else + { + offset = itemIndex - dest; + newTopIndex = 0; + } + } + + if ((iListBoxFlags & ES60StyleMarkable) && + ( (EventModifiers() & EModifierShift) || + (EventModifiers() & EModifierCtrl) )) + { + selectionMode = CListBoxView::EPenMultiselection; + iListBoxFlags |= EStateChanged; + } + TInt oldtop = gridView->TopItemIndex(); + if ( !gridView->ItemIsVisible( dest )) + { + gridView->VScrollTo( newTopIndex ); + UpdateScrollBarThumbs(); + if ( pointerIsOverAnItem ) + { + Window().RequestPointerRepeatEvent( + KEikListBoxPointerRepeatInterval, viewRect ); + } + } + itemIndex = dest + offset; + } + + + // if pointer is over some new item. + if ( pointerIsOverAnItem ) + { +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( + iView->ItemDrawer()->Gc() ); + if ( transApi && !transApi->EffectsDisabled() ) + { + transApi->SetMoveType( itemIndex < oldCurrentItemIndex ? + MAknListBoxTfxInternal::EListMoveUp : + MAknListBoxTfxInternal::EListMoveDown ); + } +#endif + if ((iListBoxFlags & ES60StyleMarkable) && + ( (EventModifiers() & EModifierShift) || + (EventModifiers() & EModifierCtrl) )) + { + selectionMode = CListBoxView::EPenMultiselection; + iListBoxFlags |= EStateChanged; + } + + gridView->MoveToItemIndexL(itemIndex, selectionMode); + } + else if ((aPointerPos.iY < visibleItemsRect.iTl.iY) && + (aPointerPos.iX > visibleItemsRect.iTl.iX) && + (aPointerPos.iX < visibleItemsRect.iBr.iX) && + !currItemIsInFirstRow) // Dragged upwards from the grid. + { + ignoreDragRect = TRect(maxRect.iTl, TPoint(maxRect.iBr.iX, visibleItemsRect.iTl.iY)); + + MoveToNextOrPreviousItemL(aPointerPos); + + if ( (iListBoxFlags & ES60StyleMarkable) && + ( (EventModifiers() & EModifierShift) || + (EventModifiers() & EModifierCtrl) )) + { + iView->UpdateSelectionL(CListBoxView::EPenMultiselection); + iListBoxFlags |= EStateChanged; + } + + UpdateScrollBarThumbs(); + + Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect); + } + else if (aPointerPos.iY > visibleItemsRect.iBr.iY && + (aPointerPos.iX > visibleItemsRect.iTl.iX) && + (aPointerPos.iX < visibleItemsRect.iBr.iX) && + !currItemIsInLastRow) // Dragged downwards from the grid. + { + ignoreDragRect = TRect(TPoint( maxRect.iTl.iX, visibleItemsRect.iBr.iY), maxRect.iBr ); + + MoveToNextOrPreviousItemL(aPointerPos); + + if ( (iListBoxFlags & ES60StyleMarkable) && + ( (EventModifiers() & EModifierShift) || + (EventModifiers() & EModifierCtrl) )) + { + iView->UpdateSelectionL(CListBoxView::EPenMultiselection); + iListBoxFlags |= EStateChanged; + } + + UpdateScrollBarThumbs(); + + Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect); + } + + if (CurrentItemIndex() != oldCurrentItemIndex) + { + ReportListBoxEventL(MEikListBoxObserver::EEventItemDraggingActioned); + iListBoxFlags |= EStateChanged; + if (IsMatchBuffer()) + { + ClearMatchBuffer(); + DrawMatcherCursor(); + } + } + } + else + { + if (!(iListBoxFlags & ELeftDownInViewRect)) + { + _AKNTRACE_FUNC_EXIT; + return; + } + + CAknGridView* gridView = GridView(); + const TInt clickableBorder = 20; // distance in pixels of area around grid that can see pointer events. + TRect ignoreDragRect(TPoint(aPointerPos.iX-clickableBorder, aPointerPos.iY-clickableBorder), TPoint(aPointerPos.iX+clickableBorder, aPointerPos.iY+clickableBorder)); + TRect viewRect(gridView->ViewRect()); + TInt itemIndex; + TBool pointerIsOverAnItem = gridView->XYPosToItemIndex(aPointerPos, itemIndex); + // SERIES60 LAF + CListBoxView::TSelectionMode selectionMode = CListBoxView::ENoSelection; + // CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection; + // END OF SERIES60 LAF + + TInt oldCurrentItemIndex = CurrentItemIndex(); + TRect currentItemRect(gridView->ItemPos(oldCurrentItemIndex), gridView->ItemSize(oldCurrentItemIndex)); + if (pointerIsOverAnItem) + { + gridView->MoveToItemIndexL(itemIndex, selectionMode); + } + else if ((aPointerPos.iX < viewRect.iTl.iX) || (aPointerPos.iX > viewRect.iBr.iX)) + { + // drag event occurred outside the listbox's viewRect + if (aPointerPos.iX < viewRect.iTl.iX) + gridView->MoveCursorL(CListBoxView::ECursorPreviousColumn, selectionMode); + else if (aPointerPos.iX > viewRect.iBr.iX) + gridView->MoveCursorL(CListBoxView::ECursorNextColumn, selectionMode); + MoveToNextOrPreviousItemL(aPointerPos); + UpdateScrollBarThumbs(); + Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect); + } + else + { + // find item nearest to the pointer pos and make that the current item + if (viewRect.Contains(aPointerPos)) + { + } + else + { + if (aPointerPos.iX > currentItemRect.iBr.iX) + gridView->MoveCursorL(CListBoxView::ECursorNextColumn, selectionMode); + else if (aPointerPos.iX < currentItemRect.iTl.iX) + gridView->MoveCursorL(CListBoxView::ECursorPreviousColumn, selectionMode); + MoveToNextOrPreviousItemL(aPointerPos); + UpdateScrollBarThumbs(); + Window().RequestPointerRepeatEvent(KEikListBoxPointerRepeatInterval, ignoreDragRect); + } + } + if (CurrentItemIndex() != oldCurrentItemIndex) + { + iListBoxFlags |= EStateChanged; + if (IsMatchBuffer()) + { + ClearMatchBuffer(); + DrawMatcherCursor(); + } + } + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::RestoreClientRectFromViewRect(TRect& aClientRect) const + { + _AKNTRACE_FUNC_ENTER; + aClientRect=iView->ViewRect(); + aClientRect.SetRect(aClientRect.iTl.iX - ListBoxMargins().iLeft, aClientRect.iTl.iY - ListBoxMargins().iTop, + aClientRect.iBr.iX + ListBoxMargins().iRight, aClientRect.iBr.iY + ListBoxMargins().iBottom); + if (!ViewRectHeightAdjustment()) + { + _AKNTRACE_FUNC_EXIT; + return; + } + aClientRect.iBr.iY += ViewRectHeightAdjustment(); + _AKNTRACE( "The rect of grid are ( %d, %d ) ( %d, %d )", + aClientRect.iTl.iX, aClientRect.iTl.iY, + aClientRect.iBr.iX, aClientRect.iBr.iY ); + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C TInt CAknGrid::AdjustRectHeightToWholeNumberOfItems(TRect& aRect) const + { + _AKNTRACE_FUNC_ENTER; + TInt remainder = aRect.Height() % (iItemHeight + iSpaceBetweenItems.iHeight); + if (remainder >= iItemHeight) + remainder -= iItemHeight; + if (remainder != 0) + aRect.iBr.iY -= remainder; + _AKNTRACE_FUNC_EXIT; + return remainder; + } + +EXPORT_C void CAknGrid::MoveToNextOrPreviousItemL(TPoint aPointerPos) + { + _AKNTRACE_FUNC_ENTER; + // SERIES60 LAF + CListBoxView::TSelectionMode selectionMode = CListBoxView::ENoSelection; +// CListBoxView::TSelectionMode selectionMode = (iListBoxFlags & EMultipleSelection) ? CListBoxView::EContiguousSelection : CListBoxView::ESingleSelection; + // END OF SERIES60 LAF + + TInt cix = CurrentItemIndex(); + TRect currentItemRect(iView->ItemPos(cix), iView->ItemSize(cix)); + TInt numOfRows = Max(GridView()->GridCellDimensions().iHeight,1); + + TBool currItemIsInLastRow; + TBool currItemIsInFirstRow; + + if ( AknLayoutUtils::PenEnabled() ) + { + const TInt placesInGrid = numOfRows * iNumOfColsInView; + + // calculate is the item in first or last row. + currItemIsInLastRow = ((placesInGrid - iNumOfColsInView) <= cix) && (placesInGrid > cix); + currItemIsInFirstRow = (cix >= 0 && cix < iNumOfColsInView); + } + else + { + currItemIsInLastRow = ((cix % numOfRows) == (numOfRows-1)); + currItemIsInFirstRow = ((cix % numOfRows) == 0); + } + + TBool currItemIsLastItem = (cix == (iModel->NumberOfItems()-1)); + + if ((aPointerPos.iY > currentItemRect.iBr.iY) && (! (currItemIsInLastRow || currItemIsLastItem))) + { + iView->MoveCursorL(CListBoxView::ECursorNextItem, selectionMode); + } + else if ((aPointerPos.iY < currentItemRect.iTl.iY) && (! currItemIsInFirstRow)) + { + iView->MoveCursorL(CListBoxView::ECursorPreviousItem, selectionMode); + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::UpdateScrollBarsL() + { + _AKNTRACE_FUNC_ENTER; + if (!iSBFrame) + { + _AKNTRACE_FUNC_EXIT; + return; + } + TEikScrollBarModel hSbarModel; + TEikScrollBarModel vSbarModel; + CAknGridView* gridView = GridView(); + TRect rect=gridView->ViewRect(); + if (!(iListBoxFlags & EScrollBarSizeExcluded)) + { + // Ignore scrollbars presence to set the model, Scrollbar Frame will change it as required + rect = iBorder.InnerRect(Rect()); + rect.SetRect(rect.iTl.iX + ListBoxMargins().iLeft, rect.iTl.iY + ListBoxMargins().iTop, + rect.iBr.iX - ListBoxMargins().iRight, rect.iBr.iY - ListBoxMargins().iBottom); + AdjustRectHeightToWholeNumberOfItems(rect); + // rect is now viewRect when ignoring scrollbars + } + if (iSBFrame->VScrollBarVisibility()!=CEikScrollBarFrame::EOff) + { + TInt currentIndex = CurrentItemIndex(); + if (currentIndex < 0) + { + _AKNTRACE_FUNC_EXIT; + return; // current item is not defined + } + TInt row = 0; + TInt col = 0; + gridView->LogicalPosFromListBoxIndex(currentIndex, row, col); + row *= iView->ItemHeight(); + row -= iView->ItemOffsetInPixels(); + + TSize gridSize = gridView->GridCellDimensions(); + gridSize.iHeight = Max(gridSize.iHeight,1);//check gridSize != 0 + + vSbarModel.iThumbPosition = row; + // EHXA-7AQ8N4. Only set it to 0 can make scrollbar empty. + vSbarModel.iScrollSpan = GridModel()->NumberOfItems() >0 ? + gridSize.iHeight : 0; + vSbarModel.iThumbSpan = gridView->NumberOfRowsInView(); + vSbarModel.iScrollSpan = GridModel()->NumberOfItems() >0 ? + gridSize.iHeight*iView->ItemHeight() : 0; + vSbarModel.iThumbSpan = rect.Height(); + + if (iSBFrame->TypeOfVScrollBar() == CEikScrollBarFrame::EDoubleSpan) + { + TInt topRow = 0; + TInt topCol = 0; + gridView->LogicalPosFromListBoxIndex(TopItemIndex(), topRow, topCol); + topRow *= iView->ItemHeight(); + topRow -= iView->ItemOffsetInPixels(); + vSbarModel.iThumbPosition = topRow; + } + if (vSbarModel.iScrollSpan-vSbarModel.iThumbPositionMoveToItemIndexL(currentIndex,CListBoxView::ENoSelection); // force a scroll if neccessary + } + } + if (iSBFrame->ScrollBarVisibility(CEikScrollBar::EHorizontal)!=CEikScrollBarFrame::EOff) + { + GridView()->CalcDataWidth(); + hSbarModel.iThumbPosition = gridView->HScrollOffset(); + hSbarModel.iScrollSpan = gridView->DataWidth(); + } + + if (iSBFrame->TypeOfVScrollBar() == CEikScrollBarFrame::EDoubleSpan) + { + //same scrollbar data within landscape & portraid + TInt varietyIndex = Layout_Meta_Data::IsLandscapeOrientation() ? 1: 0; + TAknWindowComponentLayout layout = TAknWindowComponentLayout::Compose( + AknLayoutScalable_Avkon::listscroll_app_pane(0), + AknLayoutScalable_Avkon::scroll_pane_cp15(varietyIndex)); + + CEikAppUi* appUi = iEikonEnv->EikAppUi(); + TRect clientRect = appUi->ClientRect(); + TRect mainPaneRect; + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPaneRect); + + TRect scrollBarParent = TRect( TPoint(0, 0), mainPaneRect.Size()); + AknLayoutUtils::LayoutVerticalScrollBar(iSBFrame, scrollBarParent, layout.LayoutLine()); + + + TRect inclusiveRect=Rect(); + + TEikScrollBarFrameLayout layoutSB; + layoutSB.SetClientMargin(0); + layoutSB.SetInclusiveMargin(0); + layoutSB.iTilingMode=TEikScrollBarFrameLayout::EInclusiveRectConstant; + + iSBFrame->Tile(&hSbarModel, &vSbarModel ); + } + else + { + TRect clientRect; + RestoreClientRectFromViewRect(clientRect); + TRect inclusiveRect=Rect(); + TEikScrollBarFrameLayout layout; + CreateScrollBarFrameLayout(layout); + TBool sizeChanged=iSBFrame->TileL(&hSbarModel, &vSbarModel, clientRect, inclusiveRect, layout); + if (!sizeChanged) + { + _AKNTRACE_FUNC_EXIT; + return; + } + // else size of client/inclusive rect has changed + if (layout.iTilingMode==TEikScrollBarFrameLayout::EClientRectConstant) + SetSizeWithoutNotification(inclusiveRect.Size()); + else + { + SetViewRectFromClientRect(clientRect); + ClearMargins(); + } + } + AdjustTopItemIndex(); + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C void CAknGrid::UpdateScrollBarThumbs() const + { + _AKNTRACE_FUNC_ENTER; + if (!iSBFrame) + { + _AKNTRACE_FUNC_EXIT; + return; + } + CAknGridView* gridView = GridView(); + TInt currentDataIndex = gridView->CurrentDataIndex(); + TInt row = 0; + TInt col = 0; + gridView->LogicalPosFromDataIndex(currentDataIndex, row, col); + iSBFrame->MoveHorizThumbTo(col); + if (iSBFrame->TypeOfVScrollBar() == CEikScrollBarFrame::EArrowHead) + { + iSBFrame->MoveVertThumbTo(row); + iSBFrame->DrawScrollBarsNow(); + } + else + { + TInt topRow = 0; + TInt topCol = 0; + gridView->LogicalPosFromListBoxIndex(TopItemIndex(), topRow, topCol); + topRow *= iView->ItemHeight(); + topRow -= iView->ItemOffsetInPixels(); + iSBFrame->MoveVertThumbTo(topRow); + } + _AKNTRACE_FUNC_EXIT; + } + +EXPORT_C TInt CAknGrid::CountComponentControls() const + { + if (GridModel()->NumberOfItems()<=0) return 0; + return CEikListBox::CountComponentControls(); + } + + +// debug only invariant function +EXPORT_C void CAknGrid::__DbgTestInvariant() const + { +#if defined(_DEBUG) + TBool invalid = EFalse; + + if ( !iModel ) + { + invalid = ETrue; + } + + if ( !iView ) + { + invalid = ETrue; + } + + if ( invalid ) + { + User::Invariant(); + } +#endif + } + +EXPORT_C TAny* CAknGrid::MListBoxModel_Reserved() + { + return NULL; + } + + +//---------------------------------------------------------------------------- +// Handles scroll events received from the scroll bar. +// Function reads thumb position from model and updates view by these values. +// One thumb step is actually one row in list, not item in list. +//---------------------------------------------------------------------------- +// +EXPORT_C void CAknGrid::HandleScrollEventL( CEikScrollBar* aScrollBar, + TEikScrollEvent aEventType ) + { + _AKNTRACE_FUNC_ENTER; + if ( AknLayoutUtils::PenEnabled() ) + { + // Read values from model. + TInt oldThumbPos = iView->TopItemIndex() / iNumOfColsInView * iView->ItemHeight() - iView->ItemOffsetInPixels(); + TInt newThumbPos = aScrollBar->ThumbPosition(); + TInt pageSize = aScrollBar->Model()->iThumbSpan; + TInt maxThumbPos = aScrollBar->Model()->MaxThumbPos(); + TBool update = EFalse; + + switch ( aEventType & KEikScrollEventBarMask ) + { + case KEikScrollEventFromHBar: + { + switch ( aEventType ) + { + case EEikScrollLeft: + { + newThumbPos -= HorizontalNudgeValue(); + break; + } + + case EEikScrollRight: + { + newThumbPos += HorizontalNudgeValue(); + break; + } + + case EEikScrollPageLeft: + { + newThumbPos -= pageSize; + break; + } + + case EEikScrollPageRight: + { + newThumbPos += pageSize; + break; + } + + case EEikScrollThumbDragVert: + { + // In the case of drag events, the scrollbar + // automatically updates its thumb pos... + SuspendEffects( ETrue ); + break; + } + + case EEikScrollThumbReleaseVert: + { + // In the case of drag events, the scrollbar + // automatically updates its thumb pos... + SuspendEffects( EFalse ); + break; + } + + default: + { + // Do nothing + break; + } + } + + newThumbPos = Max( 0, Min( newThumbPos, maxThumbPos ) ); + + if ( aEventType != EEikScrollThumbDragHoriz ) + { + iView->HScroll( newThumbPos - oldThumbPos ); + aScrollBar->SetModelThumbPosition( iView->HScrollOffset() ); + } + break; + } + + case KEikScrollEventFromVBar: + { + switch ( aEventType ) + { + case EEikScrollUp: + { + if ( oldThumbPos == 0 && (iListBoxFlags & ELoopScrolling) ) + { + // move thumb to downmost site if current is upmost + newThumbPos = maxThumbPos; + update = ETrue; + } + break; + } + + case EEikScrollDown: + { + if ( oldThumbPos == maxThumbPos && (iListBoxFlags & ELoopScrolling) ) + { + // move thumb to upmost site if current is downmost + newThumbPos = 0; + update = ETrue; + } + break; + } + + case EEikScrollThumbDragVert: + { + SuspendEffects( ETrue ); + break; + } + + case EEikScrollThumbReleaseVert: + { + SuspendEffects( EFalse ); + break; + } + + default: + { + // Do nothing + break; + } + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + MAknListBoxTfxInternal* transApi = + CAknListLoader::TfxApiInternal( + iView->ItemDrawer()->Gc() ); + TBool effects = newThumbPos != oldThumbPos && + transApi && !transApi->EffectsDisabled(); + if ( effects ) + { + transApi->SetMoveType( newThumbPos < oldThumbPos ? + MAknListBoxTfxInternal::EListScrollUp : + MAknListBoxTfxInternal::EListScrollDown ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + if ( iExtension && !ScrollingDisabled() ) + { + HandlePhysicsScrollEventL( newThumbPos - oldThumbPos ); + } + else + { + // Do normal scrolling if physics are not enabled. + iView->VScrollTo( newThumbPos/iView->ItemHeight() * iNumOfColsInView ); + } + +#ifdef RD_UI_TRANSITION_EFFECTS_LIST + if ( effects ) + { + transApi->Draw( Rect() ); + } +#endif // RD_UI_TRANSITION_EFFECTS_LIST + + // If event has changed thumb position to different than in + // model do by default, then update scroll bar to + // correct values. + if ( update ) + { + aScrollBar->SetModelThumbPosition( + iView->TopItemIndex() / iNumOfColsInView*iView->ItemHeight() - iView->ItemOffsetInPixels() ); + + UpdateScrollBarThumbs(); + } + else + { + aScrollBar->DrawNow(); + } + } + + default: + { + // Do nothing + break; + } + } + } + else + { + CEikListBox::HandleScrollEventL( aScrollBar, aEventType ); + } + _AKNTRACE_FUNC_EXIT; + } + + +EXPORT_C TTypeUid::Ptr CAknGrid::MopSupplyObject(TTypeUid aId) + { + if ( iExtension && iExtension->iIsFromBaseClass ) + { + iExtension->iIsFromBaseClass = EFalse; + return CEikListBox::MopSupplyObject( aId ); + } + + if ( iExtension && aId.iUid == MAknsControlContext::ETypeId ) + { + MAknsControlContext* cc = NULL; + iExtension->iIsFromBaseClass = ETrue; + if ( !CEikListBox::MopGetObject( cc )) + { + cc = ItemDrawer()->FormattedCellData()->SkinBackgroundContext(); + } + return MAknsControlContext::SupplyMopObject( aId, cc); + } + return CEikListBox::MopSupplyObject( aId ); + }