diff -r ae942d28ec0e -r 2455ef1f5bbc javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupListBox.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupListBox.cpp Wed Sep 01 12:33:18 2010 +0100 @@ -0,0 +1,589 @@ +/* +* Copyright (c) 2003-2006 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: The CMIDChoiceGroup listbox +* +*/ + + +#include "CMIDChoiceGroupListBox.h" +// API for iChoiceControl +#include "CMIDChoiceGroupControl.h" +#include "CMIDChoiceGroupModel.h" + +#include +// using for CColumnListBoxData related to colors +// and in HandleResourceChange function - setting icon array +#include +#include +#include +#include +#include +#include + +// LAF +// AknLayoutScalable_Avkon::list_single_pane_cp2 +#include // LAF + +#include + +#undef TRAP_INSTRUMENTATION_LEAVE +#define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDChoiceGroupListBox.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult); + + +CMIDChoiceGroupListBox::CMIDChoiceGroupListBox(CMIDChoiceGroupControl* aChoiceControl) + : CAknColumnListBox() + , iChoiceControl(aChoiceControl) +#ifdef RD_JAVA_S60_RELEASE_9_2 + , iHighlight(EFalse) + , iTopVisibleItemIndex(KErrNotFound) +#endif // RD_JAVA_S60_RELEASE_9_2 +{ + ASSERT(iChoiceControl); +} + +CMIDChoiceGroupListBox::~CMIDChoiceGroupListBox() +{ +} + +// Constructs the listbox with the model created and owned outside. +// Makes sure the EKeepModel flag is set, in order to not destroy +// the model when listbox is destroyed +void CMIDChoiceGroupListBox::ConstructL( + const CCoeControl* aParent, + TInt aFlags, + CMIDChoiceGroupModel* aModel) +{ + // Model is owned outside, set it here, so that when + // CCAknColumnListBox::ConstructL() calls CreateModelL(), + // it is already in place. Absolutely make sure that the + // model owned outside flag is set + iModel = aModel; + aFlags |= EKeepModel; + + CAknColumnListBox::ConstructL(aParent, aFlags); + iListBoxFlags &= ~ELoopScrolling; + + if (iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup) + { + TAknLayoutRect layoutRect; + // layout in respect of the screen as only the height is needed + layoutRect.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(), AknLayoutScalable_Avkon::list_single_pane_cp2(0).LayoutLine()); + SetItemHeightL(layoutRect.Rect().Height()); + } +#ifndef RD_JAVA_FOR_S60_5_0_w49_2008 + else + { + // Disable flick/panning functionality + // Disbled in OMJ DisableScrolling( ETrue ); + } +#endif // RD_JAVA_FOR_S60_5_0_w49_2008 + +#ifdef RD_SCALABLE_UI_V2 + SetAllowStrayPointers(); +#endif + +#ifdef RD_TACTILE_FEEDBACK + iFeedback = MTouchFeedback::Instance(); +#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK + iFeedback->EnableFeedbackForControl(this, FALSE); +#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK +#endif //RD_TACTILE_FEEDBACK + +} + +// Overridden, because CEikListBox returns EKeyWasConsumed when +// up is pressed on the first item, or down on last. We need to +// return not consumed in order to make the form move focus +// to other items +// Offers key events to the listbox +TKeyResponse CMIDChoiceGroupListBox::OfferKeyEventL( + const TKeyEvent& aKeyEvent, + TEventCode aType) +{ + // First save the currently selected item + TInt oldCurrent = iView->CurrentItemIndex(); + + TKeyResponse resp = EKeyWasNotConsumed; + +#ifdef RD_JAVA_S60_RELEASE_9_2 + if (iChoiceControl->ChoiceType() != MMIDChoiceGroup::EPopup) + { + if (aType != EEventKey || iHighlight) + { + // Do not pass the EEventKey to ListBox in case of first + // HW key action after highlight was disabled. + resp = CAknColumnListBox::OfferKeyEventL(aKeyEvent, aType); + } + else + { + // This is first HW key action after highlight was disabled: + // highlight should be enabled + UpdateTopVisibleItemIndex(); + if (iTopVisibleItemIndex > KErrNotFound) + { + // First top visible element should be highlighted + iView->SetCurrentItemIndex(iTopVisibleItemIndex); + + // Item drawer must know, that highlight should be enabled + // from now. + if (IsHighlightNeeded(oldCurrent,aKeyEvent)) + { + SingleClickDisableHighlightL(EFalse); + } + resp = EKeyWasConsumed; + iTopVisibleItemIndex = KErrNotFound; + } + // Enable highlight flag for this ChoiceGroup, even if top visible + // element wasn't found (ChoiceGroup is now fully invisible). + iHighlight = ETrue; + } + } + else + { + // For popup ChoiceGroup, handle key events in usual way + resp = CAknColumnListBox::OfferKeyEventL(aKeyEvent, aType); + } +#else + // Let the ListBox handle the key + resp = CAknColumnListBox::OfferKeyEventL(aKeyEvent, aType); +#endif // RD_JAVA_S60_RELEASE_9_2 + + if (iChoiceControl->ChoiceType() != MMIDChoiceGroup::EPopup) + { + // If the key was up or down, and the current item did not change, + // we were apparently already on the first or last item. + // Return EKeyWasNotConsumed so that the form knows to transfer focus + // BUT ONLY if not used in a popup (otherwise the form will get it and + // move focus under the popup) + if (!IsHighlightNeeded(oldCurrent,aKeyEvent)) + { + resp = EKeyWasNotConsumed; + } + } + + //For Popup ChoiceGroup in landscape mode we have to redraw listbox + //to display background properly + if (iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup && + Layout_Meta_Data::IsLandscapeOrientation() && + (aKeyEvent.iCode == EKeyUpArrow || + aKeyEvent.iCode == EKeyDownArrow)) + { + DrawDeferred(); + } + + return resp; +} + + +// Overridden in order to prevent the listbox from creating its +// own model. +void CMIDChoiceGroupListBox::CreateModelL() +{ + // Model should've already been given + ASSERT(iModel); + if (!iModel) + { + User::Leave(KErrArgument); + } +} + +void CMIDChoiceGroupListBox::SizeChanged() +{ + // Because SizeChanged() is the only method called by CAknPopupList during a screen + // resolution change, we must call these two in here. If we don't, + // open popup dialogs do not update their content during a screen resolution change + // @see CMIDChoiceGroupListBox::HandleResolutionChange() and CAknPopupList::HandleResolutionChange(). + if (iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup) + { + TRAP_IGNORE( + iChoiceControl->SetupColumnsL(ItemDrawer()->ColumnData()); + TAknLayoutRect layoutRect; + // layout in respect of the screen as only the height is needed + layoutRect.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(), AknLayoutScalable_Avkon::list_single_pane_cp2(0).LayoutLine()); + SetItemHeightL(layoutRect.Rect().Height()); + ); + } + + CAknColumnListBox::SizeChanged(); + + // Assure that non-popup choicegroup is updated correctly visually + // after dynamic resolution change. + TInt lbHeight = Rect().Height(); + TInt lbItemHeight = iItemHeight; + + // check that listbox's size is already set + if ((lbHeight > 0) && (lbItemHeight > 0) && (lbHeight >= lbItemHeight) && + iChoiceControl && + (iChoiceControl->ChoiceType() != MMIDChoiceGroup::EPopup)) + { + TInt topItemIndex = TopItemIndex(); + TInt bottomItemIndex = BottomItemIndex(); + TInt currentItemIndex = CurrentItemIndex(); + TInt numOfItems = (Model()) ? Model()->NumberOfItems() : 0; + + // check that listbox-view is set correctly + if ((topItemIndex >= 0) && (bottomItemIndex >= topItemIndex) && + (bottomItemIndex < numOfItems) && + (currentItemIndex >= topItemIndex) && + (currentItemIndex <= bottomItemIndex)) + { + // number of actually/possible visible items + TInt numOfActuallyVisibleItems = bottomItemIndex - topItemIndex + 1; + TInt numOfPossiblyVisibleItems = lbHeight / lbItemHeight; + + // detect if it is possible to display more items than it is + // currently displayed (this indicates that listbox-view is not + // updated correctly after dynamic resolution change) and + // eventually update listbox-view's top-item-index + if ((numOfPossiblyVisibleItems > numOfActuallyVisibleItems) && + (topItemIndex >= numOfPossiblyVisibleItems - + numOfActuallyVisibleItems)) + { + topItemIndex -= numOfPossiblyVisibleItems - + numOfActuallyVisibleItems; + SetTopItemIndex(topItemIndex); + } + } + } +} + +void CMIDChoiceGroupListBox::Draw(const TRect& aRect) const +{ + //For Popup ChoiceGroup we have to draw its background, + //because native side doesn't do that properly. + if (iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup) + { + CWindowGc& gc = SystemGc(); + MAknsControlContext* cc = NULL; + //create background context: + //KAknsIIDQsnFrPopupCenter - id of proper background + //for popup dialog, background is without borders + TRAP_IGNORE(cc = CAknsBasicBackgroundControlContext::NewL( + KAknsIIDQsnFrPopupCenter, + aRect, + EFalse)); + if (cc) + { + //draw background + AknsDrawUtils::DrawBackground( + AknsUtils::SkinInstance(), + cc, + NULL, + gc, + Position(), //current listobox position on popup dialog + aRect, + KAknsDrawParamDefault); + } + } + + CAknColumnListBox::Draw(aRect); +} + +TTypeUid::Ptr CMIDChoiceGroupListBox::MopSupplyObject(TTypeUid aId) +{ + if (iChoiceControl->ChoiceType() != MMIDChoiceGroup::EPopup) + { + return iChoiceControl->MopSupplyObject(aId); + } + else // no skinned background in popup list + { + return CAknColumnListBox::MopSupplyObject(aId); + } +} + +/** This is currently only used for the open popup choice group items. For the normal +closed items at the moment form won't pass the notification to them. They are instead +recreated on a screen resolution change. See CMIChoiceGroupItem::ResolutionChange() and +CMIChoiceGroupItem::ColorChange(). */ +void CMIDChoiceGroupListBox::HandleResourceChange(TInt aType) +{ + if (aType == KEikColorResourceChange || + aType == KAknsMessageSkinChange || aType == KUidValueCoeColorSchemeChangeEvent) + {//skin or color scheme have changed + TRAP_IGNORE(((CMIDChoiceGroupModel*)Model())->ReConstructSelectionIconsL()); + ItemDrawer()->ColumnData()->SetIconArray(((CMIDChoiceGroupModel*)Model())->IconArray(ETrue)); + + SetTextColors(); + } + else if (aType == KEikDynamicLayoutVariantSwitch) + { + // NOTE for the open popup choicegroup items: + // CAknPopupList never calls HandleResourceChange() on the list box when aType + // is KEikDynamicLayoutVariantSwitch so do not put any code here, + // SizeChanged() will be called instead. + } + + CAknColumnListBox::HandleResourceChange(aType); +} + +/** Initialise the listbox text and background colors with values + from LAF first, and then from the skin if this is supported. */ +void CMIDChoiceGroupListBox::SetTextColors() +{ + CColumnListBoxData::TColors colors; + + colors.iText = AKN_LAF_COLOR_STATIC(215); + colors.iHighlightedText = AKN_LAF_COLOR_STATIC(0); + + if (AknsUtils::AvkonSkinEnabled()) + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + TRgb color; + + // icon color, checkbox, radio button + TInt error = AknsUtils::GetCachedColor(skin, + color, + KAknsIIDQsnIconColors, + EAknsCIQsnIconColorsCG14); + + if (!error) + { + colors.iText = color; + } + + // icon color, setting list highlight checkbox, radio button + error = AknsUtils::GetCachedColor(skin, + color, + KAknsIIDQsnIconColors, + EAknsCIQsnIconColorsCG14); + + if (!error) + { + colors.iHighlightedText = color; + } + } + + View()->ItemDrawer()->SetTextColor(colors.iText); + View()->ItemDrawer()->SetHighlightedTextColor(colors.iHighlightedText); +} + + +void CMIDChoiceGroupListBox::PositionChanged() +{ + // Code copied from CEikListBox::SizeChanged() + TRect clientRect = iBorder.InnerRect(Rect()); + SetViewRectFromClientRect(clientRect); +} + +#ifdef RD_SCALABLE_UI_V2 +void CMIDChoiceGroupListBox::HandlePointerEventL(const TPointerEvent& aPointerEvent) +{ +#ifdef RD_JAVA_S60_RELEASE_9_2 + if (aPointerEvent.iType == TPointerEvent::EButton1Down) + { + iUpEventSent = EFalse; + iHighlight = EFalse; + UpdateTopVisibleItemIndex(); + } +#endif // RD_JAVA_S60_RELEASE_9_2 + + // In non-popup case, don't forward to base class the drag events + // that occur outside the listbox + +#ifdef RD_TACTILE_FEEDBACK + if ((aPointerEvent.iType == TPointerEvent::EButton1Down || + aPointerEvent.iType == TPointerEvent::EButton1Up) && + iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup) + { +#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK + iFeedback->InstantFeedback(ETouchFeedbackList); +#else + iFeedback->InstantFeedback(ETouchFeedbackBasic); +#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK + } +#endif //RD_TACTILE_FEEDBACK + +#ifndef RD_JAVA_S60_RELEASE_9_2 + if (iChoiceControl->ChoiceType() != MMIDChoiceGroup::EPopup && + aPointerEvent.iType == TPointerEvent::EDrag) + { + + if (!View()->ViewRect().Contains(aPointerEvent.iPosition)) + { + return; + } + else + { + + // this flag must be set in order that drag events can change + // the focused listbox item + iListBoxFlags |= ELeftDownInViewRect; + } + } +#endif // RD_JAVA_S60_RELEASE_9_2 + +#ifdef RD_JAVA_S60_RELEASE_9_2 + if (aPointerEvent.iType == TPointerEvent::EDrag && !iUpEventSent && iChoiceControl->Form()->PhysicsScrolling()) + { + TPointerEvent pointerEvent = aPointerEvent; + pointerEvent.iType = TPointerEvent::EButton1Up; + CAknColumnListBox::HandlePointerEventL(pointerEvent); + iUpEventSent = ETrue; + } + else if (!iUpEventSent) + { +#endif // RD_JAVA_S60_RELEASE_9_2 + CAknColumnListBox::HandlePointerEventL(aPointerEvent); +#ifdef RD_JAVA_S60_RELEASE_9_2 + if (aPointerEvent.iType == TPointerEvent::EButton1Up) + { + iUpEventSent = ETrue; + } + } + +#endif // RD_JAVA_S60_RELEASE_9_2 + + //For Popup ChoiceGroup in landscape mode we have to redraw listbox + //to display background properly + if (iChoiceControl->ChoiceType() == MMIDChoiceGroup::EPopup && + Layout_Meta_Data::IsLandscapeOrientation()) + { + DrawDeferred(); + } +} +#endif + +/** + * Checks if highlight is needed + * Returns EFalse if there should be no highlight + */ +TBool CMIDChoiceGroupListBox::IsHighlightNeeded(TInt aCurrentSelected, + const TKeyEvent& aKeyEvent) +{ + // If the key was up or down, and the current item did not change, + // we were apparently already on the first or last item. + // Return EFalse when highlight should be lost + TBool isHighlightNeeded = ETrue; + TInt newCurrent = iView->CurrentItemIndex(); + TBool change = aCurrentSelected != newCurrent; + TInt lastItemIdx = KErrNotFound; + + if (iModel) + { + lastItemIdx = iModel->NumberOfItems() - 1; + } + if ((aKeyEvent.iCode == EKeyUpArrow) && !change && (newCurrent == 0)) + { + isHighlightNeeded = EFalse; + } + if ((aKeyEvent.iCode == EKeyDownArrow) && !change && + (newCurrent == lastItemIdx)) + { + isHighlightNeeded = EFalse; + } + return isHighlightNeeded; +} + +#ifdef RD_JAVA_S60_RELEASE_9_2 +/** + * Returns index of ChoiceGroup element, which is the first + * visible element in ChoiceGroup from top of Form. + * Used in CMIDChoiceGroupControl, which needs to know + * current element for possible scrolling + * (@see CMIDChoiceGroupControl::RequestScrollIfNeededL()). + */ +TInt CMIDChoiceGroupListBox::TopVisibleItemIndex() +{ + return iTopVisibleItemIndex; +} + +/** + * Fuction calculates index of element, which is the first + * visible element in ChoiceGroup from top of Form. + */ +void CMIDChoiceGroupListBox::UpdateTopVisibleItemIndex() +{ + if (!iHighlight) + { + // There is touch interaction, so we need index for element, + // which will be highlighted, when user starts using HW keys + if (iPosition.iY < 0) + { + // ChoiceGroup is now partially visible and its top edge is + // above the Form top edge. + + // Calculate index of first (partially) visible element + iTopVisibleItemIndex = Abs(iPosition.iY) / iView->ItemHeight(); + TRect lbitemRect = TRect( + iView->ItemPos(iTopVisibleItemIndex), + iView->ItemSize(iTopVisibleItemIndex)); + if (lbitemRect.iTl.iY < 0) + { + // Item is really partially visible. + // Because we don't want index of partially visible item, + // move index to next item + iTopVisibleItemIndex++; + } + if (iTopVisibleItemIndex >= iModel->NumberOfItems()) + { + // ChoiceGroup is fully invisible (whole rect is above + // the Form top edge): no element is visible now + iTopVisibleItemIndex = KErrNotFound; + } + } + else + { + // Top item idge is lower than top edge of Form - is visible + iTopVisibleItemIndex = 0; + } + } + else + { + // In case of HW keys interaction, there is no highlight, + // so we don't need highlight any element + iTopVisibleItemIndex = KErrNotFound; + } +} +/** + * Fuction sets ESingleClickDisabledHighlight - item drawer flags + * and reports current highlight element change event + */ +void CMIDChoiceGroupListBox::SingleClickDisableHighlightL(TBool aDisable) +{ + // Item drawer must know, that highlight should be enabled/disabled + // when listbox element taped + CColumnListBoxItemDrawer* drawer = ItemDrawer(); + if (drawer) + { + if (aDisable) + { + if (iHighlight) + { + // Set flags in Item drawer so that highlight could be disabled + drawer->SetFlags(CListItemDrawer::ESingleClickDisabledHighlight); + iHighlight = EFalse; + iTopVisibleItemIndex = KErrNotFound; + } + } + else + { + // Set flags in Item drawer so that highlight could be enabled + drawer->ClearFlags(CListItemDrawer::ESingleClickDisabledHighlight); + } + } + // Report, that current highlighted element changed + ReportEventL(MCoeControlObserver::EEventStateChanged); + DrawNow(); +} + +void CMIDChoiceGroupListBox::SetHighlight(TBool aVisible) +{ + iHighlight = aVisible; +} + +TBool CMIDChoiceGroupListBox::GetHighlight() +{ + return iHighlight; +} +#endif // RD_JAVA_S60_RELEASE_9_2