browserui/browser/FavouritesSrc/BrowserFavouritesListbox.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:31:04 +0100
branchRCL_3
changeset 48 8e6fa1719340
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201032 Kit: 201035

/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* 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:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*      Implementation of CBrowserFavouritesListbox.
*
*
*/


// INCLUDE FILES

#include <aknkeys.h>
#include <EIKCLBD.H>
#include <gulicon.h>
#include <AknIconArray.h>
#include <favouritesdb.h>
#include <BrowserNG.rsg>
#include <ApListItemList.h>
#include <favouritesitem.h>
#include <favouritesitemlist.h>
#include <AknsConstants.h>

#include "BrowserFavouritesListbox.h"
#include "BrowserFavouritesListboxState.h"
#include "BrowserFavouritesListboxModel.h"
#include "BrowserFavouritesListboxView.h"
#include "BrowserFavouritesModel.h"
#include "CommsModel.h"
#include "BrowserFavouritesListboxIconHandler.h"
#include "BrowserFavouritesIconIndexArray.h"
#include "BrowserUtil.h"
#include "BrowserFavouritesListboxCursorObserver.h"
#include "BrowserFavouritesListboxState.h"
#include "BrowserFavouritesListboxItemDrawer.h"
#include "ApiProvider.h"
#include "BrowserAppUi.h"

#include "BrowserFaviconHandler.h"
#include <AknLayout2ScalableDef.h>
#include <aknlayoutscalable_avkon.cdl.h>

#include "eikon.hrh"


// CONSTANTS
/// Granularity of the icon index array.
LOCAL_C const TInt KGranularity = 4;


// ================= LOCAL FUNCTIONS =======================

/**
* Append elements from aSource to the end of aTarget.
* @param aTarget Array which receives copied elements from aSource.
* @param aSource Elements from this will be appended to aTarget.
*/
LOCAL_D void AppendArrayL
( CArrayFix<TInt>& aTarget, const CArrayFix<TInt>& aSource )
    {
    TInt i;
    TInt count = aSource.Count();
    for ( i = 0; i < count; i++ )
        {
        aTarget.AppendL( aSource.At( i ) );
        }
    }

// ================= MEMBER FUNCTIONS =======================

// ---------------------------------------------------------
// CBrowserFavouritesListbox::NewL
// ---------------------------------------------------------
//
CBrowserFavouritesListbox* CBrowserFavouritesListbox::NewL
        (
        MApiProvider& aApiProvider,
        const CCoeControl* aParent,
        const MBrowserFavouritesListboxIconHandler& aIconHandler
        )
    {
    CBrowserFavouritesListbox* listbox =
        new (ELeave) CBrowserFavouritesListbox( aApiProvider );
    CleanupStack::PushL( listbox );
    listbox->ConstructL( aParent, aIconHandler );
    CleanupStack::Pop();    // listbox
    return listbox;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::~CBrowserFavouritesListbox
// ---------------------------------------------------------
//
CBrowserFavouritesListbox::~CBrowserFavouritesListbox()
    {
    delete iFaviconHandler;
    delete iIconIndexes;
    delete iItems;
    delete iNewState;
    if(iIconUpdateCallback) iIconUpdateCallback->Cancel();
    delete iIconUpdateCallback;
    
    if ( iFontItalic )
        {
        CWsScreenDevice& screenDev = *( CEikonEnv::Static()->ScreenDevice() );
        screenDev.ReleaseFont( iFontItalic );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SetListboxCursorObserver
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::SetListboxCursorObserver
(MBrowserFavouritesListboxCursorObserver* aObserver)
    {
    iCursorObserver = aObserver;
    if ( View() )
        {
        STATIC_CAST( CBrowserFavouritesListboxView*, View() )->
            SetCursorObserver( aObserver );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SetDataL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::SetDataL
( CFavouritesItemList* aItems, /*MCommsModel& aCommsModel,*/ TBool aKeepState )
    {
    __ASSERT_DEBUG( aItems, Util::Panic( Util::EUnExpected ) );

    // Ownership of aItems is taken, and will become a member (but not yet
    // that) - push until then.
    CleanupStack::PushL( aItems );

    // Get all favicons asynchronously by iteration on icon array
    /* TODO: There should a callback from engine when favIcon are decode
       otherwise it takes some redundant calls to engine in order to get 
     the favIcons to UI. */
#ifdef BRDO_PERF_IMPROVEMENTS_ENABLED_FF    
    if(iApiProvider.StartedUp())
        UpdateFavIconsL();
#else
    iFaviconHandler->StartGetFaviconsL( aItems );
#endif     


    // Get icon indexes into new list. Replace the existing
    // data only if successfully gotten. This ensures that they don't go out
    // of sync (there cannot be different number of items in the two list).
    CBrowserFavouritesIconIndexArray* newIconIndexes =
        GetIconIndexesLC( /*aCommsModel,*/ *aItems );

    if ( aKeepState )
        {
        // Calculate new state now, while we still have old items.
        CalcNewStateL( *aItems );
        }

    // Got new data. Empty existing data, but keep the empty lists.
    ClearSelection();
    iItems->ResetAndDestroy();
    iIconIndexes->Reset();
    SetTopItemIndex(0);
    UpdateFilterL();
    HandleItemRemovalL();
    // Replace data with new.
    delete iIconIndexes;                            // Not NULL-ed, because...
    delete iItems;                                  // Not NULL-ed, because...
    iItems = aItems;                                // ... this cannot leave
    iIconIndexes = newIconIndexes;                  // ... this cannot leave

    // Let the model know the change.
    TheModel()->SetData( *iItems, *iIconIndexes );  // ... this cannot leave

    CleanupStack::Pop( 2 ); // newIconIndexes, aItems: now members.
    HandleItemAdditionL();
    UpdateFilterL();
    if ( aKeepState )
        {
        // Now set the new state into listbox, then discard it.
        __ASSERT_DEBUG( iNewState, Util::Panic( Util::EUnExpected ) );
        SetStateL( *iNewState );
        delete iNewState;
        iNewState = NULL;
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::UpdateFavIcons
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::UpdateFavIconsL()
    {
    if(iIconUpdateCallback)
        iIconUpdateCallback->Cancel();
    else 
        iIconUpdateCallback = CIdle::NewL(CActive::EPriorityIdle);

    iFaviconHandler->RequestFavicons(iItems);
    iIconUpdateCallback->Start(TCallBack(UpdateFavIconsCallback, this));
    }

// ----------------------------------------------------------------------------
// CBrowserBookmarksView::CompleteAppInitCallback
// ----------------------------------------------------------------------------
//
TInt CBrowserFavouritesListbox::UpdateFavIconsCallback( TAny* aParam )
    {
    CBrowserFavouritesListbox  *favListBox = STATIC_CAST(CBrowserFavouritesListbox*, aParam);
    TRAP_IGNORE( (favListBox->iFaviconHandler->StartGetFaviconsL(favListBox->iItems)) )
    return EFalse;
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::DrawFavicons
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::DrawFavicons()
    {
    // We have some favicons to draw
    TInt err = KErrNone;

    //Update the icon indices
    TRAP(   err,
            CBrowserFavouritesIconIndexArray* newIconIndexes =
                GetIconIndexesLC( /*aCommsModel,*/ *iItems );
            iIconIndexes->Reset();
            delete iIconIndexes;
            iIconIndexes = newIconIndexes;
            CleanupStack::Pop( newIconIndexes );
        );

    // Don't draw the favicons if there is a leave
    if ( !err )
        {
        // Let the model know the change and update the lisbox.
        TheModel()->SetData( *iItems, *iIconIndexes );
        DrawNow();
        }

    return err;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SelectionStateL
// ---------------------------------------------------------
//
TBrowserFavouritesSelectionState
CBrowserFavouritesListbox::SelectionStateL() const
    {
    TBrowserFavouritesSelectionState state;

    // Check marking first.
    const CArrayFix<TInt>* selection = MarkedRealIndexesLC();
    TInt i;
    TInt count = selection->Count();
    for ( i = 0; i < count; i++ )
        {
        state.iMarkFlags |=
            SelectionFlags( *(iItems->At( selection->At( i ) )) );
        if ( iItems->At( selection->At( i ) )->IsItem() )
            {
            state.iMarkedItemCount++;
            }
        else
            {
            state.iMarkedFolderCount++;
            }
        }

    if ( count == iItems->Count() )
        {
        state.iMarkFlags |= TBrowserFavouritesSelectionState::EAll;
        }

    TInt visibleCount;
    CAknListBoxFilterItems* filter = TheModel()->Filter();
    visibleCount = filter ? filter->FilteredNumberOfItems() : iItems->Count();
    for ( i = 0; i < visibleCount; i++ )
        {
        if ( iItems->At( RealIndex( i ) )->IsItem() )
            {
            state.iVisibleItemCount++;
            }
        else
            {
            state.iVisibleFolderCount++;
            }
        }

    TKeyArrayFix key( 0, ECmpTInt32 );
    TInt dummy;
    if ( !selection->Find( CurrentItemRealIndex(), key, dummy ) )
        {
        state.iMarkFlags |=
            TBrowserFavouritesSelectionState::ECurrent;
        }

    CleanupStack::PopAndDestroy();  // selection

    // Then comes the current.
    const CFavouritesItem* current = CurrentItem();
    if ( current )
        {
        state.iCurrentFlags |= SelectionFlags( *current );
        }

    return state;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::CurrentItem
// ---------------------------------------------------------
//
const CFavouritesItem* CBrowserFavouritesListbox::CurrentItem() const
    {
    TInt index = CurrentItemRealIndex();
    if ( index >= 0 )
        {
        return iItems->At( index );
        }
    return NULL;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::MarkedItemL
// ---------------------------------------------------------
//
const CFavouritesItem* CBrowserFavouritesListbox::MarkedItemL() const
    {
    CFavouritesItem* item = NULL;
    CArrayFix<TInt>* marked = MarkedRealIndexesLC();
    if ( marked->Count() == 1 )
        {
        item = iItems->At( marked->At( 0 ) );
        }
    CleanupStack::PopAndDestroy();
    return item;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::HighlightUidNow
// ---------------------------------------------------------
//
TBool CBrowserFavouritesListbox::HighlightUidNow( TInt aUid )
    {
    TInt index = 0;
    if (aUid != 0)
        {
        index = UidToViewIndex( aUid );
        }

    if ( index >= 0 )
        {
        SetCurrentItemIndexAndDraw( index );
        return ETrue;
        }
    return EFalse;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::HandleMarkableListCommandL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::HandleMarkableListCommandL( TInt aCommand )
    {
    if ( ListboxFlags() & EAknListBoxMarkableList )
        {
        TInt index;
        switch ( aCommand )
            {
            case EWmlCmdMark:
                {
                index = CurrentItemIndex();
                if ( index >= 0 )
                    {
                    View()->SelectItemL( index );
                    }
                break;
                }

            case EWmlCmdUnmark:
                {
                index = CurrentItemIndex();
                if ( index >= 0 )
                    {
                    View()->DeselectItem( index );
                    }
                break;
                }

            case EWmlCmdMarkAll:
                {
                ClearSelection();
                TInt count = Model()->NumberOfItems();
                if ( count )
                    {
                    TInt i = 0;
                    CArrayFixFlat<TInt>* selection =
                        new(ELeave) CArrayFixFlat<TInt>( 1 );
                    CleanupStack::PushL( selection );
                    selection->SetReserveL( count );
                    for ( i = 0; i < count; i++ )
                        {
                        selection->AppendL( i );
                        }
                    SetSelectionIndexesL( selection );
                    CleanupStack::PopAndDestroy();  // selection
                    }
                break;
                }

            case EWmlCmdUnmarkAll:
                {
                ClearSelection();
                break;
                }

            default:
                {
                Util::Panic( Util::EUnExpected );
                }
            }
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::MarkedUidsLC
// ---------------------------------------------------------
//
CArrayFix<TInt>* CBrowserFavouritesListbox::MarkedUidsLC() const
    {
    CArrayFix<TInt>* array = MarkedRealIndexesLC();
    RealIndexesToUids( *array );
    return array;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SelectedUidsLC
// ---------------------------------------------------------
//
CArrayFix<TInt>* CBrowserFavouritesListbox::SelectedUidsLC() const
    {
    CArrayFix<TInt>* array = SelectedRealIndexesLC();
    RealIndexesToUids( *array );
    return array;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SelectedItemsLC
// ---------------------------------------------------------
//
CArrayPtr<const CFavouritesItem>*
CBrowserFavouritesListbox::SelectedItemsLC(TBool aIncludeSpecialItems) const
    {
    CArrayPtrFlat<const CFavouritesItem>* itemPtrs =
        new (ELeave) CArrayPtrFlat<const CFavouritesItem>( KGranularity );
    CleanupStack::PushL( itemPtrs );
    CArrayFix<TInt>* indexes = SelectedRealIndexesLC();
    TInt i;
    TInt count = indexes->Count();
    for ( i = 0; i < count; i++ )
        {
        CFavouritesItem* item = iItems->At( indexes->At( i ) );

        if ( !aIncludeSpecialItems )
            {
            // Skip special items:
            // folders, homepage, last visited & start page URLs.
            // Need a workaround for the start page since CFavouritesItem
            // does not provide IsStartPage() or something similar.
            if ( (item->Uid() == KFavouritesHomepageUid ) ||
                (item->Uid() == KFavouritesLastVisitedUid ) ||
                item->IsFolder() ||
                item->Uid() == KFavouritesStartPageUid )
                    continue;
            }
        itemPtrs->AppendL( item );
        }
    CleanupStack::PopAndDestroy();  // indexes
    return itemPtrs;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::ItemByUid
// ---------------------------------------------------------
//
const CFavouritesItem* CBrowserFavouritesListbox::ItemByUid
( TInt aUid ) const
    {
    return iItems->ItemByUid( aUid );
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::UnfilteredNumberOfItems
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::UnfilteredNumberOfItems()
    {
    return iItems->Count();
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::FilteredNumberOfItems
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::FilteredNumberOfItems()
    {

    CAknListBoxFilterItems* filter = TheModel()->Filter();
    return filter->FilteredNumberOfItems();
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::UpdateFilterL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::UpdateFilterL()
    {
    CAknListBoxFilterItems* filter = TheModel()->Filter();
    if ( filter )
        {
        filter->HandleItemArrayChangeL();
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::AnyFoldersL
// ---------------------------------------------------------
//
TBool CBrowserFavouritesListbox::AnyFoldersL()
    {
    TInt i;
    TInt count = iItems->Count();
    for ( i = 0; i < count; i++ )
        {
        if ( iItems->At( i )->IsFolder() )
            {
            if (iItems->At( i )->Uid()!=KFavouritesAdaptiveItemsFolderUid) return ETrue; //exclude Adaptive Bookmarks Folder
            }
        }
    return EFalse;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::OfferKeyEventL
// ---------------------------------------------------------
//
TKeyResponse CBrowserFavouritesListbox::OfferKeyEventL
( const TKeyEvent& aKeyEvent, TEventCode aType )
    {
    TKeyResponse result = EKeyWasNotConsumed;

    switch ( aKeyEvent.iCode )
        {
        case EKeyLeftUpArrow:     // Northwest
        case EStdKeyDevice10:     //   : Extra KeyEvent supports diagonal event simulator wedge
        case EKeyLeftArrow:       // West
        case EKeyLeftDownArrow:   // Southwest
        case EStdKeyDevice13:     //   : Extra KeyEvent supports diagonal event simulator wedge

        case EKeyRightUpArrow:    // Northeast
        case EStdKeyDevice11:     //   : Extra KeyEvent supports diagonal event simulator wedge
        case EKeyRightArrow:      // East
        case EKeyRightDownArrow:  // Southeast
        case EStdKeyDevice12:     //   : Extra KeyEvent supports diagonal event simulator wedge
            {
            // This listbox does not consume left/right or diagonal keypresses.
            // (The base class always does, even if it doesn't use them )
            break;
            }

        default:
            {
            result = CAknSingleGraphicStyleListBox::OfferKeyEventL
                ( aKeyEvent, aType );
            // Call UpdateCBA to update MSK in case of mark/unmark
            CBrowserAppUi::Static()->UpdateCbaL();
            }

        }

    return result;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::FocusChanged
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::FocusChanged( TDrawNow aDrawNow )
    {
    // Do nothing until the listbox is fully constructed
    // The dialogpage sets the focus before calling ConstructL
    if ( iView )
        {
        CAknSingleGraphicStyleListBox::FocusChanged( aDrawNow );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::CreateModelL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::CreateModelL()
    {
    iModel = CBrowserFavouritesListboxModel::NewL( *iItems, *iIconIndexes );
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::MakeViewClassInstanceL
// ---------------------------------------------------------
//
CListBoxView* CBrowserFavouritesListbox::MakeViewClassInstanceL()
    {
    return new (ELeave) CBrowserFavouritesListboxView( *this );
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::CreateItemDrawerL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::CreateItemDrawerL()
    {
    CAknSingleGraphicStyleListBox::CreateItemDrawerL();
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::CBrowserFavouritesListbox
// ---------------------------------------------------------
//
CBrowserFavouritesListbox::CBrowserFavouritesListbox
                            ( MApiProvider& aApiProvider ) :
    iApiProvider( aApiProvider )
    {
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::ConstructL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::ConstructL
        (
        const CCoeControl* aParent,
        const MBrowserFavouritesListboxIconHandler& aIconHandler
        )
    {
    iSkinUpdated = EFalse;
    iIconHandler = &aIconHandler;
    iItems = new (ELeave) CFavouritesItemList();
    iIconIndexes =
        new (ELeave) CBrowserFavouritesIconIndexArray( KGranularity );
    CAknSingleGraphicStyleListBox::ConstructL( aParent, ListboxFlags() );
    // MUST call this after the listbox has finished; listbox construction
    // is buggy and overwrites the model's itemarray ptr.
    TheModel()->SetItemArray();
    CreateScrollBarFrameL( ETrue );
    ScrollBarFrame()->SetScrollBarVisibilityL
        ( CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto );

    // Load icons
    ItemDrawer()->ColumnData()->SetIconArray
        ( iIconHandler->CreateIconArrayL() );

    // Store the size of an icon
    TAknWindowComponentLayout layout =
                AknLayoutScalable_Avkon::list_single_graphic_pane_g1(0);

    TAknLayoutRect naviPaneGraphicsLayoutRect;
    TRect listBoxGraphicRect;
    TRect rect = iAvkonAppUi->ClientRect();


    naviPaneGraphicsLayoutRect.LayoutRect( rect, layout);
    listBoxGraphicRect = naviPaneGraphicsLayoutRect.Rect();

    TSize listBoxGraphicSize( listBoxGraphicRect.iBr.iX - listBoxGraphicRect.iTl.iX,
                                listBoxGraphicRect.iBr.iY - listBoxGraphicRect.iTl.iY );
    // Favicon handler
    iFaviconHandler = CBrowserFaviconHandler::NewL(
                                iApiProvider,
                                ItemDrawer()->ColumnData()->IconArray(),
                                *this,
                                listBoxGraphicSize );

    ItemDrawer()->ColumnData()->EnableMarqueeL( ETrue );


    // Setup italicized font for use later    
    const CFont* logicalFont = AknLayoutUtils::FontFromId(EAknLogicalFontPrimaryFont);
    
    // Note: This font is owned by the application's system font array (where it 
    // is likely already to have been created) and does not need to be
    // released. It can just go out of scope.// Extract font information
    TFontSpec fontSpec = logicalFont->FontSpecInTwips();// Desired height, weight, and posture already set in locals
    fontSpec.iFontStyle.SetPosture( EPostureItalic );// Obtain new font
    CWsScreenDevice& screenDev = *( CEikonEnv::Static()->ScreenDevice() );
    screenDev.GetNearestFontInTwips( ( CFont*& )iFontItalic, fontSpec );
 
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::ListboxFlags
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::ListboxFlags()
    {
    return AknLayoutUtils::PenEnabled() ?  
         EAknListBoxStylusMarkableList :  EAknListBoxMarkableList;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::GetIconIndexesLC
// ---------------------------------------------------------
//
CBrowserFavouritesIconIndexArray*
CBrowserFavouritesListbox::GetIconIndexesLC
( /*MCommsModel& aCommsModel, */CFavouritesItemList& aItems )
    {
    // Create new empty list.
    CBrowserFavouritesIconIndexArray* iconIndexes =
        new (ELeave) CBrowserFavouritesIconIndexArray( KGranularity );
    CleanupStack::PushL( iconIndexes );
    // Get list of access points. Not copy, owned by the AP model.
   // const CApListItemList* apList = aCommsModel.AccessPoints();
    // Fill the list.
    TInt i = 0;
    TInt count = aItems.Count();
    for ( i = 0; i < count; i++ )
        {
        iconIndexes->AppendL
            ( iIconHandler->IconIndexes( *(aItems.At( i ))/*, apList*/,this ) );
        }
    return iconIndexes;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::CalcNewStateL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::CalcNewStateL
( CFavouritesItemList& aNewItems )
    {
    delete iNewState;
    iNewState = NULL;
    iNewState = new( ELeave ) CBrowserFavouritesListboxState;

    // 1. Check if we have any new item. If yes, highlight goes to first
    // new one.
    TInt i;
    TInt count = aNewItems.Count();
    for ( i = 0; i < count; i++ )
        {
        if ( iItems->UidToIndex( aNewItems.IndexToUid( i ) ) ==
                                                            KErrNotFound )
            {
            // New item, not found among the old ones.
            // Set highlight to that, and also becomes top item.
            iNewState->iHighlightUid = iNewState->iTopItemUid =
                aNewItems.IndexToUid( i );
            break;
            }
        }

    // 2. If there is no new item, get the new highlight. That is the old
    // one, if still exists, or the next remaining one after the
    // deleted old one(s).
    TInt uid;
    if ( iNewState->iHighlightUid == KFavouritesNullUid )
        {
        i = CurrentItemRealIndex();
        if ( i >= 0 )
            {
            // Have current item.
            // Now go down the old list, beginning from highlighted one;
            // find first item that still exists.
            count = iItems->Count();
            for ( /*current highlight index: i*/; i < count; i++ )
                {
                uid = iItems->At( i )->Uid();
                if ( aNewItems.UidToIndex( uid ) != KErrNotFound )
                    {
                    iNewState->iHighlightUid = uid;
                    break;
                    }
                }
            // Here we should have higlight uid, unless the deleted element(s)
            // were last. In that case, set last item highlighted (if there is
            // anything to highlight).
            if ( iNewState->iHighlightUid == KFavouritesNullUid &&
                                                            aNewItems.Count() )
                {
                iNewState->iHighlightUid = aNewItems.IndexToUid
                    ( aNewItems.Count() - 1 );
                }
            }
        }

    // 3. Get mark uids. Whether these uids exist in the new list or not, is
    // not checked here; setting marks to the already changed listbox is
    // fool-proof.
    iNewState->iMarkUids = MarkedUidsLC();
    CleanupStack::Pop();    // Uid list; ownership is now in the state.
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SetStateL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::SetStateL
( const CBrowserFavouritesListboxState& aState )
    {
    TInt topIndex;

    // Set marks.
    if ( aState.iMarkUids->Count() )
        {
        CArrayFix<TInt>* marks = new (ELeave) CArrayFixFlat<TInt>( 4 );
        CleanupStack::PushL( marks );
        marks->AppendL
            ( aState.iMarkUids->Back( 0 ), aState.iMarkUids->Count() );
        UidsToViewIndexes( *marks );
        SetSelectionIndexesL( marks );
        CleanupStack::PopAndDestroy();  // marks
        }

    // Set top item index.
    topIndex = UidToViewIndex ( aState.iTopItemUid );
    if ( topIndex >= 0 )
        {
        // Always try to fill the listbox (if there were empty lines below,
        // "scroll down", instead of strictly restoring the top item index).
        TInt topIndexToSeeLastItem = Model()->NumberOfItems() -
            View()->NumberOfItemsThatFitInRect( View()->ViewRect() );
        if ( topIndexToSeeLastItem < 0 )
            {
            topIndexToSeeLastItem = 0;
            }
        topIndex = Min( topIndex, topIndexToSeeLastItem );
        SetTopItemIndex( topIndex );
        }

    // Set higlight.
    TInt curIndex = UidToViewIndex ( aState.iHighlightUid );
    if ( curIndex < 0 )
        {
        // If cannot restore highlight, set it to top item.
        curIndex = topIndex;
        }
    if ( curIndex >= 0 )
        {
        SetCurrentItemIndex( curIndex );
        }

    DrawNow();

    if ( iCursorObserver )
        {
        // Cursor now points to some different item. Let the observer know it.
        iCursorObserver->HandleCursorChangedL( this );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::UidToViewIndex
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::UidToViewIndex( TInt aUid ) const
    {
    TInt viewIndex = KErrNotFound;
    TInt realIndex = iItems->UidToIndex( aUid );
    if ( realIndex >= 0 )
        {
        CAknListBoxFilterItems* filter = TheModel()->Filter();
        if ( filter )
            {
            // Have filter, do the conversion.
            viewIndex = filter->VisibleItemIndex( realIndex );
            }
        else
            {
            // No filter, no conversion necessary.
            viewIndex = realIndex;
            }
        }
    return viewIndex;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::UidsToViewIndexes
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::UidsToViewIndexes
( CArrayFix<TInt>& aList ) const
    {
    TInt i;
    TInt j;
    TInt index;
    TInt count = aList.Count();
    for ( i = 0, j = 0; i < count; i++ )
        {
        index = UidToViewIndex( aList.At ( i ) );
        if ( index != KErrNotFound )
            {
            aList.At( j++ ) = index;
            }
        }
    if ( j < count )
        {
        // Not all Uids were converted. Delete the trailing rubbish.
        aList.Delete( j, count - j );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::RealIndexesToUids
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::RealIndexesToUids
( CArrayFix<TInt>& aList ) const
    {
    TInt i;
    TInt uid;
    TInt count = aList.Count();
    for ( i = 0; i < count; i++ )
        {
        uid = iItems->IndexToUid( aList.At( i ) );
        __ASSERT_DEBUG( uid != KFavouritesNullUid, \
            Util::Panic( Util::EFavouritesBadBookmarkUid ) );
        aList.At( i ) = uid;
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::MarkedRealIndexesLC
// ---------------------------------------------------------
//
CArrayFix<TInt>* CBrowserFavouritesListbox::MarkedRealIndexesLC() const
    {
    CListBoxView::CSelectionIndexArray* array =
        new (ELeave) CArrayFixFlat<TInt>( KGranularity );
    CleanupStack::PushL( array );
    if ( iItems->Count() )
        {
        const CArrayFix<TInt>* marked;
        CAknListBoxFilterItems* filter = TheModel()->Filter();
        if ( filter )
            {
            // Filter knows all.
            filter->UpdateSelectionIndexesL();
            marked = filter->SelectionIndexes();
#if 1 /* TODO remove when AVKON bug fixed*/
            // Overcoming AVKON bug. If filter criteria is empty (i.e. the
            // user is not typing in the filter), selection indexes between
            // the filter and the listbox are not synchronized! Unfortunately,
            // this strange back-way is the only means by we can discover if
            // we have criteria or not; CAknListBoxFilterItems has the
            // criteria as private; and the CAknSearchField, which holds the
            // filter (and has the string) is not accessible here in the
            // listbox (it's in the container).
            if ( filter->FilteredNumberOfItems() ==
                filter->NonFilteredNumberOfItems() )
                {
                marked = View()->SelectionIndexes();
                }
#endif
            }
        else
            {
            // No filter.
            marked = View()->SelectionIndexes();
            }
        AppendArrayL( /*aTarget=*/*array, /*aSource=*/*marked );
        }
    return array;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SelectedRealIndexesLC
// ---------------------------------------------------------
//
CArrayFix<TInt>* CBrowserFavouritesListbox::SelectedRealIndexesLC() const
    {
    CListBoxView::CSelectionIndexArray* selection =
        MarkedRealIndexesLC();
    if ( selection->Count() == 0 )
        {
        // No marks; use the highlighted one.
        selection->AppendL( CurrentItemRealIndex() );
        }
    return selection;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::CurrentItemRealIndex
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::CurrentItemRealIndex() const
    {
    return RealIndex( CurrentItemIndex() /*that's view index*/ );
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::RealIndex
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::RealIndex( TInt aViewIndex ) const
    {
    TInt index = KErrNotFound;
    if ( aViewIndex >= 0 )
        {
        CAknListBoxFilterItems* filter = TheModel()->Filter();
        if ( filter )
            {
            // If we have the index and the filter also, do the conversion.
            index = filter->FilteredItemIndex( aViewIndex );
            }
        else
            {
            index = aViewIndex;
            }
        }
    return index;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::RealIndexes
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::RealIndexes( CArrayFix<TInt>& aList ) const
    {
    TInt i;
    TInt j;
    TInt index;
    TInt count = aList.Count();
    for ( i = 0, j = 0; i < count; i++ )
        {
        index = RealIndex( aList.At ( i ) );
        if ( index != KErrNotFound )
            {
            aList.At( j++ ) = index;
            }
        }
    if ( j < count )
        {
        // Not all indexes were converted. Delete the trailing rubbish.
        aList.Delete( j, count - j );
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SelectionFlags
// ---------------------------------------------------------
//
TInt CBrowserFavouritesListbox::SelectionFlags
( const CFavouritesItem& aItem ) const
    {
    TInt flags = 0;
    if ( aItem.IsItem() )
        {
        switch ( aItem.Uid() )
            {
            case KFavouritesHomepageUid:
                {
                flags |=
                    TBrowserFavouritesSelectionState::EAny |
                    TBrowserFavouritesSelectionState::EHomepage |
                    TBrowserFavouritesSelectionState::EItem;
                break;
                }

            case KFavouritesStartPageUid:
                {
                flags |=
                    TBrowserFavouritesSelectionState::EAny |
                    TBrowserFavouritesSelectionState::EStartPage |
                    TBrowserFavouritesSelectionState::EItem;
                break;
                }

            case KFavouritesLastVisitedUid:
                {
                flags |=
                    TBrowserFavouritesSelectionState::EAny |
                    TBrowserFavouritesSelectionState::ELastVisited |
                    TBrowserFavouritesSelectionState::EItem;
                break;
                }

            default:
                {
                flags |=
                    TBrowserFavouritesSelectionState::EAny |
                    TBrowserFavouritesSelectionState::EPlainItem |
                    TBrowserFavouritesSelectionState::EItem;
                break;
                }
            }
        }
    else
        {
        flags |=
            TBrowserFavouritesSelectionState::EAny |
            TBrowserFavouritesSelectionState::EFolder;
        }
    return flags;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::TheModel
// ---------------------------------------------------------
//
CBrowserFavouritesListboxModel*
CBrowserFavouritesListbox::TheModel() const
    {
    return REINTERPRET_CAST( CBrowserFavouritesListboxModel*, Model() );
    }


// ---------------------------------------------------------
// CBrowserFavouritesListbox::HandleResourceChange
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::HandleResourceChange( TInt aType )
    {
    CAknSingleGraphicStyleListBox::HandleResourceChange( aType );
    if ( aType == KAknsMessageSkinChange )
        {
        CArrayPtr<CGulIcon>* array =
        ItemDrawer()->ColumnData()->IconArray();

        array->ResetAndDestroy();
        delete array;

        CAknIconArray* iconArray = NULL;
        TRAPD( err,
                iconArray = iIconHandler->CreateIconArrayL()
                )

        if ( !err )
            {
            ItemDrawer()->ColumnData()->SetIconArray( iconArray );
            iFaviconHandler->UpdateIconArray(ItemDrawer()->ColumnData()->IconArray());
            SetSkinUpdated(ETrue);
            }
        }
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::SetSkinUpdated
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::SetSkinUpdated(TBool aSkinUpdated)
    {
    iSkinUpdated = aSkinUpdated;
    }

// ---------------------------------------------------------
// CBrowserFavouritesListbox::ItalicizeRowItemL
// ---------------------------------------------------------
//
void CBrowserFavouritesListbox::ItalicizeRowItemL(TInt aRowIndex)
    {
    if (ItemDrawer() && ItemDrawer()->ColumnData() && iFontItalic)
        {
        ItemDrawer()->ColumnData()->SetColumnFontForRowL( aRowIndex, 1, iFontItalic );
        }
    }

//  End of File