/*
* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* Support for CheckBoxes in Popped up setting pages
*
*/
#include "akncheckboxsettingpage.h"
// For icon support
#include <gulicon.h>
#include <barsread.h>
// For icon array support
#include <AknIconArray.h>
// lists
#include <aknlists.h>
#include <AknTasHook.h>
// Used for setting 0 and 1 in the radio button
_LIT(KOneSlashT, "1\t");
// Selectable Item Array
EXPORT_C CSelectableItem::CSelectableItem( TDesC& aItem, TBool aSelected ) :
iDesC(aItem), iSelected( aSelected )
{
}
EXPORT_C void CSelectableItem::ConstructL()
{
iItem = iDesC.AllocL();
}
CSelectableItem::~CSelectableItem()
{
delete ( iItem );
}
EXPORT_C void CSelectableItem::SetSelectionStatus( TBool aSelected )
{
iSelected = aSelected;
}
EXPORT_C TBool CSelectableItem::SelectionStatus()
{
return iSelected;
}
EXPORT_C TPtrC CSelectableItem::ItemText()
{
return (TPtrC)(*iItem);
}
EXPORT_C CSelectionItemList::CSelectionItemList(TInt aGranularity) : CArrayPtrFlat<CSelectableItem>( aGranularity )
{
}
EXPORT_C TInt CSelectionItemList::MdcaCount() const
{
return Count();
}
EXPORT_C TPtrC CSelectionItemList::MdcaPoint(TInt anIndex) const
{
return ( (TPtrC)( (At(anIndex))->ItemText() ));
}
// Extension for CAknCheckBoxSettingPage
NONSHARABLE_CLASS(CAknCheckBoxSettingPageExtension): public CBase
{
public:
CAknCheckBoxSettingPageExtension();
public:
TBool iIsDragged;
};
CAknCheckBoxSettingPageExtension::CAknCheckBoxSettingPageExtension()
: iIsDragged(EFalse)
{
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/**
* Destructor
*
*/
EXPORT_C CAknCheckBoxSettingPage::~CAknCheckBoxSettingPage()
{
AKNTASHOOK_REMOVE();
delete (iInternalItemArray);
delete iExtension;
}
EXPORT_C CAknCheckBoxSettingPage::CAknCheckBoxSettingPage( TInt aResourceId, CSelectionItemList* aItemArray):
CAknListBoxSettingPage(aResourceId), iItemArray(aItemArray)
{
AKNTASHOOK_ADD( this, "CAknCheckBoxSettingPage" );
}
EXPORT_C CAknCheckBoxSettingPage::CAknCheckBoxSettingPage(
const TDesC* aSettingText,
TInt aSettingNumber,
TInt aControlType,
TInt aEditorResourceId,
TInt aSettingPageResourceId,
CSelectionItemList* aItemArray )
: CAknListBoxSettingPage(
aSettingText,
aSettingNumber,
aControlType,
aEditorResourceId,
aSettingPageResourceId ),
iItemArray(aItemArray)
{
AKNTASHOOK_ADD( this, "CAknCheckBoxSettingPage" );
}
EXPORT_C void CAknCheckBoxSettingPage::ConstructL()
{
BaseConstructL();
iExtension = new(ELeave) CAknCheckBoxSettingPageExtension;
CreateCheckBoxBitmapsL();
// Only a reference to the CBase object; not owned
CAknSetStyleListBox* listBox = ListBoxControl();
//
// SelectItemL make the view item drawn by default, SetDisableRedraw can remove flick
//
TBool bRedrawDisabled = listBox->View()->RedrawDisabled();
listBox->View()->SetDisableRedraw( ETrue );
GenerateInternalArrayAndGiveToListBoxL();
listBox->View()->SetDisableRedraw( bRedrawDisabled );
// This updates the CBA
CheckAndSetDataValidity();
UpdateCbaL();
listBox->SetListBoxObserver(this);
// Set the scroller indication to appear when needed
listBox->CreateScrollBarFrameL(ETrue, ETrue);
listBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff,CEikScrollBarFrame::EAuto);
listBox->ItemDrawer()->FormattedCellData()->SetDrawScrollbarBackground( EFalse );
listBox->ScrollBarFrame()->VerticalScrollBar()->SetMopParent(this);
listBox->UpdateScrollBarsL();
if(!IsBackgroundDrawingEnabled())
listBox->ScrollBarFrame()->DrawBackground(EFalse, EFalse);
// To force the layout
SizeChanged();
// check and change MSK according to item selection status
CEikButtonGroupContainer *bgc;
CCoeControl* MSK(NULL);
CEikCba* cba(NULL);
MopGetObject(bgc);
TInt newResourceId(NULL);
if (bgc)
{
cba = ( static_cast<CEikCba*>( bgc->ButtonGroup() ) ); // downcast from MEikButtonGroup
if (cba)
{
MSK = cba->Control(3); // MSK's position is 3
}
}
TInt currentSelectionIndex = listBox->CurrentItemIndex();
if( iItemArray && iItemArray->Count() > 0 )
{
if (MSK && ( (cba->ControlId(MSK) == EAknSoftkeyMark) ||
(cba->ControlId(MSK) == EAknSoftkeyUnmark) ))
{
if( (*iItemArray)[currentSelectionIndex]->SelectionStatus() )
{
newResourceId = R_AVKON_SOFTKEY_UNMARK;
}
else
{
newResourceId = R_AVKON_SOFTKEY_MARK;
}
}
if (newResourceId)
{
bgc->SetCommandL(3,newResourceId);
cba->DrawDeferred();
}
}
// Construct an appropriate control context for the contained editor areas.
// Context produced is owned by CAknSettingPage.
SetEditedItemFrameIID( KAknsIIDQsnFrSetOpt, KAknsIIDQsnFrSetOptCenter );
}
EXPORT_C void CAknCheckBoxSettingPage::HandleListBoxEventL(CEikListBox* /*aListBox*/,
MEikListBoxObserver::TListBoxEvent aEventType)
{
if (!iExtension)
{
iExtension = new (ELeave) CAknCheckBoxSettingPageExtension;
}
switch ( aEventType )
{
// Fall through these things that should all cause the selection to change
case MEikListBoxObserver::EEventEnterKeyPressed:
case MEikListBoxObserver::EEventItemActioned:
case MEikListBoxObserver::EEventItemClicked:
case MEikListBoxObserver::EEventItemSingleClicked:
// select when no dragging
if ( !iExtension->iIsDragged )
{
ToggleSelectionL();
UpdateSettingL();
}
break;
case MEikListBoxObserver::EEventItemDraggingActioned:
case EEventPanningStarted:
case EEventFlickStarted:
iExtension->iIsDragged = ETrue;
break;
case MEikListBoxObserver::EEventPenDownOnItem:
iExtension->iIsDragged = EFalse;
if( iSettingPageObserver )
iSettingPageObserver->HandleSettingPageEventL(this, MAknSettingPageObserver::EEventSettingChanged);
break;
default:
break;
}
}
void CAknCheckBoxSettingPage::ToggleSelectionL()
{
CAknSetStyleListBox* listBox = ListBoxControl();
CListBoxView* view = listBox->View();
TInt currentSelectionIndex = listBox->CurrentItemIndex();
TInt newResourceId(NULL);
// Toggle based upon current master status
if( iItemArray && iItemArray->Count() > 0 )
{
if( (*iItemArray)[currentSelectionIndex]->SelectionStatus() )
{
view->DeselectItem( currentSelectionIndex );
( (*iItemArray)[ currentSelectionIndex ] )->SetSelectionStatus( EFalse );
newResourceId = R_AVKON_SOFTKEY_MARK;
}
else
{
view->SelectItemL( currentSelectionIndex );
( (*iItemArray)[ currentSelectionIndex ] )->SetSelectionStatus( ETrue );
newResourceId = R_AVKON_SOFTKEY_UNMARK;
}
}
// if the selection came from Mark/Unmark event from MSK, toggle also MSK
CEikButtonGroupContainer *bgc;
CCoeControl* MSK(NULL);
CEikCba* cba(NULL);
MopGetObject(bgc);
if (bgc)
{
cba = ( static_cast<CEikCba*>( bgc->ButtonGroup() ) ); // downcast from MEikButtonGroup
if (cba)
{
MSK = cba->Control(3); // MSK's position is 3
}
}
if (MSK && ( (cba->ControlId(MSK) == EAknSoftkeyMark) ||
(cba->ControlId(MSK) == EAknSoftkeyUnmark) ))
{
if (newResourceId)
{
bgc->SetCommandL(3,newResourceId);
cba->DrawNow();
}
}
if( iSettingPageObserver )
iSettingPageObserver->HandleSettingPageEventL(this, MAknSettingPageObserver::EEventSettingChanged);
}
EXPORT_C void CAknCheckBoxSettingPage::UpdateSettingL()
{
}
EXPORT_C CAknSetStyleListBox* CAknCheckBoxSettingPage::ListBoxControl() const
{
return STATIC_CAST( CAknSetStyleListBox*, EditorControl());
}
EXPORT_C void CAknCheckBoxSettingPage::DynamicInitL()
{
}
void CAknCheckBoxSettingPage::UpdateAllSelections()
{
TInt nItems = iItemArray->Count();
CAknSetStyleListBox* listBox = ListBoxControl();
CListBoxView* view = listBox->View();
for (TInt ii=0; ii<nItems; ii++)
{
(*iItemArray)[ ii ]->SetSelectionStatus( view->ItemIsSelected( ii ) );
}
}
void CAknCheckBoxSettingPage::SetAllSelectionsL()
{
TInt nItems = iItemArray->Count();
CAknSetStyleListBox* listBox = ListBoxControl();
CListBoxView* view = listBox->View();
for (TInt ii=0; ii<nItems; ii++)
{
if ( (*iItemArray)[ ii ]->SelectionStatus() )
view->SelectItemL( ii );
else
view->DeselectItem( ii );
}
}
/**
* Processes events from the softkeys. (Or tranlated from key events)
*
*
* @param aCommandId Event Id from the soft-key
*/
EXPORT_C void CAknCheckBoxSettingPage::ProcessCommandL(TInt aCommandId)
{
HideMenu();
// Respond to softkey events
switch (aCommandId)
{
case EAknSoftkeySelect:
{
if ( EnableSingleClickHighlight( aCommandId ) )
{
break;
}
// no single click mode was enabled, fall through
}
case EAknSoftkeyMark:
case EAknSoftkeyUnmark:
if ( AknLayoutUtils::PenEnabled() )
{
if (ListBoxControl()->View()->ItemIsVisible(ListBoxControl()->View()->CurrentItemIndex()))
{
SelectCurrentItemL();
}
else
{
// No exit in this case
ListBoxControl()->View()->ScrollToMakeItemVisible(ListBoxControl()->View()->CurrentItemIndex());
ListBoxControl()->UpdateScrollBarsL();
}
}
else
{
SelectCurrentItemL(); // No exit in this case
}
break;
case EAknSoftkeyOk:
case EAknSoftkeyDone:
if ( AknLayoutUtils::PenEnabled() )
{
// Pen support changes selection only in the view, do update for items here.
UpdateAllSelections();
}
AttemptExitL(ETrue);
break;
case EAknSoftkeyBack:
case EAknSoftkeyCancel:
AttemptExitL(EFalse);
break;
case EAknSoftkeyOptions:
DisplayMenuL();
break;
default:
break;
}
}
EXPORT_C void CAknCheckBoxSettingPage::SelectCurrentItemL()
{
ToggleSelectionL();
UpdateSettingL();
}
void CAknCheckBoxSettingPage::GenerateInternalArrayAndGiveToListBoxL()
{
delete iInternalItemArray;
iInternalItemArray = 0;
// Make a new owned text array from the input one:
iInternalItemArray = new(ELeave)CDesCArrayFlat(1);
TInt nItems = iItemArray->Count();
for (TInt ii=0; ii<nItems; ii++)
{
// Fill up the control-owned space for the modified buffers:
TInt newLen = ((*iItemArray)[ii]->ItemText()).Length() + KOneSlashT().Length();
HBufC* newText = HBufC::NewMaxLC( newLen );
TPtr newTPtr = newText->Des();
newTPtr.Copy( KOneSlashT );
newTPtr.Append( ((*iItemArray)[ii])->ItemText() );
// A copy of the new buffer goes to the internal itemarray:
iInternalItemArray->AppendL(newTPtr);
CleanupStack::PopAndDestroy(); // newText
}
CAknSetStyleListBox* listBox = ListBoxControl();
CTextListBoxModel* model=listBox->Model();
model->SetItemTextArray(iInternalItemArray);
model->SetOwnershipType(ELbmDoesNotOwnItemArray);
//
// let the list box not throw away pointer event
//
if( nItems > 0)
{
CArrayFix<TInt>* tmp = new(ELeave)CArrayFixFlat<TInt>(nItems);
CleanupStack::PushL( tmp );
for(TInt i=0; i<nItems; i++)
{
tmp->AppendL( i );
}
listBox->SetPointerEventFilterDisabledL( *tmp );
CleanupStack::PopAndDestroy( tmp );
}
// Transfer the selected status from the input array into the listbox view:
SetAllSelectionsL();
}
EXPORT_C void CAknCheckBoxSettingPage::SetSelectionItemArrayL( CSelectionItemList* aItemArray )
{
iItemArray = aItemArray;
GenerateInternalArrayAndGiveToListBoxL();
// This updates the CBA
CheckAndSetDataValidity();
UpdateCbaL();
SizeChanged();
DrawDeferred();
}
/**
* Writes the internal state of the control and its components to aStream.
* Does nothing in release mode.
* Designed to be overidden and base called by subclasses.
*/
#ifndef _DEBUG
EXPORT_C void CAknCheckBoxSettingPage::WriteInternalStateL(RWriteStream& /*aWriteStream*/) const
{}
#else
EXPORT_C void CAknCheckBoxSettingPage::WriteInternalStateL(RWriteStream& aWriteStream) const
{
CAknSettingPage::WriteInternalStateL(aWriteStream);
}
#endif
//---------------------------------------------------------------------------------------
// CAknCheckBoxSettingPage::HandlePointerEventL()
// Handles pointer events by removing Shift and Control button modifiers from it and
// sends modified pointerevent to CEikListbox. This prevents multiselection
//---------------------------------------------------------------------------------------
//
EXPORT_C void CAknCheckBoxSettingPage::HandlePointerEventL(const TPointerEvent& aPointerEvent)
{
if ( !iExtension )
{
iExtension = new(ELeave) CAknCheckBoxSettingPageExtension;
}
TPointerEvent newPointerEvent = aPointerEvent;
// Remove Shift and Ctrl modifiers from PointerEvent
newPointerEvent.iModifiers &= ~EModifierShift;
newPointerEvent.iModifiers &= ~EModifierCtrl;
// If click on an item, pressed down state draw. After dragging to other item
// or outside, item can not be selected.
CAknSetStyleListBox* listbox = ListBoxControl();
TInt index;
if ( newPointerEvent.iType == TPointerEvent::EButton1Down
&& listbox->View()->XYPosToItemIndex( newPointerEvent.iPosition, index ))
{
listbox->View()->ItemDrawer()->SetFlags( CListItemDrawer::EPressedDownState );
}
else if ( aPointerEvent.iType == TPointerEvent::EDrag
&& !listbox->Rect().Contains( aPointerEvent.iPosition ))
{
iExtension->iIsDragged = ETrue;
}
CAknListBoxSettingPage::HandlePointerEventL( aPointerEvent );
}
void CAknCheckBoxSettingPage::CreateCheckBoxBitmapsL()
{
// Only a reference to the CBase object; not owned
CAknSetStyleListBox* listBox = ListBoxControl();
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
// In case CAknPopupSettingList has already created the icons
if ( listBox->ItemDrawer()->FormattedCellData()->IconArray() )
{
listBox->ItemDrawer()->FormattedCellData()->IconArray()->ResetAndDestroy();
delete (listBox->ItemDrawer()->FormattedCellData()->IconArray());
}
TResourceReader reader;
// Original code used R_AVKON_SETTING_PAGE_CHECKBOX_ICONS but
// R_AVKON_RADIOBUTT_BMP defines the same icons.
iCoeEnv->CreateResourceReaderLC(reader, R_AVKON_SETTING_PAGE_CHECKBOX_ICONS);
reader.ReadInt16(); //not needed, simple or complex
HBufC* bmpFile = reader.ReadHBufCL();
TInt count = reader.ReadInt16(); // count
if(count<2)
User::Leave(KErrCorrupt);
TInt32 bmpSelected = reader.ReadInt32();
TInt32 bmpSelectedM = reader.ReadInt32();
TInt32 bmp = reader.ReadInt32();
TInt32 bmpM = reader.ReadInt32();
CleanupStack::PopAndDestroy(); // reader
if (bmpFile == NULL)
User::Leave(KErrCorrupt);
CleanupStack::PushL(bmpFile);
CArrayPtr<CGulIcon>* icons = new(ELeave) CAknIconArray(4);
// put on the cleanup stack until ownership is transferred
CleanupStack::PushL( icons );
// create normally colored icons
CreateIconAndAddToArrayL( icons,
KAknsIIDQgnIndiCheckboxOn,
EAknsCIQsnIconColorsCG14,
*bmpFile,
bmpSelected,
bmpSelectedM );
CreateIconAndAddToArrayL( icons,
KAknsIIDQgnIndiCheckboxOff,
EAknsCIQsnIconColorsCG14,
*bmpFile,
bmp,
bmpM );
// create highlight colored icons
CreateIconAndAddToArrayL( icons,
KAknsIIDQgnIndiCheckboxOn,
EAknsCIQsnIconColorsCG18,
*bmpFile,
bmpSelected,
bmpSelectedM );
CreateIconAndAddToArrayL( icons,
KAknsIIDQgnIndiCheckboxOff,
EAknsCIQsnIconColorsCG18,
*bmpFile,
bmp,
bmpM );
listBox->ItemDrawer()->FormattedCellData()->SetIconArrayL(icons); // ownership transferred, cell data deletes all members of list
listBox->ItemDrawer()->FormattedCellData()->UseHighlightIconSwapping( ETrue );
CleanupStack::Pop(); // icons - ownership now transferred; do not destroy
CleanupStack::PopAndDestroy(); // bmpfile
}
EXPORT_C void CAknCheckBoxSettingPage::HandleResourceChange(TInt aType)
{
if( aType == KAknsMessageSkinChange )
{
TRAP_IGNORE( CreateCheckBoxBitmapsL() );
}
CAknSettingPage::HandleResourceChange(aType);
}
/**
* Setting Page reserved methods
*/
EXPORT_C void* CAknCheckBoxSettingPage::ExtensionInterface( TUid /*aInterface*/ )
{
return NULL;
}
/**
* Reserved method derived from CCoeControl
*/
EXPORT_C void CAknCheckBoxSettingPage::Reserved_2()
{
}
/**
* Setting Page reserved methods
*/
EXPORT_C void CAknCheckBoxSettingPage::CAknSettingPage_Reserved_1()
{
}
EXPORT_C void CAknCheckBoxSettingPage::CAknSettingPage_Reserved_2()
{
}
/**
* CAknListBoxSettingPage-derived reserved methods
*/
EXPORT_C void CAknCheckBoxSettingPage::CAknListBoxSettingPage_Reserved_1()
{
}
// End of File