/*
* Copyright (c) 2009-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: UI status control
*
*/
#include "ccappstatuscontrol.h"
#include "MVPbkContactLink.h"
#include "TPbk2IconId.h"
#include <eikimage.h>
#include <eiklabel.h>
#include <AknIconUtils.h>
#include <aknutils.h>
#include <avkon.mbg>
#include <gulicon.h>
#include <stringloader.h>
#include <aknsframebackgroundcontrolcontext.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <AknsUtils.h>
#include <AknsDrawUtils.h>
#include <touchfeedback.h>
#include <aknlayoutscalable_apps.cdl.h>
#include <Pbk2PresentationUtils.h>
namespace {
/// Amount of child UI components
const TInt KControlCount = 3; // image & label x 2
/// Max amount of lines used to show status text. Rest will be clipped
const TInt KStatusTextLines = 2;
const TText KGraphicReplaceCharacter = ' ';
inline CGulIcon* CreateEmptyIconL()
{
CFbsBitmap* image = NULL;
CFbsBitmap* mask = NULL;
AknIconUtils::CreateIconL( image, mask,
AknIconUtils::AvkonIconFileName(),
EMbmAvkonQgn_prop_empty,
EMbmAvkonQgn_prop_empty_mask );
return CGulIcon::NewL( image, mask );
}
inline void ReSizeIcon( CGulIcon* aIcon, const TSize& aSize )
{
if( aIcon )
{
CFbsBitmap* bitmap = aIcon->Bitmap();
CFbsBitmap* mask = aIcon->Mask();
if( bitmap )
{
AknIconUtils::SetSize( bitmap, aSize, EAspectRatioPreservedAndUnusedSpaceRemoved );
}
if( mask )
{
AknIconUtils::SetSize( mask, aSize, EAspectRatioPreservedAndUnusedSpaceRemoved );
}
}
}
} // namespace
// ---------------------------------------------------------------------------
// CCCAppStatusControl::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CCCAppStatusControl* CCCAppStatusControl::NewL(
CSpbContentProvider& aContentProvider, MCCAStatusControlObserver& aObserver )
{
CCCAppStatusControl* self= new(ELeave) CCCAppStatusControl( aContentProvider, aObserver );
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::CCCAppStatusControl
// ---------------------------------------------------------------------------
//
CCCAppStatusControl::CCCAppStatusControl(
CSpbContentProvider& aContentProvider, MCCAStatusControlObserver& aObserver ) :
iContentProvider( aContentProvider ),
iObserver( aObserver ),
iDefaultResource( KErrNotFound )
{
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::ConstructL
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::ConstructL()
{
// Create status icon image
iStatusImage = new( ELeave ) CEikImage;
iStatusImage->SetAlignment( EHCenterVCenter );
iStatusImage->SetPictureOwnedExternally( ETrue );
iStatusImage->SetBrushStyle( CGraphicsContext::ENullBrush ); // transparent
iStatusImage->MakeVisible( EFalse );
// Create status text label
iStatusLabel1 = new( ELeave ) CEikLabel;
iStatusLabel1->SetAlignment( EHLeftVCenter );
iStatusLabel1->SetTextL( KNullDesC() ); // CEikLabel will panic without text
iStatusLabel1->MakeVisible( EFalse );
iStatusLabel2 = new( ELeave ) CEikLabel;
iStatusLabel2->SetAlignment( EHLeftVCenter );
iStatusLabel2->SetTextL( KNullDesC() ); // CEikLabel will panic without text
iStatusLabel2->MakeVisible( EFalse );
iStatusText = KNullDesC().AllocL();
iContentProvider.AddObserverL( *this );
iBgContext = CAknsFrameBackgroundControlContext::NewL(
KAknsIIDNone, TRect(), TRect(), EFalse );
// normal state by default
iBgContext->SetFrame( KAknsIIDQsnFrButtonNormal );
iBgContext->SetCenter( KAknsIIDQsnFrButtonCenterNormal );
// stylus feedback support
iTouchFeedBack = MTouchFeedback::Instance();
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::~CCCAppStatusControl
// ---------------------------------------------------------------------------
//
CCCAppStatusControl::~CCCAppStatusControl()
{
if( iTouchFeedBack )
{
iTouchFeedBack->RemoveFeedbackForControl( this );
}
iContentProvider.RemoveObserver( *this );
delete iStatusImage;
delete iStatusIcon;
delete iStatusLabel1;
delete iStatusLabel2;
delete iStatusText;
delete iDefaultIcon;
delete iBgContext;
delete iLink;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::SetPressed
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::SetPressed( TBool aPressed )
{
if( iPressed != aPressed )
{
iPressed = aPressed;
if( iPressed )
{
// pressed
iBgContext->SetFrame( KAknsIIDQsnFrButtonPressed );
iBgContext->SetCenter( KAknsIIDQsnFrButtonCenterPressed );
DrawNow(); // respond quickly to user event
}
else
{
// normal
iBgContext->SetFrame( KAknsIIDQsnFrButtonNormal );
iBgContext->SetCenter( KAknsIIDQsnFrButtonCenterNormal );
DrawDeferred();
}
}
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::IsPressed
// ---------------------------------------------------------------------------
//
TBool CCCAppStatusControl::IsPressed()
{
return iPressed;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::CountComponentControls
// ---------------------------------------------------------------------------
//
EXPORT_C void CCCAppStatusControl::SetContactLinkL( MVPbkContactLink& aLink )
{
delete iLink;
iLink = NULL;
iLink = aLink.CloneLC();
CleanupStack::Pop(); // iLink
delete iStatusText;
iStatusText = NULL;
TPbk2IconId iconId;
CSpbContentProvider::TSpbContentType type = CSpbContentProvider::ETypeNone;
iContentProvider.GetContentL( *iLink, iStatusText, iconId, type );
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::SetDefaultStatusL
// ---------------------------------------------------------------------------
//
EXPORT_C void CCCAppStatusControl::SetDefaultStatusL( TInt aDefaultResource,
CGulIcon* aDefaultStatusIcon )
{
iDefaultResource = aDefaultResource;
delete iDefaultIcon;
iDefaultIcon = aDefaultStatusIcon;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::CountComponentControls
// ---------------------------------------------------------------------------
//
TInt CCCAppStatusControl::CountComponentControls() const
{
return KControlCount;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::ComponentControl
// ---------------------------------------------------------------------------
//
CCoeControl* CCCAppStatusControl::ComponentControl( TInt aIndex ) const
{
switch( aIndex )
{
case 0:
{
return iStatusImage;
}
case 1:
{
return iStatusLabel1;
}
case 2:
{
return iStatusLabel2;
}
}
return NULL;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::SetVariableLayouts
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::SetVariableLayouts( TInt aOption )
{
const TRect rect(Rect());
// set background graphics layout
TAknWindowComponentLayout innerLayout(
AknLayoutScalable_Apps::bg_button_pane_cp033( aOption ) );
TAknLayoutRect innerLayoutRect;
innerLayoutRect.LayoutRect( rect, innerLayout.LayoutLine() );
TRect innerRect( innerLayoutRect.Rect() );
iBgContext->SetFrameRects( rect, innerRect );
// status icon
TAknWindowComponentLayout statusIconLayout(
AknLayoutScalable_Apps::phob2_cc_button_pane_g1( aOption ) );
TAknLayoutRect statusIconLayoutRect;
statusIconLayoutRect.LayoutRect( Rect(), statusIconLayout.LayoutLine() );
TRect statusIconRect( statusIconLayoutRect.Rect() );
iStatusIconSize = statusIconRect.Size();
iStatusImage->SetRect( statusIconRect );
// status label 1
AknLayoutUtils::LayoutLabel(
iStatusLabel1,
rect,
AknLayoutScalable_Apps::phob2_cc_button_pane_t1( aOption ) );
// resize images for new resolution
ReSizeIcon( iStatusIcon, iStatusIconSize );
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::SizeChanged
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::SizeChanged()
{
const TRect rect( Rect() );
// update stylus feedback
if( iTouchFeedBack )
{
iTouchFeedBack->ChangeFeedbackArea( this, 0, rect );
}
// status label 2
AknLayoutUtils::LayoutLabel(
iStatusLabel2,
rect,
AknLayoutScalable_Apps::phob2_cc_button_pane_t2( 0 ) );
TInt count(0);
// If this leaves, it means we're out of memory. Nothing we can do.
TRAP_IGNORE( count = RewrapStatusTextL() );
TInt option( 1 );
if( count > 1 )
{
option = 0;
}
SetVariableLayouts( option );
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::HandlePointerEventL
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::HandlePointerEventL(
const TPointerEvent& aPointerEvent)
{
CCoeControl::HandlePointerEventL( aPointerEvent );
if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
{
SetPressed( ETrue );
}
else if ( aPointerEvent.iType == TPointerEvent::EButton1Up )
{
SetPressed( EFalse );
if( Rect().Contains( aPointerEvent.iPosition ) )
{
// stylus released inside the button area
iObserver.StatusClickedL();
}
}
else if( aPointerEvent.iType == TPointerEvent::EDrag )
{
if( Rect().Contains( aPointerEvent.iPosition ) )
{
// stylus moved inside the button area
SetPressed( ETrue );
}
else
{
// stylus moved outside the button area
SetPressed( EFalse );
}
}
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::SetContainerWindowL
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::SetContainerWindowL(
const CCoeControl& aContainer )
{
CCoeControl::SetContainerWindowL( aContainer );
// Assign window for child controls too
TInt childCount = CountComponentControls();
for( TInt i = 0; i < childCount; ++i )
{
ComponentControl( i )->SetContainerWindowL( *this );
}
// stylus feedback can be set only after we have parent control (window owning)
if( iTouchFeedBack )
{
CFeedbackSpec* spec = CFeedbackSpec::New();
if( spec )
{
spec->AddFeedback( ETouchEventStylusDown, ETouchFeedbackBasicButton );
iTouchFeedBack->SetFeedbackArea( this, 0, Rect(), spec );
delete spec;
}
}
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::ContentUpdated
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::ContentUpdated( MVPbkContactLink& aLink,
MSpbContentProviderObserver::TSpbContentEvent aEvent )
{
TRAP_IGNORE( DoStatusUpdateL( aLink, aEvent ) );
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::DoStatusUpdateL
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::DoStatusUpdateL( MVPbkContactLink& aLink,
MSpbContentProviderObserver::TSpbContentEvent aEvent )
{
if( aEvent == EContentNotAvailable )
{
DefaultStatusL();
return;
}
if( iLink && iLink->IsSame( aLink ) )
{
delete iStatusText;
iStatusText = NULL;
TPbk2IconId iconId;
CSpbContentProvider::TSpbContentType type = CSpbContentProvider::ETypeNone;
iContentProvider.GetContentL( aLink, iStatusText, iconId, type );
TInt count( RewrapStatusTextL() );
TInt option( 1 );
if( count > 1 )
{
option = 0;
}
SetVariableLayouts( option );
CGulIcon* icon = NULL;
TRAP_IGNORE(
{
icon = iContentProvider.CreateServiceIconLC( iconId );
CleanupStack::Pop( icon );
} );
if( !icon )
{
icon = CreateEmptyIconL();
}
delete iStatusIcon;
// iStatusIcon owns bitmaps
iStatusIcon = icon;
ReSizeIcon( iStatusIcon, iStatusIconSize );
iStatusImage->SetPicture( iStatusIcon->Bitmap(), iStatusIcon->Mask() );
iStatusImage->MakeVisible( ETrue );
DrawDeferred();
}
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::RewrapStatusTextToArrayL
// ---------------------------------------------------------------------------
//
inline void CCCAppStatusControl::RewrapStatusTextToArrayL(
TDes& aStatusText,
CArrayFix<TPtrC>& aTxtArray )
{
// generate array of line lengths
CArrayFixFlat<TInt>* array =
new(ELeave) CArrayFixFlat<TInt>( KStatusTextLines );
CleanupStack::PushL( array );
// check width and font from label 2, because label 2 layout is
// set before this function is called
const TInt width( iStatusLabel2->Size().iWidth );
array->AppendL( width );
array->AppendL( width );
const CFont* font = iStatusLabel2->Font();
// wrap text
AknTextUtils::WrapToArrayAndClipL(
aStatusText,
*array,
*font,
aTxtArray );
CleanupStack::PopAndDestroy( array );
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::RewrapStatusTextL
// ---------------------------------------------------------------------------
//
TInt CCCAppStatusControl::RewrapStatusTextL()
{
TInt txtCount(0);
if( iStatusText )
{
HBufC* statusTxtBuffer = iStatusText->AllocLC();
TPtr statusTxt( statusTxtBuffer->Des() );
// replace non-allowed characters with ' '
Pbk2PresentationUtils::ReplaceNonGraphicCharacters(
statusTxt, KGraphicReplaceCharacter );
AknTextUtils::ReplaceCharacters(
statusTxt,
KAknCommonWhiteSpaceCharacters,
KGraphicReplaceCharacter );
// generate array of line lengths
CArrayFixFlat<TPtrC>* txtArray =
new (ELeave) CArrayFixFlat<TPtrC>(KStatusTextLines);
CleanupStack::PushL( txtArray );
RewrapStatusTextToArrayL( statusTxt, *txtArray );
// assign new text
TPtrC label1(KNullDesC);
TPtrC label2(KNullDesC);
txtCount = txtArray->Count();
switch (txtCount)
{
case 1:
{
label1.Set( txtArray->At(0) );
iStatusLabel1->MakeVisible( ETrue );
iStatusLabel2->MakeVisible( EFalse );
break;
}
case 2:
{
label1.Set( txtArray->At(0) );
label2.Set( txtArray->At(1) );
iStatusLabel1->MakeVisible( ETrue );
iStatusLabel2->MakeVisible( ETrue );
break;
}
default:
{
}
}
iStatusLabel1->SetTextL( label1 );
iStatusLabel2->SetTextL( label2 );
CleanupStack::PopAndDestroy( 2, statusTxtBuffer ); // txtArray
DrawDeferred();
}
return txtCount;
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::Draw
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::Draw( const TRect& /*aRect*/ ) const
{
TRect rect( Rect() );
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
CWindowGc& gc = SystemGc();
// draw skinned background
if( !AknsDrawUtils::Background( skin, iBgContext, NULL,
gc, rect, KAknsDrawParamNoClearUnderImage ) )
{
// if skin fails then draw solid colors
gc.SetBrushColor( iPressed ? KRgbDarkGray : KRgbGray );
gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
gc.DrawRect( rect );
}
}
// ---------------------------------------------------------------------------
// CCCAppStatusControl::DefaultStatusL
// ---------------------------------------------------------------------------
//
void CCCAppStatusControl::DefaultStatusL()
{
if( iDefaultResource != KErrNotFound )
{
delete iStatusText;
iStatusText = NULL;
iStatusText = StringLoader::LoadL( iDefaultResource );
const TInt count( RewrapStatusTextL() );
TInt option( 1 );
if( count > 1 )
{
option = 0;
}
SetVariableLayouts( option );
}
if( iDefaultIcon )
{
delete iStatusIcon;
iStatusIcon = NULL;
iStatusIcon = CGulIcon::NewL( iDefaultIcon->Bitmap(), iDefaultIcon->Mask() );
iStatusIcon->SetBitmapsOwnedExternally( ETrue ); // iDefaultIcon owns bitmaps
ReSizeIcon( iStatusIcon, iStatusIconSize );
iStatusImage->SetPicture( iDefaultIcon->Bitmap(), iDefaultIcon->Mask() );
iStatusImage->MakeVisible( ETrue );
DrawDeferred();
}
}
// End of file