phoneuis/easydialing/src/easydialinglistbox.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 15 Mar 2010 12:40:24 +0200
branchRCL_3
changeset 15 2a26698d78ba
parent 9 8871b09be73b
child 17 38529f706030
permissions -rw-r--r--
Revision: 201009 Kit: 201010

/*
* Copyright (c) 2010 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:  Easy dialing list box.
*
*/


// INCLUDE FILES

#include "easydialinglistbox.h"
#include "easydialinglistboxview.h"
#include "easydialinglistboxitemdrawer.h"
#include "easydialinglistboxdata.h"
#include "easydialingpanics.h"
#include "easydialingcontactdatamanager.h"
#include "easydialingcrkeys.h"

#include <easydialingpluginresources.rsg>

#include <phoneappcommands.hrh>
#include <phonebook2.mbg>
#include <phonebook2ece.mbg>

#include <ccappcommlauncherpluginrsc.rsg>

// AvKON and drawing header files

#include <aknpointereventsuppressor.h> 
#include <aknlongtapdetector.h> // Required for touch
#include <AknsFrameBackgroundControlContext.h>
#include <AknInfoPopupNoteController.h>  // tooltips

#include <aknlayoutscalable_apps.cdl.h>
#include <layoutmetadata.cdl.h>
#include <gulicon.h>
#include <centralrepository.h>
#include <bautils.h>    // for BaflUtils

#include <aknlistloadertfx.h>
#include <aknlistboxtfxinternal.h>
#include <aknlistboxtfx.h>

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES  

extern TRect ContactImageBoundingBox( const TRect& aItemRect );
extern TRect ActionMenuIconBoundingBox(const TRect& aItemRect);

// CONSTANTS
static const TInt KListBoxMarginWidth = 2;
static const TInt KMaxVisibleItemsPortrait = 3;
static const TInt KMaxVisibleItemsLandscape = 2;

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS


/*
 * ==============================================================================
 * 
 * 
 * class CEasyDialingListBox
 * 
 * 
 * ==============================================================================
 */


// -----------------------------------------------------------------------------
// CEasyDialingListBox
// 
// -----------------------------------------------------------------------------
//
CEasyDialingListBox::CEasyDialingListBox() :
    CEikFormattedCellListBox()
    {
    }

// -----------------------------------------------------------------------------
// ~CEasyDialingListBox
// 
// -----------------------------------------------------------------------------
//
CEasyDialingListBox::~CEasyDialingListBox()
    {
    delete iBGContext;    
    delete iLongTapDetector;
    }

// -----------------------------------------------------------------------------
// ConstructL
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::ConstructL( TInt aFlags, 
        CEasyDialingContactDataManager* aContactDataManager )
    {
    CEikFormattedCellListBox::ConstructL( NULL, aFlags );
    
    iLongTapDetector = CAknLongTapDetector::NewL( this );
 
    CEasyDialingListBoxItemDrawer* drawer = static_cast<CEasyDialingListBoxItemDrawer*> (iItemDrawer);
    CEasyDialingListBoxData* data = drawer->EasyDialingCellData();
    data->SetContactDataManager(aContactDataManager);
    data->SetEDLBXControl(this);
    
    iBGContext = CAknsFrameBackgroundControlContext::NewL( KAknsIIDQsnFrPopupSub,
            Rect(), Rect(), EFalse );
       
    // ContactDataManager is accessed from SizeChanged. If list item size
    // changes -> thumbnail size changes
    iContactDataManager = aContactDataManager;
    
    drawer->SetColors();

    CreateScrollBarFrameL( ETrue );
    ScrollBarFrame()->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto );
    }


// -----------------------------------------------------------------------------
// MakeViewClassInstanceL
// 
// -----------------------------------------------------------------------------
//
CListBoxView* CEasyDialingListBox::MakeViewClassInstanceL()
    {
    return (new ( ELeave ) CEasyDialingListBoxView);
    }


// -----------------------------------------------------------------------------
// ItemDrawer
// 
// -----------------------------------------------------------------------------
//
CEasyDialingListBoxItemDrawer* CEasyDialingListBox::ItemDrawer() const
    {
    return (CEasyDialingListBoxItemDrawer*) iItemDrawer;
    }


// -----------------------------------------------------------------------------
// FocusChanged
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::FocusChanged( TDrawNow aDrawNow )
    {
    if ( !IsFocused() )
        {
        CEasyDialingListBoxView* view = static_cast<CEasyDialingListBoxView*>( iView );
        view->SetCurrentItemIndexToNone();
        
        // Invalidate window area. 
        // This fixes the drawing problem that the top 
        // of listbox is not always redrawn on the area that overlaps 
        // the status pane area. 
        // TODO: This overlapping no longer happens in 9.2 so this may
        // now be unnecessary.
        Window().Invalidate();
        }
    CEikFormattedCellListBox::FocusChanged( aDrawNow );
    }


// -----------------------------------------------------------------------------
// CreateItemDrawerL
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::CreateItemDrawerL()
    {
    CEasyDialingListBoxData* celldata = CEasyDialingListBoxData::NewL();
    CleanupStack::PushL( celldata );
    iItemDrawer = new(ELeave) CEasyDialingListBoxItemDrawer(Model(), iEikonEnv->NormalFont(), celldata);
    CleanupStack::Pop( celldata );  
    }


// -----------------------------------------------------------------------------
// Draw
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::Draw(const TRect& aRect) const
    {
    MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( iItemDrawer->Gc() );
    if ( transApi )
        {
        transApi->SetListType( MAknListBoxTfxInternal::EListBoxTypeMainPane );
        transApi->BeginRedraw( MAknListBoxTfxInternal::EListView, this->Rect() );
        }
    
    if (!iView->RedrawDisabled() )
        {
        TRect clientRect( Rect() );
        TRect viewRect = iView->ViewRect();
        
        if ( transApi )
            {
            transApi->StartDrawing( MAknListBoxTfxInternal::EListView );
            }

        AknsDrawUtils::BackgroundBetweenRects( 
            AknsUtils::SkinInstance(), 
            iBGContext, 
            this, 
            *iItemDrawer->Gc(), 
            clientRect, 
            viewRect );
        
        if ( transApi )
            {
            transApi->StopDrawing();
            }
        }
    
    if ( iModel->NumberOfItems() )
        {
        // Draw the actual list
        iView->Draw(&aRect);
        }
    if ( transApi )
        {
        transApi->EndViewRedraw( aRect );
        }
    }


// -----------------------------------------------------------------------------
// HandleResourceChange
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::HandleResourceChange(TInt aType)
    {
    CEikFormattedCellListBox::HandleResourceChange( aType );
    iSBFrame->VerticalScrollBar()->HandleResourceChange( aType );
    iSBFrame->DrawScrollBarsNow();
    ItemDrawer()->SetColors();
    
    // Base call to HandleResourceChange justifies the list to even items
    // on the top. This causes problems when listbox height is not a multiple of
    // listitem heights. Fix scrolling manually for these cases.
    TRAP_IGNORE( HandleItemAdditionL() ); // needed to prevent drawing problems
    TInt scrollIndex = ( IsFocused() ? CurrentItemIndex() : iNumberOfNames - 1 );
    ScrollToMakeItemVisible( scrollIndex );
    
    DrawDeferred();
    }


// -----------------------------------------------------------------------------
// SizeChanged
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::SizeChanged()
    {
    CEikFormattedCellListBox::SizeChanged();
    
    // Set the listbox colors.
    // For some reason, calling this in HandleResourceChange is not enough, it does
    // not get called in situation it should.
    ItemDrawer()->SetColors();
   
    // resize scroll bar
    if ( iSBFrame )
        {
        TAknLayoutRect rect;
        TInt variety = ( Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0 );
    
        TAknWindowComponentLayout viewLayout( AknLayoutScalable_Apps::dia3_list_pane( variety ) );
        rect.LayoutRect( Rect(), viewLayout );
        TRect viewRect( rect.Rect() );
        // Add a bit of margin around the view as layout doesn't define any
        viewRect.Shrink( KListBoxMarginWidth, KListBoxMarginWidth );
        
        TAknWindowComponentLayout scrollBarLayout( AknLayoutScalable_Apps::scroll_pane_cp12() );
        rect.LayoutRect( Rect(), scrollBarLayout );
        TRect scrollBarRect( rect.Rect() );

        iView->SetViewRect( viewRect );
        
        CAknDoubleSpanScrollBar* scrollbar = static_cast <CAknDoubleSpanScrollBar*>( iSBFrame->VerticalScrollBar() );

        scrollbar->SetFixedLayoutRect( scrollBarRect );
        scrollbar->SetRect( scrollBarRect );
        
        TRect viewAndScrollBarRect( viewRect );
        
        if ( AknLayoutUtils::LayoutMirrored() )
            {
            viewAndScrollBarRect.iTl = scrollBarRect.iTl;
            }
        else
            {
            viewAndScrollBarRect.iBr = scrollBarRect.iBr;
            }
        iBGContext->SetFrameRects( Rect(), viewAndScrollBarRect );
        }
    }


// -----------------------------------------------------------------------------
// MopSupplyObject
// 
// -----------------------------------------------------------------------------
//
TTypeUid::Ptr CEasyDialingListBox::MopSupplyObject( TTypeUid aId )
    {
    if ( aId.iUid == MAknsControlContext::ETypeId && iBGContext )
        {
        return MAknsControlContext::SupplyMopObject( aId, iBGContext );
        }
    return CEikFormattedCellListBox::MopSupplyObject( aId );    
    }

// -----------------------------------------------------------------------------
// MakeVisible
// 
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::MakeVisible( TBool aVisible )
    {
    if ( aVisible != IsVisible() )
        {
        CEikFormattedCellListBox::MakeVisible( aVisible );
        if ( iSBFrame )
            {
            CEikScrollBar* sb = iSBFrame->GetScrollBarHandle( CEikScrollBar::EVertical );
            if ( sb )
                {
                sb->MakeVisible( aVisible );
                if ( aVisible )
                    {
                    UpdateScrollBarThumbs();
                    }
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// SetMaxRect
//
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::SetMaxRect( TRect aMaxRect )
    {
    iMaxRect = aMaxRect;

    // Update the list item size according the maximum view rect size
    TInt variety = ( Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0 );
    TAknLayoutRect maxViewLayout;
    maxViewLayout.LayoutRect( aMaxRect, AknLayoutScalable_Apps::dia3_list_pane( variety ) );
    TRect maxViewRect( maxViewLayout.Rect() );
    maxViewRect.Shrink( KListBoxMarginWidth, KListBoxMarginWidth ); // layout data doens't include any margins but we have added some
    
    TInt maxItemsShown = ( variety ? KMaxVisibleItemsLandscape : KMaxVisibleItemsPortrait );
    TInt itemHeight = maxViewRect.Height() / maxItemsShown;
    TRAP_IGNORE( SetItemHeightL( itemHeight ) );

    // Calculate new thumbnail rect from item size
    TSize itemSize( maxViewRect.Width(), itemHeight );
    TRect thumbnailRect = ContactImageBoundingBox( itemSize );
    iContactDataManager->SetThumbnailSize( thumbnailRect.Size() ); // reloads thumbnails if the new size is different from old one

    // Inform listbox data class about changed list item size
    ItemDrawer()->EasyDialingCellData()->HandleItemSizeChange();
    }

// -----------------------------------------------------------------------------
// SetRectToNumberOfItems
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::SetRectToNumberOfItems( TInt aNumberOfNames ) 
    {
    iNumberOfNames = aNumberOfNames;

    TRect listboxRect( iMaxRect );
    
    // Make listbox smaller if maximum size is not needed to show
    // all list items.
    TInt requiredHeight = GetHeightBasedOnNumberOfItems( iNumberOfNames );
    if ( requiredHeight < listboxRect.Height() )
        {
        // Shrink rect height so that bottom of the rect doesn't move
        listboxRect.iTl.iY += ( listboxRect.Height() - requiredHeight );
        }
    
    SetRect( listboxRect );
    }


// -----------------------------------------------------------------------------
// SetFocusedWithKeyEventL
// -----------------------------------------------------------------------------
//
TKeyResponse CEasyDialingListBox::SetFocusedWithKeyEventL( const TKeyEvent& aKeyEvent, TEventCode aType )
    {
    TKeyResponse keyResponse = EKeyWasNotConsumed;
    TInt keyCode = aKeyEvent.iCode;
            
    // Disable redrawing temporarily.
    // This is because OfferKeyEventL puts the focus to the wrong item,
    // and we don't want to show it flashing there.
    // Make sure that no leave happens before redraw is enabled again.
    iView->SetDisableRedraw( ETrue );
        
    TRAP_IGNORE( keyResponse = OfferKeyEventL( aKeyEvent, aType ) );
    
    TInt itemToFocus = ( keyCode == EKeyUpArrow ? iNumberOfNames - 1 : 0 );
    ScrollToMakeItemVisible( itemToFocus );
    SetCurrentItemIndex( itemToFocus );
        
    iView->SetDisableRedraw( EFalse );
    
    DrawDeferred();
    
    return keyResponse;
    }


// -----------------------------------------------------------------------------
// GetHeightBasedOnNumberOfItems
// 
// -----------------------------------------------------------------------------
//
TInt CEasyDialingListBox::GetHeightBasedOnNumberOfItems( TInt aNum ) const
    {
    return ( ItemHeight()*aNum + KListBoxMarginWidth*2 ); 
    }


// -----------------------------------------------------------------------------
// CurrentContactDataIndex
// 
// -----------------------------------------------------------------------------
//
TInt CEasyDialingListBox::CurrentContactDataIndex()
    {
    if ( CurrentItemIndex() >= 0 ) 
        {
        TPtrC itemText = Model()->ItemText( CurrentItemIndex() );
        TPtrC indexText;
        
        TInt error = TextUtils::ColumnText( indexText , 0, &itemText );
        __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) );

        TUint id( 0 );
        TLex lex( indexText );
        error = lex.Val( id, EHex );
        __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) );
        
        return id;
        }
    else 
        {
        return KErrNotFound;
        }
    }

// -----------------------------------------------------------------------------
// CurrentContactLinkLC
// 
// -----------------------------------------------------------------------------
//
HBufC8* CEasyDialingListBox::CurrentContactLinkLC()
    {
    TInt index = CurrentContactDataIndex();
    return iContactDataManager->ContactLinkLC( index );
    }


// -----------------------------------------------------------------------------
// HandleLongTapEventL
// Callback from CAknLongTapDetector.
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::HandleLongTapEventL( const TPoint& /*aPenEventLocation*/, 
                                               const TPoint& /*aPenEventScreenLocation*/ )
    {
    ReportListBoxEventL( static_cast<MEikListBoxObserver::TListBoxEvent>
            ( KEasyDialingContactLongTapped ) );
    iPointerLongPressHandled = ETrue;
    }


// -----------------------------------------------------------------------------
// HandlePointerEventL
// Pointer event handling within the EasyDialingListBox.
// -----------------------------------------------------------------------------
//
void CEasyDialingListBox::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
    // Button down event starts new pointer press. Reset flags at this point.
    if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
        {
        iPointerLongPressHandled = EFalse;
        }
    
    iLongTapDetector->PointerEventL(aPointerEvent);
    if ( iPointerLongPressHandled )
        {
        // No further handling is made after long tap on list item
        // has been detected.
        return;
        }

    CEikFormattedCellListBox::HandlePointerEventL( aPointerEvent );
    }


// end of file