phoneuis/easydialing/src/easydialinglistbox.cpp
branchRCL_3
changeset 62 5266b1f337bd
child 81 c26cc2a7c548
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phoneuis/easydialing/src/easydialinglistbox.cpp	Wed Sep 01 12:30:10 2010 +0100
@@ -0,0 +1,615 @@
+/*
+* 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>
+
+#include <aknlongtapdetector.h> // Required for touch
+#include <AknsFrameBackgroundControlContext.h>
+
+#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;
+
+// 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();
+        }
+    CEikFormattedCellListBox::FocusChanged( aDrawNow );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CreateItemDrawerL
+// 
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingListBox::CreateItemDrawerL()
+    {
+    CEasyDialingListBoxData* celldata = CEasyDialingListBoxData::NewL( *iEikonEnv );
+    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()
+    {
+	// Note that within this call view rect is adjusted to fit into TGulBorder
+    // that could have been given in construction. It's not used by ED listbox.
+    // The view rect is not correct for ED after this call but it's
+    // calculated and set below.
+    CEikFormattedCellListBox::SizeChanged();
+    
+    TRect parentRect = Rect();
+    
+    // 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();
+    
+    // Get all the layout rects
+    TAknLayoutRect rect;
+    TInt variety = ( Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0 );
+
+    TAknWindowComponentLayout viewLayout( AknLayoutScalable_Apps::dia3_list_pane( variety ) );
+    rect.LayoutRect(parentRect, 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( parentRect, scrollBarLayout );
+    TRect scrollBarRect( rect.Rect() );
+
+    TRect viewAndScrollBarRect( viewRect );
+    if ( AknLayoutUtils::LayoutMirrored() )
+        {
+        viewAndScrollBarRect.iTl.iX = scrollBarRect.iTl.iX + KListBoxMarginWidth;
+        }
+    else
+        {
+        viewAndScrollBarRect.iBr.iX = scrollBarRect.iBr.iX - KListBoxMarginWidth;
+        }
+
+    // If scrollbar is not needed, then we can use all the space for the list view
+    if ( GetHeightBasedOnNumberOfItems( iNumberOfNames ) <= parentRect.Height() )
+        {
+        viewRect = viewAndScrollBarRect;
+        scrollBarRect.SetWidth( 0 );
+        }
+
+    // Must use this method so that all eiklistbox's internal variables are 
+    // set and updated according to this viewRect. This call would
+    // add list margins but no such are defined in layouts so view's rect is
+    // set to viewRect calculated here.
+    SetViewRectFromClientRect( viewRect );
+    
+    // Set scroll bar rect
+    if ( iSBFrame )
+        {
+        CAknDoubleSpanScrollBar* scrollbar = static_cast <CAknDoubleSpanScrollBar*>( iSBFrame->VerticalScrollBar() );
+        scrollbar->SetFixedLayoutRect( scrollBarRect );
+        scrollbar->SetRect( scrollBarRect );
+        scrollbar->MakeVisible( scrollBarRect.Width() != 0 );
+        }
+
+    iBGContext->SetFrameRects( parentRect, viewAndScrollBarRect );
+    
+    TRAP_IGNORE( CEikFormattedCellListBox::HandleViewRectSizeChangeL() );
+    }
+
+
+// -----------------------------------------------------------------------------
+// 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
+
+    // Read list item size aid from layout data. Use it to determine how many
+    // items to show in listbox.
+    TAknLayoutRect listSizeAid;
+    listSizeAid.LayoutRect( aMaxRect, AknLayoutScalable_Apps::aid_size_list_single_double() );
+    TInt itemHeightAid = listSizeAid.Rect().Height();
+    
+    TInt maxItemsShown = maxViewRect.Height() / itemHeightAid;
+    if ( maxViewRect.Height() % itemHeightAid > itemHeightAid / 2 )
+        {
+        maxItemsShown++;
+        }
+    
+    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;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CurrentContactLinkL
+// 
+// -----------------------------------------------------------------------------
+//
+HBufC8* CEasyDialingListBox::CurrentContactLinkL()
+    {
+    TInt index = CurrentContactDataIndex();
+    if ( index >= 0 )
+        {
+        HBufC8* packedContact = iContactDataManager->ContactLinkLC( index );
+        CleanupStack::Pop( packedContact );
+        return packedContact;
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// HandleLongTapEventL
+// Callback from CAknLongTapDetector.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingListBox::HandleLongTapEventL( const TPoint& /*aPenEventLocation*/, 
+                                               const TPoint& /*aPenEventScreenLocation*/ )
+    {
+    ReportListBoxEventL( static_cast<MEikListBoxObserver::TListBoxEvent>
+            ( KEasyDialingContactLongTapped ) );
+    iPointerLongPressHandled = ETrue;
+    
+    TPointerEvent simulatedButtonUpEvent( TPointerEvent::EButton1Up, 0,
+                                          TPoint(), TPoint() );
+    TRAP_IGNORE( CEikFormattedCellListBox::HandlePointerEventL( simulatedButtonUpEvent ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// 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;
+        }
+    
+    // check if pointer event is over item
+    TInt itemIndex( KErrNotFound );
+    TPoint pointerPos( aPointerEvent.iPosition );
+    TBool pointerIsOverAnItem = iView->XYPosToItemIndex( pointerPos, itemIndex );
+    
+    // long tap is started only if pointer is over an actual item
+    // (not over margin or other empty listbox area)
+    if ( pointerIsOverAnItem || aPointerEvent.iType != TPointerEvent::EButton1Down )
+        {
+        iLongTapDetector->PointerEventL(aPointerEvent);
+        }
+    
+    if ( iPointerLongPressHandled )
+        {
+        // No further handling is made after long tap on list item
+        // has been detected.
+        return;
+        }
+
+    CEikFormattedCellListBox::HandlePointerEventL( aPointerEvent );
+    }
+
+
+// -----------------------------------------------------------------------------
+// HandleScrollEventL
+// If the EasyDialingListBox is scrolled by dragging the Scroll bar, this
+// observer function is called
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingListBox::HandleScrollEventL( CEikScrollBar* aScrollBar, TEikScrollEvent aEventType )
+    {
+    // Report scrolling to the listbox observer
+    TInt scrollEvent( KErrNotFound );
+    switch ( aEventType )
+        {
+        case EEikScrollThumbDragVert:
+            scrollEvent = KEasyDialingScrollingStarted;
+            break;
+
+        case EEikScrollThumbReleaseVert:
+        case EEikScrollUp:
+        case EEikScrollDown:
+        case EEikScrollPageUp:
+        case EEikScrollPageDown:
+            scrollEvent = KEasyDialingScrollingStopped;
+            break;
+            
+        default:
+            break;
+        }
+    
+    if ( scrollEvent != KErrNotFound )
+        {
+        ReportListBoxEventL( static_cast<MEikListBoxObserver::TListBoxEvent>( scrollEvent ) );
+        }
+    
+    // Base class(es) might be also interested about the scrollbar events
+    CEikFormattedCellListBox::HandleScrollEventL( aScrollBar, aEventType );
+    }
+
+// end of file
+