javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupControl.cpp
changeset 21 2a9601315dfc
child 23 98ccebc37403
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2003-2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  The CMIDChoiceGroup control container. Owns and manipulates
       
    15 *                the choicegroup model and creates / deletes the actual
       
    16 *                control as needed.
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 #include <e32def.h>
       
    22 #include <e32err.h>
       
    23 #include <w32std.h>
       
    24 #include <gdi.h>
       
    25 #include <gulutil.h>
       
    26 
       
    27 #include <eiktxlbm.h>
       
    28 // CColumnListBoxData API
       
    29 #include <eikclbd.h>
       
    30 
       
    31 #include <aknenv.h>
       
    32 #include <aknconsts.h>
       
    33 #include <avkon.mbg>
       
    34 #include <aknPopup.h>
       
    35 #include <AknLayoutDef.h>
       
    36 #include <AknBidiTextUtils.h>
       
    37 #include <gulcolor.h>
       
    38 
       
    39 #include <skinlayout.cdl.h>
       
    40 #include <AknLayoutFont.h>
       
    41 #include <aknlayoutscalable_avkon.cdl.h> // LAF
       
    42 #include <AknsDrawUtils.h>// skin
       
    43 #include <AknsBasicBackgroundControlContext.h> //skin
       
    44 
       
    45 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    46 #include <akntranseffect.h>
       
    47 #include <akntransitionutils.h>
       
    48 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    49 
       
    50 // using MMIDBitmapImage API in NewElement and SetElement functions - setting icon to element
       
    51 #include <lcdgr.h>
       
    52 // macros definitions for resources
       
    53 #include <lcdui.rsg>
       
    54 #ifndef RD_SCALABLE_UI_V2
       
    55 #include "CMIDForm.h"
       
    56 #endif
       
    57 
       
    58 // API used in HandlePointerEventL function
       
    59 #include "CMIDDisplayable.h"
       
    60 
       
    61 #include "CMIDFont.h"
       
    62 // using CMIDUtils::CopyBitmapL in NewElement and SetElement functions - setting icon to element
       
    63 #include "CMIDUtils.h"
       
    64 #include "CMIDChoiceGroupControl.h"
       
    65 // needed for CMIDChoiceGroupItem API in several places
       
    66 #include "CMIDChoiceGroupItem.h"
       
    67 // using SetTitleL in DoPopupL function - setting popup title
       
    68 #include "CMIDItemLabel.h"
       
    69 // using GetPopupNoteController in ShowInfoPopup function - showing popup with text
       
    70 #include "CMIDPopupNoteController.h"
       
    71 
       
    72 
       
    73 #include <j2me/jdebug.h>
       
    74 
       
    75 // For disabling transition effects
       
    76 #include <aknlistloadertfx.h>
       
    77 #include <aknlistboxtfx.h>
       
    78 
       
    79 
       
    80 /** This macro is executed each time a trapped call returns an error code different than KErrNone */
       
    81 #undef  TRAP_INSTRUMENTATION_LEAVE
       
    82 #define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDChoiceGroupControl.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult);
       
    83 
       
    84 
       
    85 // Constant used for calculation of ChoiceGroup, which is not in Form yet
       
    86 // (from eiklbx.cpp)
       
    87 const TInt KEikListBoxItemVGap = 6;
       
    88 
       
    89 
       
    90 CMIDChoiceGroupPopupList* CMIDChoiceGroupPopupList::NewL(CEikListBox* aListBox, TInt aCbaResource,
       
    91         AknPopupLayouts::TAknPopupLayouts aType)
       
    92 {
       
    93     CMIDChoiceGroupPopupList* self = new(ELeave) CMIDChoiceGroupPopupList;
       
    94     CleanupStack::PushL(self);
       
    95     self->ConstructL(aListBox, aCbaResource, aType);
       
    96     CleanupStack::Pop(self);
       
    97     return self;
       
    98 }
       
    99 
       
   100 CMIDChoiceGroupPopupList::~CMIDChoiceGroupPopupList()
       
   101 {
       
   102 }
       
   103 
       
   104 void CMIDChoiceGroupPopupList::ResizeList()
       
   105 {
       
   106     CAknPopupList::SetupWindowLayout(AknPopupLayouts::EMenuUnknownColumnWindow);
       
   107 }
       
   108 
       
   109 #ifdef RD_SCALABLE_UI_V2
       
   110 void CMIDChoiceGroupPopupList::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   111 {
       
   112     if (aPointerEvent.iType == TPointerEvent::EButton1Down &&
       
   113             !Rect().Contains(aPointerEvent.iPosition))
       
   114     {
       
   115         AttemptExitL(EFalse);
       
   116     }
       
   117     else
       
   118     {
       
   119         CAknPopupList::HandlePointerEventL(aPointerEvent);
       
   120     }
       
   121 }
       
   122 #endif //RD_SCALABLE_UI_V2
       
   123 
       
   124 CMIDChoiceGroupPopupList::CMIDChoiceGroupPopupList()
       
   125 {
       
   126 }
       
   127 
       
   128 CMIDChoiceGroupControl::CMIDChoiceGroupControl(
       
   129     MMIDChoiceGroup::TChoiceType aType,
       
   130     CMIDChoiceGroupItem* aItem)
       
   131         : iType(aType),
       
   132         iItem(aItem)
       
   133 {
       
   134 }
       
   135 
       
   136 
       
   137 CMIDChoiceGroupControl::~CMIDChoiceGroupControl()
       
   138 {
       
   139     // Do not allow the listbox data to delete the icon
       
   140     // array. It will be deleted by the model.
       
   141     DeleteListBox(iListBox);
       
   142 
       
   143     // No need to delete iPopupList here. The popup list is created and deleted in DoPopupL().
       
   144     delete iModel;
       
   145 }
       
   146 
       
   147 
       
   148 // Constructs the model and adds any given elements into it.
       
   149 // NOTE that the actual control is not yet created, it comes
       
   150 // to life when the item is added to a form (that has a window
       
   151 // for the control to draw in). Constructing and storing the model
       
   152 // outside the actual control enables elements to be manipulated
       
   153 // (in Java code) even when the ChoiceGroup is not (yet) added to a form.
       
   154 void CMIDChoiceGroupControl::ConstructL(
       
   155     RArray<TPtrC>& aStringArray,
       
   156     RArray<MMIDImage*>& aImageArray)
       
   157 {
       
   158     // Create the listbox model
       
   159     iModel = new(ELeave) CMIDChoiceGroupModel(iType);
       
   160     iModel->ConstructL(iEikonEnv);
       
   161 
       
   162     // Start observing model events
       
   163     iModel->SetObserver(this);
       
   164 
       
   165     // Stuff any given arrays in the model
       
   166     PopulateModelL(aStringArray, aImageArray);
       
   167 
       
   168     UpdateMargins();
       
   169 
       
   170     SetComponentsToInheritVisibility(ETrue);
       
   171 
       
   172 #ifdef RD_SCALABLE_UI_V2
       
   173     SetAllowStrayPointers();
       
   174 #endif
       
   175 
       
   176 #ifdef RD_TACTILE_FEEDBACK
       
   177     iFeedback = MTouchFeedback::Instance();
       
   178     // Disabling default tactile feedback to prevent a 'double feedback' while tapping on focused item
       
   179     iFeedback->EnableFeedbackForControl(this, FALSE);
       
   180 #endif
       
   181 
       
   182 }
       
   183 
       
   184 
       
   185 // Creates the actual choicegroup control, sets all kinds of
       
   186 // properties and associates the model with the created control
       
   187 void CMIDChoiceGroupControl::CreateControlL(
       
   188     const CCoeControl* aParent,
       
   189     const TRect& aRect)
       
   190 {
       
   191     // Model should be created before the control (this is true for
       
   192     // popup as well)
       
   193     ASSERT(iModel);
       
   194 
       
   195     // In dynamic resolution case store the current item index, so that it can be
       
   196     // restored once the listbox is recreated
       
   197     TInt currentItem = KErrNotFound;
       
   198     if (iListBox)
       
   199     {
       
   200         currentItem = iListBox->View()->CurrentItemIndex();
       
   201     }
       
   202 
       
   203     DeleteControl();
       
   204     ASSERT(!iListBox);
       
   205 
       
   206     // Set parent to the existing (form) window and use the rect given
       
   207     SetContainerWindowL(*aParent);
       
   208     SetRect(aRect);
       
   209 
       
   210     UpdateMargins();
       
   211 
       
   212     // If this is a popup, there's nothing to else create really
       
   213     if (IsPopup())
       
   214     {
       
   215         return;
       
   216     }
       
   217 
       
   218     //in case skin or resolution has changed
       
   219     iModel->ReConstructSelectionIconsL();
       
   220     iModel->UpdateIconArrayL();
       
   221 
       
   222     iListBox = CreateListBoxL(aParent);
       
   223 
       
   224     // Disable transition effects for iListBox, this is needed to get
       
   225     // rid of artifacts caused by transition effects when list box controls
       
   226     // are scrolled up/down.
       
   227     CWindowGc* gc = iListBox->View()->ItemDrawer()->Gc();
       
   228     MAknListBoxTfx* transApi = CAknListLoader::TfxApi(gc);
       
   229     if (transApi)
       
   230     {
       
   231         transApi->EnableEffects(EFalse);
       
   232     }
       
   233 
       
   234     // setup listbox
       
   235     iListBox->SetListBoxObserver(this);
       
   236     iListBox->SetRect(ListBoxRect(Rect()));
       
   237 
       
   238     if (currentItem != KErrNotFound)
       
   239     {
       
   240         iListBox->View()->SetCurrentItemIndex(currentItem);
       
   241     }
       
   242 
       
   243     // Ready to draw
       
   244     ActivateL();
       
   245 }
       
   246 
       
   247 
       
   248 // Deletes the actual listbox control (when item is removed from a form)
       
   249 // and disassociates the model from the control.
       
   250 // Maintains the model so that elements can be accessed even
       
   251 // if the item is not attached to a form
       
   252 void CMIDChoiceGroupControl::DeleteControl()
       
   253 {
       
   254     ClosePopup();
       
   255 
       
   256     // Gets rid of the listbox when choicegroup is removed from
       
   257     // a form, but does not yet kill the model (ie elements that
       
   258     // may have been added)
       
   259     DeleteListBox(iListBox);
       
   260 
       
   261     // Set to null, otherwise destructor will double-delete
       
   262     iListBox = NULL;
       
   263 }
       
   264 
       
   265 
       
   266 void CMIDChoiceGroupControl::HiliteFirstElement(TBool aEnableHighlight)
       
   267 {
       
   268     if (iListBox)
       
   269     {
       
   270         iListBox->View()->SetCurrentItemIndex(0);
       
   271         EnableListHighlight(aEnableHighlight);
       
   272     }
       
   273 }
       
   274 
       
   275 void CMIDChoiceGroupControl::HiliteLastElement(TBool aEnableHighlight)
       
   276 {
       
   277     if (iListBox)
       
   278     {
       
   279         iListBox->View()->SetCurrentItemIndex(iListBox->View()->BottomItemIndex());
       
   280         EnableListHighlight(aEnableHighlight);
       
   281     }
       
   282 }
       
   283 
       
   284 void CMIDChoiceGroupControl::EnableListHighlight(TBool aEnable)
       
   285 {
       
   286     if (iListBox)
       
   287     {
       
   288         CListItemDrawer* drawer = iListBox->View()->ItemDrawer();
       
   289 
       
   290         if (aEnable)
       
   291         {
       
   292             drawer->ClearFlags(CListItemDrawer::EDisableHighlight);
       
   293         }
       
   294         else
       
   295         {
       
   296             drawer->SetFlags(CListItemDrawer::EDisableHighlight);
       
   297 
       
   298 #ifdef RD_SCALABLE_UI_V2
       
   299             // If the focus is dragged to another form item, the highlight is
       
   300             // disabled in this cg. Set the flag to true to be sure that selection is not
       
   301             // changed if the pointer up happens on same cg element where the drag started.
       
   302             iPointerDragHasStarted = ETrue;
       
   303 #endif
       
   304         }
       
   305 
       
   306         TRAP_IGNORE(iListBox->View()->UpdateSelectionL(CListBoxView::ESingleSelection));
       
   307     }
       
   308 }
       
   309 
       
   310 // msk
       
   311 void CMIDChoiceGroupControl::CurrentItemChanged()
       
   312 {
       
   313     if (iItem)
       
   314     {
       
   315         // delegate the information to the item; commands may need to be updated
       
   316         iItem->UpdateCommands();
       
   317     }
       
   318     // redraw
       
   319     DrawNow();
       
   320 }
       
   321 
       
   322 // msk
       
   323 TBool CMIDChoiceGroupControl::IsCurrentItemSelected()
       
   324 {
       
   325     if (iListBox)
       
   326     {
       
   327         return IsSelected(iListBox->View()->CurrentItemIndex());
       
   328     }
       
   329 
       
   330     return EFalse;
       
   331 }
       
   332 
       
   333 // msk
       
   334 // Posts always the java event
       
   335 void CMIDChoiceGroupControl::ToggleCurrentItemSelectionL()
       
   336 {
       
   337     if (iListBox)
       
   338     {
       
   339         // SelectElementL must not be called if the unselection of the selected element is
       
   340         // attempted in exclusive choice group because it would cause the itemStateChanged event.
       
   341         if (iType != MMIDChoiceGroup::EExclusive || !IsCurrentItemSelected())
       
   342         {
       
   343 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   344             if (Form() && !Form()->PhysicsScrolling())
       
   345             {
       
   346 #endif // RD_JAVA_S60_RELEASE_9_2             
       
   347                 TInt currentIndex = iListBox->View()->CurrentItemIndex();
       
   348                 SelectElementL(currentIndex, !IsSelected(currentIndex), ETrue);
       
   349 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   350             }
       
   351 #endif // RD_JAVA_S60_RELEASE_9_2
       
   352         }
       
   353     }
       
   354 }
       
   355 
       
   356 // returns the numbers of elements in this choice group
       
   357 TInt CMIDChoiceGroupControl::NumberOfElements() const
       
   358 {
       
   359     ASSERT(iModel);
       
   360     return iModel->NumberOfItems();
       
   361 }
       
   362 
       
   363 // --- CMIDChoiceGroupItem delegated methods (java Choice interface)
       
   364 
       
   365 
       
   366 // Inserts a new element in the choice
       
   367 void CMIDChoiceGroupControl::InsertElementL(TInt aIndex, const TDesC& aText, MMIDImage* aImage)
       
   368 {
       
   369     ASSERT(iModel);
       
   370 
       
   371     CMIDChoiceGroupElement* pElement = NewElementLC(aText, aImage);
       
   372 
       
   373     // Reserve space for the new element
       
   374     iModel->SetReserveL(iModel->NumberOfItems() + 1);
       
   375 
       
   376     // Stuff it in
       
   377     iModel->InsertElementL(aIndex, pElement);
       
   378 
       
   379     CListBoxView* view = NULL;
       
   380 
       
   381     if (iListBox)
       
   382     {
       
   383         view = iListBox->View();
       
   384     }
       
   385     else if (iPopupList)
       
   386     {
       
   387         view = iPopupList->ListBox()->View();
       
   388     }
       
   389 
       
   390     if (view)
       
   391     {
       
   392         TInt current = view->CurrentItemIndex();
       
   393 
       
   394         if (current >= aIndex && current < (iModel->NumberOfItems() - 1))
       
   395         {
       
   396             // If element was inserted before the highlighted element,
       
   397             // move the highlight so that it stays in the same element
       
   398             // as before insertion.
       
   399             view->SetCurrentItemIndex(++current);
       
   400         }
       
   401     }
       
   402 
       
   403     CleanupStack::Pop(pElement);
       
   404 }
       
   405 
       
   406 
       
   407 // Deletes an element from the choice
       
   408 void CMIDChoiceGroupControl::DeleteElementL(TInt aIndex)
       
   409 {
       
   410     ASSERT(iModel);
       
   411     TInt current = 0;
       
   412     if (iListBox)
       
   413     {
       
   414         current = iListBox->View()->CurrentItemIndex();
       
   415     }
       
   416     iModel->DeleteElementL(aIndex);
       
   417 
       
   418     if (iListBox && current != KErrNotFound &&
       
   419             iModel->NumberOfItems() > 0 &&
       
   420             aIndex <= current)
       
   421     {
       
   422         if (current < iModel->NumberOfItems())
       
   423         {
       
   424             if (current > 0 && aIndex < current)
       
   425             {
       
   426                 // Element was deleted before the current item, decrease
       
   427                 // current so that highlight stays in the same element
       
   428                 // as before the deletion
       
   429                 --current;
       
   430             }
       
   431             iListBox->SetCurrentItemIndex(current);
       
   432         }
       
   433         else
       
   434         {
       
   435             iListBox->SetCurrentItemIndex(iModel->NumberOfItems()-1);
       
   436         }
       
   437     }
       
   438 
       
   439 }
       
   440 
       
   441 
       
   442 // Deletes all elements
       
   443 void CMIDChoiceGroupControl::DeleteAllL()
       
   444 {
       
   445     ASSERT(iModel);
       
   446     if (iListBox)
       
   447     {
       
   448         iListBox->SetCurrentItemIndex(0);
       
   449     }
       
   450     iModel->DeleteAllL();
       
   451 }
       
   452 
       
   453 
       
   454 // Sets properties of element at <aIndex>
       
   455 void CMIDChoiceGroupControl::SetElementL(TInt aIndex, const TDesC& aText, MMIDImage* aImage)
       
   456 {
       
   457     ASSERT(iModel);
       
   458 
       
   459     if (aImage)
       
   460     {
       
   461         MMIDBitmapImage* bitmapImage = aImage->BitmapImage();
       
   462 
       
   463         CFbsBitmap* bitmap = CMIDUtils::CopyBitmapL(bitmapImage->ColorBitmap());
       
   464         CleanupStack::PushL(bitmap);
       
   465 
       
   466         CFbsBitmap* mask = NULL;
       
   467         if (bitmapImage->AlphaBitmap())
       
   468         {
       
   469             TDisplayMode alphaDisplayMode = bitmapImage->AlphaBitmap()->DisplayMode();
       
   470             TBool invert = alphaDisplayMode == EGray2 ? ETrue : EFalse;
       
   471             mask = bitmapImage->CreateAlphaBitmapL(alphaDisplayMode, invert);
       
   472         }
       
   473 
       
   474         CleanupStack::PushL(mask);
       
   475 
       
   476         iModel->SetElementL(aIndex, aText, bitmap, mask);
       
   477 
       
   478         CleanupStack::Pop(mask);
       
   479         CleanupStack::Pop(bitmap);
       
   480 
       
   481         bitmapImage->RemoveRef();
       
   482     }
       
   483     else
       
   484     {
       
   485         iModel->SetElementL(aIndex, aText, NULL, NULL);
       
   486     }
       
   487 }
       
   488 
       
   489 
       
   490 // Sets selection state of element at <aIndex>
       
   491 // This method is also declared in MMIDChoiceGroup. It's implementation
       
   492 // in CMIDChoiceGroupItem just simply calls this method.
       
   493 void CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected)
       
   494 {
       
   495     SelectElementL(aIndex, aSelected, EFalse);
       
   496 }
       
   497 
       
   498 
       
   499 // Returns selection state of element at <aIndex>
       
   500 TBool CMIDChoiceGroupControl::IsSelected(TInt aIndex)
       
   501 {
       
   502     ASSERT(iModel);
       
   503     CMIDChoiceGroupElement* pElement = iModel->ElementAt(aIndex);
       
   504 
       
   505     if (pElement)
       
   506     {
       
   507         return pElement->IsSelected();
       
   508     }
       
   509 
       
   510     return EFalse;
       
   511 }
       
   512 
       
   513 
       
   514 // Sets element text font
       
   515 void CMIDChoiceGroupControl::SetFontL(TInt /*aIndex*/, MMIDFont* /*aFont*/)
       
   516 {
       
   517     ASSERT(iModel);
       
   518 }
       
   519 
       
   520 
       
   521 // Sets element text fit policy
       
   522 void CMIDChoiceGroupControl::SetFitPolicyL(TInt /*aFitPolicy*/)
       
   523 {
       
   524     ASSERT(iModel);
       
   525 }
       
   526 
       
   527 
       
   528 // --- from MMIDChoiceGroupModelObserver ---
       
   529 
       
   530 // Called when the model has changed. Based on the change, will cause
       
   531 // just a redraw of the control, or size recalculation
       
   532 void CMIDChoiceGroupControl::HandleChoiceGroupModelEventL(
       
   533     CMIDChoiceGroupModel* aModel,
       
   534     TChoiceGroupModelEvent aEvent)
       
   535 {
       
   536     ASSERT(iModel);
       
   537 
       
   538     // If not from our model, ignore
       
   539     if (aModel != iModel)
       
   540     {
       
   541         return;
       
   542     }
       
   543 
       
   544     // Assume everything needs to be done (makes the switch shorter)
       
   545     TBool bRedraw = ETrue;
       
   546     TBool bResize = ETrue;
       
   547 
       
   548     // Act upon the event, resize and redraw control as necessary
       
   549     switch (aEvent)
       
   550     {
       
   551     case EElementAdded:
       
   552         if (iListBox)
       
   553         {
       
   554             iListBox->HandleItemAdditionL();
       
   555         }
       
   556         break;
       
   557     case EElementDeleted:
       
   558         if (iListBox)
       
   559         {
       
   560             iListBox->HandleItemRemovalL();
       
   561         }
       
   562         break;
       
   563     case EUpdateEnded:
       
   564         if (iListBox)
       
   565         {
       
   566             iListBox->Reset();
       
   567         }
       
   568         break;
       
   569     case EElementModified:
       
   570         // after the LAF changes the icon column is dynamic, so redo the setup for the listbox
       
   571         // the columns by calling SizeChanged(). bResize is set to false because the relayout of
       
   572         // of the whole form is not needed.
       
   573         SizeChanged();
       
   574         bResize = EFalse;
       
   575         break;
       
   576     case EElementSelected:
       
   577         // Just a redraw will do
       
   578         bResize = EFalse;
       
   579         break;
       
   580     case EUpdateStarted:
       
   581     default:
       
   582         // No redraw, no resize. Do nothing.
       
   583         bRedraw = EFalse;
       
   584         bResize = EFalse;
       
   585         break;
       
   586     }
       
   587 
       
   588     // If popup is opened, it is handled separately
       
   589     if (iPopupList)
       
   590     {
       
   591         UpdatePopupListAppearanceL(aEvent);
       
   592     }
       
   593 
       
   594     // Reporting ESizeChanged event to iItem is not needed since the request
       
   595     // to update the form comes from java side (CMIDForm::RefreshItem(TInt) is called)
       
   596     // when items are added to or removed from choice group. See ChoiceGroup.java.
       
   597     // Redraw if needed and size has not changed, size change will
       
   598     // cause a form layout and redraw anyway.
       
   599     if (bRedraw && !bResize)
       
   600     {
       
   601         // Do safe redraw
       
   602         if (!IsPopup() && iListBox && iListBox->DrawableWindow())
       
   603         {
       
   604             iListBox->DrawDeferred();
       
   605         }
       
   606         else
       
   607         {
       
   608             // Seems to be a popup - redraw myself
       
   609             if (DrawableWindow())
       
   610             {
       
   611                 DrawDeferred();
       
   612             }
       
   613         }
       
   614     }
       
   615 }
       
   616 
       
   617 
       
   618 // --- from MEikListBoxObserver ---
       
   619 // Handles choice listbox events (as in selection)
       
   620 void CMIDChoiceGroupControl::HandleListBoxEventL(CEikListBox* aControl, TListBoxEvent aEventType)
       
   621 {
       
   622     if (aControl != iListBox)
       
   623     {
       
   624         return;
       
   625     }
       
   626 
       
   627     ASSERT(iModel);
       
   628 
       
   629     switch (aEventType)
       
   630     {
       
   631         // These should all cause a selection change
       
   632     case MEikListBoxObserver::EEventEnterKeyPressed:
       
   633     case MEikListBoxObserver::EEventItemActioned:
       
   634         ToggleCurrentItemSelectionL();
       
   635         break;
       
   636 
       
   637     default:
       
   638         break;
       
   639     }
       
   640 }
       
   641 
       
   642 
       
   643 // Offers key events to the listbox, or handles popup events here
       
   644 TKeyResponse CMIDChoiceGroupControl::OfferKeyEventL(
       
   645     const TKeyEvent& aKeyEvent,
       
   646     TEventCode aType)
       
   647 {
       
   648     TKeyResponse resp = EKeyWasNotConsumed;
       
   649 
       
   650     // Pop popup if needed, otherwise do nothing (if popup)
       
   651     if (IsPopup())
       
   652     {
       
   653         if ((aKeyEvent.iCode == EKeyOK) || (aKeyEvent.iCode == EKeyEnter))
       
   654         {
       
   655             // It's a popup, and the OK key was pressed on it - start poppin'
       
   656             DoPopupL();
       
   657             resp = EKeyWasConsumed;
       
   658         }
       
   659 
       
   660         return resp;
       
   661     }
       
   662 
       
   663     // Not a popup then, handle some keys in clever ways
       
   664 
       
   665     // Save the currently selected item (if exclusive choice)
       
   666     TInt oldSelected = iModel->SelectedElement();
       
   667     TInt oldCurrentIndex = -1;
       
   668 
       
   669     if (iListBox)
       
   670     {
       
   671         oldCurrentIndex = iListBox->View()->CurrentItemIndex();
       
   672         // Let the listbox take a shot at the key
       
   673         resp = iListBox->OfferKeyEventL(aKeyEvent, aType);
       
   674     }
       
   675 
       
   676     // If click (enter) on an already selected item in an exclusive choice,
       
   677     // do not consume the key. This allows the form to display a context menu
       
   678     if ((iType == MMIDChoiceGroup::EExclusive) &&
       
   679             ((aKeyEvent.iCode == EKeyOK) || (aKeyEvent.iCode == EKeyEnter)) &&
       
   680             ((oldSelected != -1) || (oldSelected == -1 && oldCurrentIndex == -1)) &&
       
   681             (oldSelected == iModel->SelectedElement()))
       
   682     {
       
   683         // Do not consume the key, so that form can pop a menu
       
   684         CMIDDisplayable& displayable = iItem->Form()->CurrentDisplayable();
       
   685         TInt cntOpt = displayable.NumCommandsForOkOptionsMenu();
       
   686 
       
   687         // set first command from command list,
       
   688         // if command list <= 0 then command sets NULL
       
   689         const CMIDCommand* command = (iItem->CommandList()->Count() > 0 ?
       
   690                                       iItem->CommandList()->At(0).iCommand :
       
   691                                       NULL);
       
   692 
       
   693         // for default command will run ProcessCommandL( KItemCommandIdBase + 1 )
       
   694         if (iItem->DefaultCommand())
       
   695         {
       
   696             displayable.ProcessCommandL(iItem->CommandList()->CommandOffset() +
       
   697                                         iItem->CommandList()->FindCommandIndex(iItem->DefaultCommand()));
       
   698 
       
   699             resp =  EKeyWasConsumed;
       
   700         }
       
   701         else
       
   702         {
       
   703             // if ( cntOpt > 1 ) will run menu, else execute ProcessCommandL( CommandOffset )
       
   704             if (cntOpt > 1)
       
   705             {
       
   706                 displayable.MenuHandler()->ShowMenuL(CMIDMenuHandler::EOkMenu);
       
   707                 resp = EKeyWasConsumed;
       
   708             }
       
   709             else if (command && command->CommandType() != MMIDCommand::EBack &&
       
   710                      command->CommandType() != MMIDCommand::ECancel)
       
   711             {
       
   712                 displayable.ProcessCommandL(iItem->CommandList()->CommandOffset());
       
   713                 resp =  EKeyWasConsumed;
       
   714             }
       
   715             else
       
   716             {
       
   717                 displayable.ProcessCommandL(displayable.MainCommandList()->CommandOffset());
       
   718                 resp =  EKeyWasConsumed;
       
   719             }
       
   720         }
       
   721     }
       
   722     // If the event caused current item change, and the new current item
       
   723     // is outside the visible area, should request the form to scroll a bit.
       
   724     // Current item has not changed, if the key was not consumed
       
   725     if (((aKeyEvent.iCode == EKeyUpArrow) ||
       
   726             (aKeyEvent.iCode == EKeyDownArrow)) &&
       
   727             (resp != EKeyWasNotConsumed))
       
   728     {
       
   729         // Calc scroll need and request one, if necessary
       
   730         RequestScrollIfNeededL();
       
   731     }
       
   732 
       
   733     if (iListBox && (oldCurrentIndex != iListBox->View()->CurrentItemIndex()))
       
   734     {
       
   735         CurrentItemChanged();
       
   736 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   737         ShowInfoPopup();
       
   738 #endif // RD_JAVA_S60_RELEASE_9_2        
       
   739     }
       
   740     return resp;
       
   741 }
       
   742 
       
   743 #ifdef RD_SCALABLE_UI_V2
       
   744 void CMIDChoiceGroupControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   745 {
       
   746     if (!AknLayoutUtils::PenEnabled() || !iListBox)
       
   747     {
       
   748 
       
   749 #ifdef RD_TACTILE_FEEDBACK
       
   750         // this is to give tactile feedback when a POPUP type CG is focused
       
   751         // and user taps it to open the popup list
       
   752         // if focus is changing, tactile feedback is given already in Form
       
   753         if (IsPopup() &&
       
   754                 aPointerEvent.iType == TPointerEvent::EButton1Down &&
       
   755                 !iItem->Form()->IsFocusChangingWithPen())
       
   756         {
       
   757 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   758             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   759 #else
       
   760             iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
   761 #endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   762         }
       
   763 #endif // RD_TACTILE_FEEDBACK
       
   764 
       
   765         return;
       
   766     }
       
   767 
       
   768     TInt nOldCurrent = iListBox->View()->CurrentItemIndex();
       
   769     TBool oldSelected = IsSelected(nOldCurrent);
       
   770 
       
   771     switch (aPointerEvent.iType)
       
   772     {
       
   773     case TPointerEvent::EDrag:
       
   774         // In order to enable highlight moving inside the choice group when the focus is dragged
       
   775         // on the form, forward drag events directly to listbox. This is needed beacuse it is not
       
   776         // always possible to set the wanted grabbing state for CMIDChoiceGroupListBox.
       
   777         // See also CCoeControl implementation of pointer event handling.
       
   778         iListBox->HandlePointerEventL(aPointerEvent);
       
   779         break;
       
   780     case TPointerEvent::EButtonRepeat:
       
   781         // EButtonRepeat events are requested by form. These events come only when pointer
       
   782         // is dragged out of main pane area.
       
   783         TimedScroll(aPointerEvent.iPosition.iY < 0 ? CMIDForm::EUp : CMIDForm::EDown);
       
   784         break;
       
   785     case TPointerEvent::EButton1Down:
       
   786     {
       
   787 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   788         // Hide pop-up note if visible.
       
   789         CMIDForm* form = iItem->Form();
       
   790         if (form)
       
   791         {
       
   792             form->GetPopupNoteController()->HidePopup();
       
   793         }
       
   794 #endif // RD_JAVA_S60_RELEASE_9_2
       
   795 
       
   796         iPointerDragHasStarted = EFalse;
       
   797 
       
   798 #ifdef RD_TACTILE_FEEDBACK
       
   799         // give tactile feedback here on ListBox only if it is already focused
       
   800         // if focus is changing, tactile feedback is given already in Form
       
   801         if (!iItem->Form()->IsFocusChangingWithPen())
       
   802         {
       
   803 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   804             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   805 #else
       
   806             iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
   807 #endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   808         }
       
   809 #endif // RD_TACTILE_FEEDBACK
       
   810         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   811 
       
   812         if (iListBox->Rect().Contains(aPointerEvent.iPosition) &&
       
   813                 !iItem->Form()->IsScrolledOnPointerDown())
       
   814         {
       
   815             TRect mainPane;
       
   816             AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPane);
       
   817 
       
   818             TRect rect = iListBox->HighlightRect(); // highlight rect is in propotion to screen,
       
   819             rect.Move(0, -mainPane.iTl.iY);         // move it so that it's in propotion to main pane
       
   820 
       
   821             // Scroll the form so that highlighted list element becomes fully visible
       
   822             TInt scroll = 0;
       
   823             if (rect.iBr.iY > mainPane.Height())
       
   824             {
       
   825                 scroll = mainPane.Height() - rect.iBr.iY;
       
   826             }
       
   827             else if (rect.iTl.iY < 0)
       
   828             {
       
   829                 scroll = -rect.iTl.iY;
       
   830             }
       
   831 
       
   832             if (scroll != 0)
       
   833             {
       
   834                 ReportEventL(MMIDChoiceGroupControlObserver::EScrollRequest,
       
   835                              (TAny*)scroll);
       
   836             }
       
   837         }
       
   838         break;
       
   839     }
       
   840     case TPointerEvent::EButton1Up:
       
   841     {
       
   842 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   843         // If up event comes when long tap has been detected, then
       
   844         // just forward the pointer event. In that case we do not
       
   845         // want to change selection, but update the listbox visually.
       
   846         // This is performed when pop-up menu is closed and we want to
       
   847         // hide listbox highlight.
       
   848         if (iItem->LongTapDetected())
       
   849         {
       
   850             CCoeControl::HandlePointerEventL(aPointerEvent);
       
   851             return;
       
   852         }
       
   853 #endif // RD_JAVA_S60_RELEASE_9_2
       
   854 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   855         switch (iType)
       
   856         {
       
   857         case MMIDChoiceGroup::EMultiple:
       
   858             iFeedback->InstantFeedback(ETouchFeedbackCheckbox);
       
   859             break;
       
   860         default:
       
   861             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   862             break;
       
   863         }
       
   864 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   865 
       
   866         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   867 
       
   868         TInt idx;
       
   869 
       
   870         // Allow toggling the selection also in a case when form has been scrolled on pointer down event,
       
   871         // if the pointer up happens still on cg item area.
       
   872         TBool toggleAfterScroll = iItem->Form()->IsScrolledOnPointerDown() &&
       
   873                                   iItem->Rect().Contains(aPointerEvent.iPosition);
       
   874 
       
   875         if (!iPointerDragHasStarted &&
       
   876                 (iListBox->View()->XYPosToItemIndex(aPointerEvent.iPosition, idx) ||
       
   877                  toggleAfterScroll))
       
   878         {
       
   879             ToggleCurrentItemSelectionL();
       
   880         }
       
   881 
       
   882         // If selected item is tapped in the Exclusive ChoiceGroup
       
   883         // then possible default Command is executed.
       
   884         if (iItem->DefaultCommand() && !iItem->Form()->PhysicsScrolling())
       
   885         {
       
   886             if (iType == MMIDChoiceGroup::EExclusive && oldSelected
       
   887                     && !iFocusChangingWithPen && !iItem->Form()->IsFocusChangingWithPen())
       
   888             {
       
   889                 iItem->Form()->CurrentDisplayable().ProcessCommandL(iItem->DefaultCommand());
       
   890             }
       
   891         }
       
   892 
       
   893         iFocusChangingWithPen = EFalse;
       
   894         break;
       
   895     }
       
   896     default:
       
   897         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   898         break;
       
   899     }
       
   900 
       
   901     // msk: notify if the current index has changed
       
   902     if (nOldCurrent != iListBox->View()->CurrentItemIndex())
       
   903     {
       
   904         iFocusChangingWithPen = ETrue;
       
   905         CurrentItemChanged();
       
   906         if (aPointerEvent.iType == TPointerEvent::EDrag)
       
   907         {
       
   908             iPointerDragHasStarted = ETrue;
       
   909         }
       
   910     }
       
   911 }
       
   912 
       
   913 #endif //RD_SCALABLE_UI_V2
       
   914 
       
   915 // Count component controls in this compound control
       
   916 TInt CMIDChoiceGroupControl::CountComponentControls() const
       
   917 {
       
   918     if (iListBox)
       
   919         return 1;
       
   920 
       
   921     return 0;
       
   922 }
       
   923 
       
   924 
       
   925 // Return requested component control
       
   926 CCoeControl* CMIDChoiceGroupControl::ComponentControl(TInt /*aIndex*/) const
       
   927 {
       
   928     return iListBox;
       
   929 }
       
   930 
       
   931 
       
   932 /** Called when the size adjustment need is detected, the item notified and
       
   933     the item caused the form to relayout. The form will calc the new
       
   934     position of the item and cause sizechanged to be called - this is
       
   935     this controls chance to update its position.
       
   936 
       
   937 */
       
   938 void CMIDChoiceGroupControl::SizeChanged()
       
   939 {
       
   940     if (iListBox)
       
   941     {
       
   942         iListBox->SetRect(ListBoxRect(Rect()));
       
   943         TRAP_IGNORE(SetupColumnsL(iListBox->ItemDrawer()->ColumnData()));
       
   944     }
       
   945 
       
   946     if (IsPopup())
       
   947     {
       
   948         TAknLayoutRect layoutRect; // used only temporarily for getting the layout for popup item's icons and text
       
   949 
       
   950         // Rect() includes also the margins so it cannot be used directly when layouting the popup icons and text.
       
   951         // popupRect is the rect that is available for the closed popup item (i.e. it does not include the margins).
       
   952         // popupRect is used as a parent rect when updating the rects of the popup icons and text.
       
   953         layoutRect.LayoutRect(Rect(),
       
   954                               AknLayoutScalable_Avkon::form2_midp_field_choice_group_pane().LayoutLine());
       
   955         TRect popupRect = layoutRect.Rect();
       
   956 
       
   957         // Layout for the element icon
       
   958         layoutRect.LayoutRect(popupRect,
       
   959                               AknLayoutScalable_Avkon::list_single_midp_graphic_pane_g4_cp(1).LayoutLine());
       
   960         iPopupIconRect = layoutRect.Rect();
       
   961 
       
   962         // Layout for the text
       
   963 
       
   964         iPopupTextLayout.LayoutText(popupRect,
       
   965                                     AknLayoutScalable_Avkon::list_single_midp_graphic_pane_t1_cp(1).LayoutLine());
       
   966     }
       
   967 }
       
   968 
       
   969 void CMIDChoiceGroupControl::PositionChanged()
       
   970 {
       
   971     if (IsPopup())
       
   972     {
       
   973         SizeChanged();
       
   974     }
       
   975 }
       
   976 
       
   977 // Calculates and returns the minimum size required by the control
       
   978 // The size is based on the number of items in the listbox, so that
       
   979 // the listbox does not need to be scrolled. In popup mode the height
       
   980 // is fixed.
       
   981 TSize CMIDChoiceGroupControl::MinimumSize() const
       
   982 {
       
   983     // Start with the current size
       
   984     TSize size = Size();
       
   985 
       
   986     TInt height = 0;
       
   987 
       
   988     // Get height of list box, if not popup, and there is one
       
   989     if (!IsPopup())
       
   990     {
       
   991         // Get current number of list box items.
       
   992         TInt numberOfItems = iModel->NumberOfItems();
       
   993 
       
   994         if (iListBox)
       
   995         {
       
   996             // Use item count to calculate listbox height
       
   997             height += iListBox->CalcHeightBasedOnNumOfItems(numberOfItems);
       
   998         }
       
   999         else
       
  1000         {
       
  1001             // If there is no iListBox, this cg is not added to form yet.
       
  1002             // In this case calculate the best estimate for the list box height
       
  1003             // here.
       
  1004             // Because none of layout seems to be suitable for this
       
  1005             // calculation, we have to do it in the same way as CEikLisBox
       
  1006             // (see CEikListBox::CalcHeightBasedOnNumOfItems in eiklbx.cpp).
       
  1007             height += (iEikonEnv->NormalFont()->HeightInPixels()
       
  1008                        + KEikListBoxItemVGap) * numberOfItems;
       
  1009         }
       
  1010 
       
  1011         height += (numberOfItems > 0)
       
  1012                   ? (iContentMargins.iTop + iContentMargins.iBottom)
       
  1013                   : iContentMargins.iBottom;
       
  1014     }
       
  1015     else // It is a popup
       
  1016     {
       
  1017         TAknLayoutRect layoutRect;
       
  1018         // layout in respect of the screen as only the height is needed
       
  1019         layoutRect.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(),
       
  1020                               AknLayoutScalable_Avkon::
       
  1021                               list_single_midp_graphic_pane_cp(1, 0).LayoutLine());
       
  1022         height += layoutRect.Rect().Height()
       
  1023                   + iContentMargins.iTop + iContentMargins.iBottom;
       
  1024     }
       
  1025 
       
  1026     // Adjust the size (height only) accordingly
       
  1027     size.iHeight = height;
       
  1028 
       
  1029     return size;
       
  1030 }
       
  1031 
       
  1032 void CMIDChoiceGroupControl::Draw(const TRect& /*aRect*/) const
       
  1033 {
       
  1034     if (IsPopup())
       
  1035     {
       
  1036         CMIDChoiceGroupElement* pElement = iModel->ElementAt(iModel->SelectedElement());
       
  1037 
       
  1038         if (pElement)
       
  1039         {
       
  1040             DrawIcon(pElement->Icon());
       
  1041             DrawText(pElement->Text());
       
  1042         }
       
  1043     }
       
  1044 }
       
  1045 
       
  1046 // Responds to focus change.
       
  1047 // From CCoeControl.
       
  1048 void CMIDChoiceGroupControl::FocusChanged(TDrawNow aDrawNow)
       
  1049 {
       
  1050     // call default CCoeControl's implementation
       
  1051     CCoeControl::FocusChanged(aDrawNow);
       
  1052 
       
  1053     // update focus state of listbox regarding to current focus state
       
  1054     if (iListBox)
       
  1055     {
       
  1056         iListBox->SetFocus(IsFocused(), aDrawNow);
       
  1057     }
       
  1058 }
       
  1059 
       
  1060 // Handles resource change.
       
  1061 // From CCoeControl.
       
  1062 void CMIDChoiceGroupControl::HandleResourceChange(TInt aType)
       
  1063 {
       
  1064     // call default CCoeControl's implementation
       
  1065     CCoeControl::HandleResourceChange(aType);
       
  1066 
       
  1067     // update listbox focus state when layout is switched
       
  1068     if (aType == KEikDynamicLayoutVariantSwitch && iListBox)
       
  1069     {
       
  1070         iListBox->SetFocus(IsFocused());
       
  1071     }
       
  1072 }
       
  1073 
       
  1074 TTypeUid::Ptr CMIDChoiceGroupControl::MopSupplyObject(TTypeUid aId)
       
  1075 {
       
  1076     return iItem->MopSupplyObject(aId);
       
  1077 }
       
  1078 
       
  1079 // Closes the popup if it is open
       
  1080 void CMIDChoiceGroupControl::ClosePopup()
       
  1081 {
       
  1082     if (iPopupList)
       
  1083     {
       
  1084         iPopupList->CancelPopup();
       
  1085     }
       
  1086 }
       
  1087 
       
  1088 // --- private functions ---
       
  1089 
       
  1090 // Draws an icon in the popup control using LAF as much as possible
       
  1091 void CMIDChoiceGroupControl::DrawIcon(CGulIcon* aIcon) const
       
  1092 {
       
  1093     // Sanity check
       
  1094     if (!aIcon)
       
  1095     {
       
  1096         return;
       
  1097     }
       
  1098 
       
  1099     // Extract parts - they're needed later anyway
       
  1100     CFbsBitmap* bmp = aIcon->Bitmap();
       
  1101     CFbsBitmap* mask = aIcon->Mask();
       
  1102 
       
  1103     CWindowGc& gc = SystemGc();
       
  1104     TRect iconRect = iPopupIconRect;
       
  1105 
       
  1106     // Draw the icon centered in its rect
       
  1107 
       
  1108     // Position in icon is (0,0), if the image fits. Else there's a
       
  1109     // need for a bit of recalc
       
  1110     TPoint posInIcon = TPoint(0, 0) + (bmp->SizeInPixels() - iconRect.Size());
       
  1111     posInIcon.iX /= 2;
       
  1112     posInIcon.iY /= 2;
       
  1113 
       
  1114     // If the thing is negative, the icon fits. Need to move the drawing
       
  1115     // rect a bit to make the icon draw in the middle
       
  1116     if (posInIcon.iX < 0)
       
  1117     {
       
  1118         // Shift right by amount left over
       
  1119         iconRect.iTl.iX -= posInIcon.iX;
       
  1120         posInIcon.iX = 0;
       
  1121     }
       
  1122 
       
  1123     if (posInIcon.iY < 0)
       
  1124     {
       
  1125         // Shift down by amount left over
       
  1126         iconRect.iTl.iY -= posInIcon.iY;
       
  1127         posInIcon.iY = 0;
       
  1128     }
       
  1129 
       
  1130     // Set the part of icon that is to be drawn
       
  1131     TRect drawRect(posInIcon, iconRect.Size());
       
  1132 
       
  1133     // Draw it
       
  1134     if (mask)
       
  1135     {
       
  1136         gc.BitBltMasked(iconRect.iTl, bmp, drawRect, mask, ETrue);
       
  1137     }
       
  1138     else
       
  1139     {
       
  1140         gc.BitBlt(iconRect.iTl, bmp, drawRect);
       
  1141     }
       
  1142 }
       
  1143 
       
  1144 
       
  1145 /** Draws the selected item text in the popup control */
       
  1146 void CMIDChoiceGroupControl::DrawText(const TDesC& aText) const
       
  1147 {
       
  1148     if (aText.Length())
       
  1149     {
       
  1150         TRgb rgb = AKN_LAF_COLOR(215);
       
  1151         AknsUtils::GetCachedColor(AknsUtils::SkinInstance(),
       
  1152                                   rgb,KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG8);
       
  1153         iPopupTextLayout.DrawText(SystemGc(), aText, ETrue, rgb);
       
  1154     }
       
  1155 }
       
  1156 
       
  1157 
       
  1158 // Populates the listbox model from given arrays
       
  1159 void CMIDChoiceGroupControl::PopulateModelL(
       
  1160     RArray<TPtrC>& aStringArray,
       
  1161     RArray<MMIDImage*>& aImageArray)
       
  1162 {
       
  1163     if (!iModel)
       
  1164     {
       
  1165         // Should not happen.
       
  1166         ASSERT(EFalse);
       
  1167         return;
       
  1168     }
       
  1169 
       
  1170     // Begin model update. The model defers updating
       
  1171     // some of its internal stuff until EndUpdate()
       
  1172     iModel->BeginUpdate();
       
  1173 
       
  1174     // Loop through the string & image arrays and add elements,
       
  1175     // pass model from here so that it doesn't need to be retrieved
       
  1176     // from the box all the time
       
  1177     TInt nCount = aStringArray.Count();
       
  1178     for (TInt i = 0; i < nCount; i++)
       
  1179     {
       
  1180         iModel->AppendElementL(NewElementLC(aStringArray[i], aImageArray[i]));
       
  1181         CleanupStack::Pop();  // NewElementLC
       
  1182     }
       
  1183 
       
  1184     // End model update
       
  1185     iModel->EndUpdate();
       
  1186 }
       
  1187 
       
  1188 // Create a new element, initialise with string & image
       
  1189 CMIDChoiceGroupElement* CMIDChoiceGroupControl::NewElementLC(
       
  1190     const TDesC& aString, MMIDImage* aImage)
       
  1191 {
       
  1192     CMIDChoiceGroupElement* pElement = CMIDChoiceGroupElement::NewL();
       
  1193     CleanupStack::PushL(pElement);
       
  1194 
       
  1195     pElement->SetTextL(aString);
       
  1196 
       
  1197     if (aImage)
       
  1198     {
       
  1199         MMIDBitmapImage* bitmapImage = aImage->BitmapImage();
       
  1200 
       
  1201         CFbsBitmap* bitmap = CMIDUtils::CopyBitmapL(bitmapImage->ColorBitmap());
       
  1202         CleanupStack::PushL(bitmap);
       
  1203 
       
  1204         CFbsBitmap* mask = NULL;
       
  1205         if (bitmapImage->AlphaBitmap())
       
  1206         {
       
  1207             TDisplayMode alphaDisplayMode = bitmapImage->AlphaBitmap()->DisplayMode();
       
  1208             TBool invert = alphaDisplayMode == EGray2 ? ETrue : EFalse;
       
  1209             mask = bitmapImage->CreateAlphaBitmapL(alphaDisplayMode, invert);
       
  1210         }
       
  1211 
       
  1212         CleanupStack::PushL(mask);
       
  1213 
       
  1214         pElement->SetIconL(*bitmap, mask);
       
  1215         CleanupStack::Pop(mask);
       
  1216         CleanupStack::Pop(bitmap);
       
  1217 
       
  1218         bitmapImage->RemoveRef();
       
  1219     }
       
  1220 
       
  1221     return pElement;
       
  1222 }
       
  1223 
       
  1224 
       
  1225 // Reports control events to observer
       
  1226 void CMIDChoiceGroupControl::ReportEventL(
       
  1227     MMIDChoiceGroupControlObserver::TChoiceGroupControlEvent aEvent,
       
  1228     TAny* aParam /* == NULL */)
       
  1229 {
       
  1230     if (iObserver)
       
  1231     {
       
  1232         iObserver->HandleChoiceGroupControlEventL(this, aEvent, aParam);
       
  1233     }
       
  1234 }
       
  1235 
       
  1236 
       
  1237 // Calculates whether scrolling the current lbox item into view
       
  1238 // is in order, and requests a scroll from the form (informs item
       
  1239 // of a svcroll request event) if necessary
       
  1240 void CMIDChoiceGroupControl::RequestScrollIfNeededL()
       
  1241 {
       
  1242     // Scroll should never be needed in a popup CG, and definitely
       
  1243     // not, if there is no listbox
       
  1244     if ((IsPopup()) || (!iListBox))
       
  1245     {
       
  1246         return;
       
  1247     }
       
  1248 
       
  1249     // Start with the form rect
       
  1250     TRect formRect = iItem->FormRect();
       
  1251 
       
  1252     if (formRect.IsEmpty())
       
  1253     {
       
  1254         return;
       
  1255     }
       
  1256 
       
  1257     // Calculate current listbox item rect
       
  1258     TInt currentItem = iListBox->CurrentItemIndex();
       
  1259     TRect lbitemRect = TRect(
       
  1260                            iListBox->View()->ItemPos(currentItem),
       
  1261                            iListBox->View()->ItemSize(currentItem));
       
  1262 
       
  1263     // CG item rect is also needed
       
  1264     TRect cgitemRect = iItem->Rect();
       
  1265 
       
  1266     // Amount to be scrolled
       
  1267     TInt nScroll = 0;
       
  1268 
       
  1269     // If the current item is even partly outside the form, should
       
  1270     // scroll. Scroll amount is either the selected item border to
       
  1271     // middle of form rect, or the rest of the CG visible, whichever is
       
  1272     // smaller.
       
  1273     if (lbitemRect.iBr.iY > formRect.iBr.iY)
       
  1274     {
       
  1275         // Items bottom is below the form bottom - need to scroll up (-)
       
  1276         nScroll = Min((lbitemRect.iTl.iY - (formRect.Height() / 2)),
       
  1277                       ((cgitemRect.iBr.iY - formRect.iBr.iY) + 1));
       
  1278         // Scroll up is negative
       
  1279         nScroll = -nScroll;
       
  1280     }
       
  1281     else if (lbitemRect.iTl.iY < formRect.iTl.iY)
       
  1282     {
       
  1283         // Items top is above the form top - need to scroll down (+)
       
  1284         nScroll = Min((((formRect.Height() / 2) - lbitemRect.iBr.iY) + 1),
       
  1285                       (formRect.iTl.iY - cgitemRect.iTl.iY));
       
  1286     }
       
  1287     else
       
  1288     {
       
  1289         // There should be no need to scroll
       
  1290         return;
       
  1291     }
       
  1292 
       
  1293     // Report a scrolling request
       
  1294     ReportEventL(
       
  1295         MMIDChoiceGroupControlObserver::EScrollRequest,
       
  1296         (TAny*) nScroll);
       
  1297 }
       
  1298 
       
  1299 
       
  1300 void CMIDChoiceGroupControl::RestoreFocus()
       
  1301 {
       
  1302     // The sub-item focus restore is done by scrolling the form
       
  1303     // Exceptions can be ignored, because failing of RequestScrollIfNeededL
       
  1304     // may cause only a cosmetic visual problems
       
  1305     TRAP_IGNORE(RequestScrollIfNeededL());
       
  1306 }
       
  1307 
       
  1308 
       
  1309 // Pops up the popup choice (creates a listbox, gives it to the
       
  1310 // popup for content, gives the popup in turn as parent to the
       
  1311 // listbox construction, sets title, creates scrollbars and
       
  1312 // pop goes the weasel
       
  1313 void CMIDChoiceGroupControl::DoPopupL()
       
  1314 {
       
  1315     //in case skin or resolution has changed
       
  1316     iModel->ReConstructSelectionIconsL();
       
  1317     iModel->UpdateIconArrayL();
       
  1318 
       
  1319     // In order for the listbox to have popup as parent, it
       
  1320     // needs to be allocated and constructed separately
       
  1321     CMIDChoiceGroupListBox* pListBox = AllocateListBoxL();
       
  1322     CleanupStack::PushL(pListBox);
       
  1323 
       
  1324 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1325     // Create the popup with the listbox as popup content
       
  1326     CMIDChoiceGroupPopupList* pPop = CMIDChoiceGroupPopupList::NewL(
       
  1327                                          pListBox,
       
  1328                                          R_MIDP_SOFTKEYS_CANCEL,
       
  1329                                          AknPopupLayouts::EMenuUnknownColumnWindow);
       
  1330 #else
       
  1331 
       
  1332     // Create the popup with the listbox as popup content
       
  1333     CMIDChoiceGroupPopupList* pPop = CMIDChoiceGroupPopupList::NewL(
       
  1334                                          pListBox,
       
  1335                                          R_MIDP_SOFTKEYS_OK_BACK,
       
  1336                                          AknPopupLayouts::EMenuUnknownColumnWindow);
       
  1337 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1338     CleanupStack::PushL(pPop);
       
  1339 
       
  1340     // Now actually construct the listbox with the popup as parent
       
  1341     ConstructListBoxL(pListBox, pPop);
       
  1342 
       
  1343     // We need some internal vertical scroll stuff in popup - set it up
       
  1344     pListBox->CreateScrollBarFrameL(ETrue);
       
  1345     pListBox->ScrollBarFrame()->SetScrollBarVisibilityL(
       
  1346         CEikScrollBarFrame::EOff,
       
  1347         CEikScrollBarFrame::EAuto);
       
  1348     // Drawing of scrollbar background is disabled - avoid improper
       
  1349     // drawing in landscape mode and appearance is consistent
       
  1350     // with native side
       
  1351     pListBox->ScrollBarFrame()->DrawBackground(EFalse, EFalse);
       
  1352 
       
  1353     // Set the popup title to be the same as the choicegroup label
       
  1354     pPop->SetTitleL(*(iItem->LabelControl()->Text()));
       
  1355 
       
  1356 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1357     // Show highlight in pop-up ChoiceGroup.
       
  1358     pListBox->DisableSingleClick(ETrue);
       
  1359 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1360 
       
  1361     // set the current item to the one we currently have selected
       
  1362     if (iModel->SelectedElement() >= 0)
       
  1363     {
       
  1364         pListBox->SetCurrentItemIndex(iModel->SelectedElement());
       
  1365     }
       
  1366 
       
  1367     iPopupList = pPop;
       
  1368 
       
  1369 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1370     //When popup list is opening, do the feedback
       
  1371     if (CAknTransitionUtils::TransitionsEnabled(
       
  1372                 AknTransEffect::EComponentTransitionsOff))
       
  1373     {
       
  1374         iFeedback->InstantFeedback(ETouchFeedbackIncreasingPopUp);
       
  1375     }
       
  1376     else
       
  1377     {
       
  1378         iFeedback->InstantFeedback(ETouchFeedbackPopUp);
       
  1379     }
       
  1380 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1381 
       
  1382     TInt popOK = pPop->ExecuteLD();
       
  1383     iPopupList = NULL;
       
  1384 
       
  1385     CleanupStack::Pop(pPop);
       
  1386 
       
  1387     // Examine result
       
  1388     if (popOK)
       
  1389     {
       
  1390         // Retrieve the selection, and set in model
       
  1391         TInt nSelected = pListBox->CurrentItemIndex();
       
  1392         if (nSelected != iModel->SelectedElement())
       
  1393         {
       
  1394             SelectElementL(nSelected, ETrue, ETrue);
       
  1395         }
       
  1396     }
       
  1397 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1398     else
       
  1399     {
       
  1400         //Popup list was closed without any selection:
       
  1401         //-user canceled it
       
  1402         //-user tapped outside of choice list dialog
       
  1403         //Do the closing feedback for these two cases
       
  1404         if (CAknTransitionUtils::TransitionsEnabled(
       
  1405                     AknTransEffect::EComponentTransitionsOff))
       
  1406         {
       
  1407             iFeedback->InstantFeedback(ETouchFeedbackDecreasingPopUp);
       
  1408         }
       
  1409         else
       
  1410         {
       
  1411             iFeedback->InstantFeedback(ETouchFeedbackPopUp);
       
  1412         }
       
  1413     }
       
  1414 #endif //RD_RD_ADVANCED_TACTILE_FEEDBACK
       
  1415 
       
  1416     // The icon column may need to be added or removed,
       
  1417     // SizeChanged does the relayout
       
  1418     SizeChanged();
       
  1419 
       
  1420     // Cleanup
       
  1421     CleanupStack::Pop(pListBox);
       
  1422     DeleteListBox(pListBox);
       
  1423 
       
  1424     iItem->DrawDeferred();
       
  1425 }
       
  1426 
       
  1427 
       
  1428 // Creates the choice listbox
       
  1429 CMIDChoiceGroupListBox* CMIDChoiceGroupControl::CreateListBoxL(
       
  1430     const CCoeControl* aParent)
       
  1431 {
       
  1432     // Allocate
       
  1433     CMIDChoiceGroupListBox* pListBox = AllocateListBoxL();
       
  1434     CleanupStack::PushL(pListBox);
       
  1435 
       
  1436     // Construct
       
  1437     ConstructListBoxL(pListBox, aParent);
       
  1438     CleanupStack::Pop(pListBox);
       
  1439 
       
  1440     return pListBox;
       
  1441 }
       
  1442 
       
  1443 
       
  1444 // Allocates the choice listbox.
       
  1445 CMIDChoiceGroupListBox* CMIDChoiceGroupControl::AllocateListBoxL()
       
  1446 {
       
  1447     return (new(ELeave) CMIDChoiceGroupListBox(this));
       
  1448 }
       
  1449 
       
  1450 
       
  1451 // Constructs the choice listbox with proper flags and parent
       
  1452 void CMIDChoiceGroupControl::ConstructListBoxL(
       
  1453     CMIDChoiceGroupListBox* aListBox,
       
  1454     const CCoeControl* aParent)
       
  1455 {
       
  1456     TInt flags(CEikListBox::ELeftDownInViewRect |
       
  1457                CEikListBox::EPaintedSelection |
       
  1458                CEikListBox::EKeepModel);
       
  1459 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1460     flags |= CEikListBox::ENoExtendedSelection;
       
  1461 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1462 
       
  1463     // Construct with the model passed in (do not allow the listbox
       
  1464     // to create its own model)
       
  1465     aListBox->ConstructL(aParent, flags, iModel);
       
  1466 
       
  1467     // Grab the column data
       
  1468     CColumnListBoxData* columnData = aListBox->ItemDrawer()->ColumnData();
       
  1469 
       
  1470     // Set up columns
       
  1471     SetupColumnsL(columnData);
       
  1472 
       
  1473     // Set icon array
       
  1474     // NOTE that the listbox (columndata) does not own the
       
  1475     // icon array. Some things are needed in deletion to make
       
  1476     // sure that the array is not deleted with the listbox
       
  1477     columnData->SetIconArray(iModel->IconArray());
       
  1478 }
       
  1479 
       
  1480 
       
  1481 // Deletes the choice listbox (taking care not to destroy the icon array)
       
  1482 void CMIDChoiceGroupControl::DeleteListBox(CMIDChoiceGroupListBox* aListBox)
       
  1483 {
       
  1484     // NOTE that the iconarray in the listbox data needs to be
       
  1485     // set to NULL, otherwise the array contents will be deleted, which
       
  1486     // is not good, since it is actually the model that owns the icons
       
  1487     if (aListBox)
       
  1488     {
       
  1489         CColumnListBoxData* columnData = aListBox->ItemDrawer()->ColumnData();
       
  1490         columnData->SetIconArray(NULL);
       
  1491 
       
  1492         delete aListBox;
       
  1493     }
       
  1494 }
       
  1495 
       
  1496 /**
       
  1497 * Functions sets and layouts column data (part of list box used for choicegroup):
       
  1498 * Column 0 (ERadioButtonOrCheckBoxColumn) is used for radiobuton/checkbox icons
       
  1499 * Column 1 (EUserDefinedImagesColumn) is used for user defined images
       
  1500 * Column 2 (ETextColumn) is used for text
       
  1501 * Each colum has specific layout.
       
  1502 *
       
  1503 * @param aColumnData pointer to CColumnListBoxData
       
  1504 */
       
  1505 void CMIDChoiceGroupControl::SetupColumnsL(CColumnListBoxData* aColumnData)
       
  1506 {
       
  1507     ASSERT(aColumnData);
       
  1508 
       
  1509     if (iModel->HasIcons())
       
  1510     { //ChoiceGroup has user defined images
       
  1511         TAknTextLineLayout textlayout;
       
  1512         TAknWindowLineLayout graphiclayout;
       
  1513 
       
  1514         if (iType != MMIDChoiceGroup::EPopup)
       
  1515         { //ChoiceGroup
       
  1516             //Normal ChoiceGroup must have radiobuton/checkbox icons
       
  1517             //if MULTIPLE or EXCLUSIVE type is set.
       
  1518             //We set and layout 0. column for those icons.
       
  1519             aColumnData->SetGraphicSubCellL(ERadioButtonOrCheckBoxColumn,
       
  1520                                             AknLayoutScalable_Avkon::
       
  1521                                             list_single_2graphic_pane_g2_cp4().LayoutLine());
       
  1522             //layout for text
       
  1523             textlayout = AknLayoutScalable_Avkon::
       
  1524                          list_single_2graphic_pane_t1_cp4().LayoutLine();
       
  1525             //layout for user defined image
       
  1526             graphiclayout = AknLayoutScalable_Avkon::
       
  1527                             list_single_2graphic_pane_g1_cp4().LayoutLine();
       
  1528         }
       
  1529         else
       
  1530         { //Popup ChoiceGroup - must not have radiobuton/checkbox icons,
       
  1531             // so that 0. column is not layouted.
       
  1532             //text layout
       
  1533             textlayout = AknLayoutScalable_Avkon::
       
  1534                          list_single_graphic_pane_t1_cp2(0).LayoutLine();
       
  1535             //layout for user defined image
       
  1536             graphiclayout = AknLayoutScalable_Avkon::
       
  1537                             list_single_graphic_pane_g1_cp2(0).LayoutLine();
       
  1538         }
       
  1539         //set and layout remaining columns
       
  1540         aColumnData->SetTextSubCellL(ETextColumn, textlayout);
       
  1541         aColumnData->SetGraphicSubCellL(EUserDefinedImagesColumn,
       
  1542                                         graphiclayout);
       
  1543     }
       
  1544     else
       
  1545     { //ChoiceGroup doesn't have user defined images
       
  1546         if (iType != MMIDChoiceGroup::EPopup)
       
  1547         { //ChoiceGroup
       
  1548             //Normal ChoiceGroup must have radiobuton/checkbox icons
       
  1549             //if MULTIPLE or EXCLUSIVE type is set.
       
  1550             //We set and layout 0. column for those icons.
       
  1551             aColumnData->SetGraphicSubCellL(ERadioButtonOrCheckBoxColumn,
       
  1552                                             AknLayoutScalable_Avkon::
       
  1553                                             list_single_midp_graphic_pane_g4_cp().LayoutLine());
       
  1554             // Set and layout text column.
       
  1555             aColumnData->SetTextSubCellL(ETextColumn,
       
  1556                                          AknLayoutScalable_Avkon::
       
  1557                                          list_single_midp_graphic_pane_t1_cp().LayoutLine());
       
  1558         }
       
  1559         else
       
  1560         { //Popup ChoiceGroup - must not have radiobuton/checkbox icons,
       
  1561             // so that 0. column is not layouted.
       
  1562             // Set and layout text column.
       
  1563             aColumnData->SetTextSubCellL(ETextColumn,
       
  1564                                          AknLayoutScalable_Avkon::
       
  1565                                          list_single_pane_t1_cp2(0).LayoutLine());
       
  1566         }
       
  1567         // Hide the 1. graphic column when there are no user defined images
       
  1568         TAknWindowLineLayout layout =
       
  1569             AknLayoutScalable_Avkon::
       
  1570             list_single_2graphic_pane_g1_cp4().LayoutLine();
       
  1571         layout.iW = 0;  // zero width
       
  1572         aColumnData->SetGraphicSubCellL(EUserDefinedImagesColumn, layout);
       
  1573     }
       
  1574 }
       
  1575 
       
  1576 // Calculate the rect to assign to the listbox.
       
  1577 TRect CMIDChoiceGroupControl::ListBoxRect(const TRect& aRect) const
       
  1578 {
       
  1579     TRect rect(aRect);
       
  1580 
       
  1581     if (iListBox)
       
  1582     {
       
  1583         TAknLayoutRect layoutRect;
       
  1584         layoutRect.LayoutRect(rect, AknLayoutScalable_Avkon::
       
  1585                               form2_midp_field_choice_group_pane().LayoutLine());
       
  1586         rect = layoutRect.Rect();
       
  1587     }
       
  1588 
       
  1589     return rect;
       
  1590 }
       
  1591 
       
  1592 
       
  1593 // Sets selection state of element at <aIndex>
       
  1594 // This a private method. There is also a public method
       
  1595 // CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected)
       
  1596 // which calls this one.
       
  1597 void CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected, TBool aPostEvent)
       
  1598 {
       
  1599     ASSERT(iModel);
       
  1600     iModel->SelectElementL(aIndex, aSelected);
       
  1601     iItem->UpdateCommands();
       
  1602 
       
  1603     if (aPostEvent)
       
  1604     {
       
  1605         iItem->PostItemStateChangedEventL();
       
  1606     }
       
  1607 }
       
  1608 
       
  1609 
       
  1610 void CMIDChoiceGroupControl::UpdateMargins()
       
  1611 {
       
  1612     TAknLayoutRect layoutRect;
       
  1613     // use the screen as a parent only the margins are calculated
       
  1614     TRect screenRect(iEikonEnv->ScreenDevice()->SizeInPixels());
       
  1615     layoutRect.LayoutRect(screenRect, AknLayoutScalable_Avkon::
       
  1616                           form2_midp_field_choice_group_pane().LayoutLine());
       
  1617 
       
  1618     TRect contentRect = layoutRect.Rect();
       
  1619 
       
  1620     iContentMargins.iTop    = contentRect.iTl.iY;
       
  1621     iContentMargins.iBottom = screenRect.iBr.iY - contentRect.iBr.iY;
       
  1622     iContentMargins.iLeft   = contentRect.iTl.iX;
       
  1623     iContentMargins.iRight  = screenRect.iBr.iX - contentRect.iBr.iX;
       
  1624 }
       
  1625 
       
  1626 void CMIDChoiceGroupControl::UpdatePopupListAppearanceL(TChoiceGroupModelEvent aEvent)
       
  1627 {
       
  1628     if (!iPopupList)
       
  1629     {
       
  1630         return;
       
  1631     }
       
  1632 
       
  1633     // resize is done by default
       
  1634     TBool bResize = ETrue;
       
  1635 
       
  1636     // Act upon the event, resize and redraw the popup list as necessary
       
  1637     // EUpdateEnded and EUpdateStarted events are not possible in this
       
  1638     // function as they occur only when choice group is constructed
       
  1639     switch (aEvent)
       
  1640     {
       
  1641     case EElementAdded:
       
  1642         iPopupList->ListBox()->HandleItemAdditionL();
       
  1643         break;
       
  1644     case EElementDeleted:
       
  1645         iPopupList->ListBox()->HandleItemRemovalL();
       
  1646 
       
  1647         // Popup list loses focus if the highlighted is in the last element and
       
  1648         // an element is removed. Set focus to last element in this case.
       
  1649         if (iPopupList->ListBox()->View()->CurrentItemIndex() == KErrNotFound &&
       
  1650                 iModel->NumberOfItems() > 0)
       
  1651         {
       
  1652             iPopupList->ListBox()->View()->SetCurrentItemIndex(iModel->NumberOfItems() - 1);
       
  1653         }
       
  1654         break;
       
  1655     case EElementModified:
       
  1656         // after the LAF changes the icon column is dynamic in popup list, so resize
       
  1657         // may be needed after image has been added to or removed from element
       
  1658         break;
       
  1659     case EElementSelected:
       
  1660         // Just a redraw will do
       
  1661         bResize = EFalse;
       
  1662         break;
       
  1663     default:
       
  1664         bResize = EFalse;
       
  1665         break;
       
  1666     }
       
  1667 
       
  1668     if (bResize)
       
  1669     {
       
  1670         // cast is safe as CMIDChoiceGroupListBox is inherited from CAknColumnListBox
       
  1671         SetupColumnsL(static_cast<CEikColumnListBox*>(
       
  1672                           iPopupList->ListBox())->ItemDrawer()->ColumnData());
       
  1673         iPopupList->ResizeList();
       
  1674     }
       
  1675 
       
  1676     iPopupList->DrawDeferred();
       
  1677 }
       
  1678 
       
  1679 void CMIDChoiceGroupControl::ShowInfoPopup()
       
  1680 {
       
  1681     if (!iListBox || !IsVisible())
       
  1682     {
       
  1683         return;
       
  1684     }
       
  1685 
       
  1686     TInt index = iListBox->View()->CurrentItemIndex();
       
  1687     if (index >= 0)
       
  1688     {
       
  1689         CMIDForm* form = iItem->Form();
       
  1690         if (form)
       
  1691         {
       
  1692             form->GetPopupNoteController()->HidePopup();
       
  1693 
       
  1694             if (static_cast<CEikColumnListBox*>(iListBox)->ItemDrawer()->ColumnData()->
       
  1695                     CurrentItemTextWasClipped())
       
  1696             {
       
  1697                 CMIDChoiceGroupElement* pElement = iModel->ElementAt(index);
       
  1698                 if (pElement)
       
  1699                 {
       
  1700                     TRect mainPane;
       
  1701                     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPane);
       
  1702 
       
  1703                     // HighLight rect returns the rect in propotion to whole screen,
       
  1704                     // move it in propotion to the main pane to check if its visible.
       
  1705                     TRect rect = iListBox->HighlightRect();
       
  1706                     TRect temp = rect;
       
  1707                     temp.Move(0, -mainPane.iTl.iY);
       
  1708                     if (form->RectPartiallyVisible(temp))
       
  1709                     {
       
  1710                         TRAP_IGNORE(form->GetPopupNoteController()->ShowPopupL(pElement->Text(),
       
  1711                                     rect));
       
  1712                     }
       
  1713                 }
       
  1714             }
       
  1715             else
       
  1716             {
       
  1717                 DEBUG("CMIDChoiceGroupControl::ShowInfoPopup(): text not clipped");
       
  1718             }
       
  1719         }
       
  1720     }
       
  1721 }
       
  1722 
       
  1723 #ifdef RD_SCALABLE_UI_V2
       
  1724 void CMIDChoiceGroupControl::TimedScroll(CMIDForm::TDirection aDirection)
       
  1725 {
       
  1726     ASSERT(iListBox);
       
  1727 
       
  1728     TRect itemRect = iItem->Rect();
       
  1729     TInt formHeight = iItem->FormRect().Height();
       
  1730 
       
  1731     // There must be something to scroll
       
  1732     if ((aDirection == CMIDForm::EDown && itemRect.iBr.iY <= formHeight) ||
       
  1733             (aDirection == CMIDForm::EUp   && itemRect.iTl.iY >= 0))
       
  1734     {
       
  1735         return;
       
  1736     }
       
  1737 
       
  1738     iPointerDragHasStarted = ETrue;
       
  1739 
       
  1740     TInt scroll = 0;
       
  1741     TInt elementHeight = iListBox->ItemHeight();
       
  1742     TInt index = FirstInvisibleElement(aDirection);
       
  1743 
       
  1744     // If valid index was found, adjust scroll so that the element at index will be fully visible.
       
  1745     // Otherwise scroll height of one element or to the bottom/top of the item.
       
  1746     if (aDirection == CMIDForm::EDown)
       
  1747     {
       
  1748         if (index != KErrNotFound)
       
  1749         {
       
  1750             scroll = -(iListBox->View()->ItemPos(index).iY + elementHeight - formHeight);
       
  1751         }
       
  1752         else
       
  1753         {
       
  1754             scroll = Max(-elementHeight, -(itemRect.iBr.iY - formHeight));
       
  1755         }
       
  1756     }
       
  1757     else if (aDirection == CMIDForm::EUp)
       
  1758     {
       
  1759         if (index != KErrNotFound)
       
  1760         {
       
  1761             scroll = -iListBox->View()->ItemPos(index).iY;
       
  1762         }
       
  1763         else
       
  1764         {
       
  1765             scroll = Min(elementHeight, -itemRect.iTl.iY);
       
  1766         }
       
  1767     }
       
  1768 
       
  1769     if (index != KErrNotFound)
       
  1770     {
       
  1771         iListBox->View()->SetCurrentItemIndex(index);
       
  1772     }
       
  1773 
       
  1774     TRAP_IGNORE(ReportEventL(MMIDChoiceGroupControlObserver::EScrollRequest, (TAny*)scroll));
       
  1775 }
       
  1776 
       
  1777 TInt CMIDChoiceGroupControl::FirstInvisibleElement(CMIDForm::TDirection aScrollDirection) const
       
  1778 {
       
  1779     TInt index = KErrNotFound;
       
  1780     TInt formHeight = iItem->FormRect().Height();
       
  1781 
       
  1782     // First find which element is currently right in the top or bottom edge of the form
       
  1783     TInt yPos = (aScrollDirection == CMIDForm::EDown) ? formHeight : 0;
       
  1784 
       
  1785     TBool found = iListBox->View()->XYPosToItemIndex(
       
  1786                       TPoint(iListBox->Rect().Center().iX, yPos), index);
       
  1787 
       
  1788     // Check if more than half of the element at index is already visible, move to next item or
       
  1789     // if already in the last/first element, return KErrNotFound
       
  1790     if (found && aScrollDirection == CMIDForm::EDown)
       
  1791     {
       
  1792         if (formHeight - iListBox->View()->ItemPos(index).iY > (iListBox->ItemHeight() / 2))
       
  1793         {
       
  1794             index = (index < (iModel->NumberOfItems() - 1)) ? index + 1 : KErrNotFound;
       
  1795         }
       
  1796     }
       
  1797     else if (found && aScrollDirection == CMIDForm::EUp)
       
  1798     {
       
  1799         if (-iListBox->View()->ItemPos(index).iY < (iListBox->ItemHeight() / 2))
       
  1800         {
       
  1801             index = (index > 0) ? index - 1 : KErrNotFound;
       
  1802         }
       
  1803     }
       
  1804 
       
  1805     return index;
       
  1806 }
       
  1807 
       
  1808 #endif
       
  1809 
       
  1810 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1811 CMIDForm* CMIDChoiceGroupControl::Form() const
       
  1812 {
       
  1813     return iItem->Form();
       
  1814 }
       
  1815 #endif // RD_JAVA_S60_RELEASE_9_2