javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupModel.cpp
branchRCL_3
changeset 19 04becd199f91
child 77 7cee158cb8cd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupModel.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,591 @@
+/*
+* 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 model
+*
+*/
+
+
+#include "CMIDChoiceGroupModel.h"
+#include "CMIDDisplayable.h"
+
+#include <e32def.h>
+
+#include <aknconsts.h>
+// using TMifAvkon enumeration
+#include <avkon.mbg>
+// LAF
+// AknLayoutScalable_Avkon::list_single_2graphic_pane_g2_cp4()
+#include <aknlayoutscalable_avkon.cdl.h>
+
+#include <j2me/jdebug.h>
+
+// Index where element icons start in the icon array. They're
+// preceded by selection state icons (currently 2, selected and nonselected)
+const TInt KElementIconStartIndex = 2;
+
+/** This macro is executed each time a trapped call returns an error code different than KErrNone */
+#undef  TRAP_INSTRUMENTATION_LEAVE
+#define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDChoiceGroupModel.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult);
+
+
+// C'tor
+CMIDChoiceGroupModel::CMIDChoiceGroupModel(
+    MMIDChoiceGroup::TChoiceType aType)
+        : CAknFilteredTextListBoxModel(),
+        iType(aType),
+        iUpdating(EFalse)
+{
+}
+
+
+// D'tor
+CMIDChoiceGroupModel::~CMIDChoiceGroupModel()
+{
+    // Delete element array
+    if (iElements)
+    {
+        //all elemnts in iElements array should be destroyed
+        //to prevent memory leak
+        iElements->ResetAndDestroy();
+        delete iElements;
+    }
+
+    // Delete icon array, do not delete icons
+    if (iIconArray)
+    {
+        iIconArray->Reset();
+        delete iIconArray;
+    }
+
+    // Delete icons
+    delete iIconSelected;
+    delete iIconNotSelected;
+    delete iIconDummy;
+}
+
+
+// Two-phase constructor, initialises member arrays and stuff
+void CMIDChoiceGroupModel::ConstructL(CEikonEnv* aEikonEnv)
+{
+    ASSERT(aEikonEnv);
+
+    // Create element array
+    iElements = new(ELeave) CArrayPtrFlat<CMIDChoiceGroupElement>(
+        KCGElementArrayGranularity);
+
+    // Create icon array
+    iIconArray = new(ELeave) CArrayPtrFlat<CGulIcon>(
+        KCGElementArrayGranularity);
+
+    ReConstructSelectionIconsL();
+
+    // Create the dummy icon (zero-sized bitmap)
+    CFbsBitmap* bitmap = new(ELeave) CFbsBitmap();
+    bitmap->Create(TSize(0,0), aEikonEnv->DefaultDisplayMode());
+
+    CleanupStack::PushL(bitmap);
+    iIconDummy = CGulIcon::NewL(bitmap);
+    CleanupStack::Pop(); // bitmap
+}
+
+/** Create selection icons according to type */
+void CMIDChoiceGroupModel::ReConstructSelectionIconsL()
+{
+    TFileName avkonbmpFilename = AknIconUtils::AvkonIconFileName();
+    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+
+    const TAknsItemID& selectedSkinId = (iType == MMIDChoiceGroup::EMultiple) ? KAknsIIDQgnIndiCheckboxOn :
+                                        KAknsIIDQgnIndiRadiobuttOn;
+
+    const TAknsItemID& notSelectedSkinId = (iType == MMIDChoiceGroup::EMultiple) ? KAknsIIDQgnIndiCheckboxOff :
+                                           KAknsIIDQgnIndiRadiobuttOff;
+
+    TInt selectedIconId = (iType == MMIDChoiceGroup::EMultiple) ? EMbmAvkonQgn_indi_checkbox_on : EMbmAvkonQgn_indi_radiobutt_on;
+    TInt selectedMaskId = (iType == MMIDChoiceGroup::EMultiple) ? EMbmAvkonQgn_indi_checkbox_on_mask : EMbmAvkonQgn_indi_radiobutt_on_mask;
+    TInt notSelectedIconId = (iType == MMIDChoiceGroup::EMultiple) ? EMbmAvkonQgn_indi_checkbox_off : EMbmAvkonQgn_indi_radiobutt_off;
+    TInt notSelectedMaskId = (iType == MMIDChoiceGroup::EMultiple) ? EMbmAvkonQgn_indi_checkbox_off_mask : EMbmAvkonQgn_indi_radiobutt_off_mask;
+
+    CFbsBitmap* bitmap = NULL;
+    CFbsBitmap* mask = NULL;
+
+    TRect screenRect;
+    AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screenRect);
+
+    TAknLayoutRect layoutRect;
+    // layout in respect of the whole screen as only the icon size is needed
+    layoutRect.LayoutRect(screenRect, AknLayoutScalable_Avkon::list_single_2graphic_pane_g2_cp4().LayoutLine());
+
+    TSize iconSize(layoutRect.Rect().Width(), layoutRect.Rect().Height());
+
+    AknsUtils::CreateColorIconLC(skin, notSelectedSkinId, KAknsIIDQsnIconColors,
+                                 EAknsCIQsnIconColorsCG14, bitmap, mask, avkonbmpFilename, notSelectedIconId,
+                                 notSelectedMaskId, KRgbBlue, iconSize, EAspectRatioPreservedAndUnusedSpaceRemoved);
+
+    CGulIcon* iconNotSelected = CGulIcon::NewL(bitmap, mask);
+    CleanupStack::Pop(2); //bitmap, mask
+
+    delete iIconNotSelected;
+    iIconNotSelected = iconNotSelected;
+
+    AknsUtils::CreateColorIconLC(skin, selectedSkinId, KAknsIIDQsnIconColors,
+                                 EAknsCIQsnIconColorsCG14, bitmap, mask, avkonbmpFilename, selectedIconId,
+                                 selectedMaskId, KRgbBlue, iconSize, EAspectRatioPreservedAndUnusedSpaceRemoved);
+
+    CGulIcon* iconSelected = CGulIcon::NewL(bitmap, mask);
+    CleanupStack::Pop(2); //bitmap, mask
+
+    delete iIconSelected;
+    iIconSelected = iconSelected;
+}
+
+// Base class overrides
+
+// The model contains more than just the strings - need to override
+// number of items query
+TInt CMIDChoiceGroupModel::NumberOfItems() const
+{
+    return iElements ? iElements->Count() : 0;
+}
+
+
+// Provides a string with correct indices to images
+TPtrC CMIDChoiceGroupModel::ItemText(TInt aItemIndex) const
+{
+    CMIDChoiceGroupElement* pElement = ElementAt(aItemIndex);
+
+    if (pElement)
+    {
+        return (pElement->LboxText(aItemIndex + KElementIconStartIndex));
+    }
+
+    return TPtrC(KNullDesC);
+}
+
+
+// Base class override
+void CMIDChoiceGroupModel::SetItemTextArray(MDesCArray* /*aItemTextArray*/)
+{
+    // Strings are stored in elements, so this is just to make sure
+    // the base class does nothing.
+}
+
+
+// Returns a pointer to the item text array, which is not used,
+// because strings are stored inside elements.
+MDesCArray* CMIDChoiceGroupModel::ItemTextArray() const
+{
+    return NULL;
+}
+
+
+// Add an element to the end of the array
+void CMIDChoiceGroupModel::AppendElementL(CMIDChoiceGroupElement* aElement)
+{
+    // Sanity check
+    if (!iElements)
+    {
+        ASSERT(EFalse);
+        return;
+    }
+
+    // If this is the first added element and choice is single selection
+    // type, initially make the first item selected
+    if ((iType != MMIDChoiceGroup::EMultiple) && (NumberOfItems() == 0))
+    {
+        aElement->SetSelected(ETrue);
+    }
+
+    iElements->AppendL(aElement);
+
+    // If not in the middle of an update, refresh a bit
+    if (!iUpdating)
+    {
+        // Refresh icon array
+        UpdateIconArrayL();
+
+        // Report event
+        ReportEventL(MMIDChoiceGroupModelObserver::EElementAdded);
+    }
+}
+
+
+// Insert an element at <aIndex>. Space must be reserved.
+void CMIDChoiceGroupModel::InsertElementL(
+    TInt aIndex,
+    CMIDChoiceGroupElement* aElement)
+{
+    if ((iElements) && (aIndex >= 0) && (aIndex <= NumberOfItems()))
+    {
+        // If this is the first added element and choice is single selection
+        // type, initially make the first inserted item selected
+        if ((iType != MMIDChoiceGroup::EMultiple) && (NumberOfItems() == 0))
+        {
+            aElement->SetSelected(ETrue);
+        }
+
+        iElements->InsertL(aIndex, aElement);
+
+        // If not in the middle of an update, refresh a bit
+        if (!iUpdating)
+        {
+            // Refresh icon array
+            UpdateIconArrayL();
+
+            // Report element addition
+            ReportEventL(MMIDChoiceGroupModelObserver::EElementAdded);
+        }
+    }
+    else
+    {
+        ASSERT(EFalse);
+    }
+}
+
+
+// Delete element at <aIndex>
+void CMIDChoiceGroupModel::DeleteElementL(TInt aIndex)
+{
+    if ((iElements) && (aIndex >= 0) && (aIndex <= NumberOfItems()))
+    {
+
+        if (iType != MMIDChoiceGroup::EMultiple && NumberOfItems() > 1)
+        {
+            CMIDChoiceGroupElement* pElement = ElementAt(aIndex);
+
+            if (pElement)
+            {
+                if (pElement->IsSelected())
+                {
+                    if ((aIndex + 1) < NumberOfItems())
+                    {
+                        CMIDChoiceGroupElement* pNextElement = ElementAt(aIndex+1);
+                        pNextElement->SetSelected(ETrue);
+                    }
+                    else
+                    {
+                        CMIDChoiceGroupElement* pPrevElement = ElementAt(aIndex-1);
+                        pPrevElement->SetSelected(ETrue);
+                    }
+                }
+            }
+        }
+
+        // Grab hold of the element for deletion, remove from array
+        // and compress the array
+        CMIDChoiceGroupElement* ptr = iElements->At(aIndex);
+        iElements->Delete(aIndex);
+        delete ptr;
+        iElements->Compress();
+
+        // If not in the middle of an update, refresh a bit
+        if (!iUpdating)
+        {
+            // Refresh icon array.
+            UpdateIconArrayL();
+
+            // Update the looks of the control
+            ReportEventL(MMIDChoiceGroupModelObserver::EElementDeleted);
+        }
+    }
+    else
+    {
+        ASSERT(EFalse);
+    }
+}
+
+
+// Delete all elements
+void CMIDChoiceGroupModel::DeleteAllL()
+{
+    if (iElements)
+    {
+        iElements->ResetAndDestroy();
+
+        // If not updating, refresh now
+        if (!iUpdating)
+        {
+            // Recreate icon array
+            UpdateIconArrayL();
+
+            // Report event
+            ReportEventL(MMIDChoiceGroupModelObserver::EElementDeleted);
+        }
+    }
+}
+
+
+// Set properties of element at <aIndex>
+void CMIDChoiceGroupModel::SetElementL(
+    TInt aIndex,
+    const TDesC& aText,
+    CFbsBitmap* aBitmap,
+    CFbsBitmap* aMask)
+{
+    CMIDChoiceGroupElement* pElement = ElementAt(aIndex);
+
+    if (pElement)
+    {
+        // Set new properties
+        pElement->SetTextL(aText);
+        if (aBitmap)
+        {
+            pElement->SetIconL(*aBitmap, aMask);
+        }
+        else
+        {
+            pElement->SetIcon(NULL, EFalse);
+        }
+
+        // Refresh stuff, if not in the middle of an update
+        if (!iUpdating)
+        {
+            // Icon may have changed, recreate array.
+            UpdateIconArrayL();
+
+            // Report event
+            ReportEventL(MMIDChoiceGroupModelObserver::EElementModified);
+        }
+    }
+}
+
+
+// Get element at position <aIndex>
+CMIDChoiceGroupElement* CMIDChoiceGroupModel::ElementAt(TInt aIndex) const
+{
+    if ((iElements) && (aIndex >= 0) && (aIndex < NumberOfItems()))
+    {
+        return iElements->At(aIndex);
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+
+// Reserve space for <aCount> elements
+void CMIDChoiceGroupModel::SetReserveL(TInt aCount)
+{
+    if ((iElements) && (aCount >= NumberOfItems()))
+    {
+        iElements->SetReserveL(aCount);
+    }
+}
+
+
+// Retrieves the icon array, recreates if flag is set
+CArrayPtr<CGulIcon>* CMIDChoiceGroupModel::IconArray(TBool aReCreate)
+{
+    if (aReCreate)
+    {
+        // Recreate, trap & ignore leaves
+        TRAP_IGNORE(UpdateIconArrayL());
+    }
+
+    return iIconArray;
+}
+
+
+// Set selection state of item at <index>.
+// If an item is set selected in an exclusive type choice, also
+// deselects other items.
+// Deselection of an item in an exlusive choice has no effect.
+void CMIDChoiceGroupModel::SelectElementL(TInt aIndex, TBool aSelected)
+{
+    ASSERT(iElements);
+
+    // Quick sanity check
+    if ((aIndex < 0) || (aIndex >= NumberOfItems()))
+    {
+        return;
+    }
+
+    // Exclusive and popup are both single-selection types
+    if (iType != MMIDChoiceGroup::EMultiple)
+    {
+        if (!aSelected)
+        {
+            // Deselecting in an exclusive - void op
+            return;
+        }
+
+        // Remove any previous selection
+        ClearSelection();
+    }
+
+    // Set the selection state of the element
+    CMIDChoiceGroupElement* pElement = ElementAt(aIndex);
+
+    if (pElement)
+    {
+        pElement->SetSelected(aSelected);
+    }
+
+    // Report selection
+    ReportEventL(MMIDChoiceGroupModelObserver::EElementSelected);
+}
+
+
+// Begin a model update. During an update, the observer will not
+// reveive notifications about element actions.
+void CMIDChoiceGroupModel::BeginUpdate()
+{
+    iUpdating = ETrue;
+
+    // Report update start
+    TRAP_IGNORE(ReportEventL(MMIDChoiceGroupModelObserver::EUpdateStarted));
+}
+
+
+// End a model update. At the end the icon array will be
+// recreated, and the associated control refreshed.
+void CMIDChoiceGroupModel::EndUpdate()
+{
+    iUpdating = EFalse;
+
+    // Create array, refresh control
+    TRAPD(ignore, UpdateIconArrayL());
+
+    // Report update end (observer should redraw)
+    TRAP(ignore, ReportEventL(MMIDChoiceGroupModelObserver::EUpdateEnded));
+}
+
+
+// Returns the index of the selected element in an exclusive
+// choice, or -1
+TInt CMIDChoiceGroupModel::SelectedElement()
+{
+    TInt nSelected = -1;
+
+    // Exclusive & Popup are both single-selection
+    if (iType != MMIDChoiceGroup::EMultiple)
+    {
+        // Loop through the elements, look for a selected one
+        TInt nCount = NumberOfItems();
+
+        for (TInt i = 0; i < nCount; i++)
+        {
+            CMIDChoiceGroupElement* pElement = ElementAt(i);
+
+            if (pElement)
+            {
+                if (pElement->IsSelected())
+                {
+                    // Found, break out
+                    nSelected = i;
+                    break;
+                }
+            }
+        }
+    }
+
+    return nSelected;
+}
+
+
+// --- private functions ---
+
+// Clears all selections, does not report, as is used when
+// subsequently a selection is set (in an exclusive choice)
+void CMIDChoiceGroupModel::ClearSelection()
+{
+    // Loop through the elements and clear element selections
+    TInt nCount = NumberOfItems();
+    for (TInt i = 0; i < nCount; i++)
+    {
+        CMIDChoiceGroupElement* pElement = ElementAt(i);
+
+        if (pElement)
+        {
+            pElement->SetSelected(EFalse);
+        }
+    }
+}
+
+
+// Reports element actions to observer
+void CMIDChoiceGroupModel::ReportEventL(
+    MMIDChoiceGroupModelObserver::TChoiceGroupModelEvent aEvent)
+{
+    if (iObserver)
+    {
+        iObserver->HandleChoiceGroupModelEventL(this, aEvent);
+    }
+}
+
+
+// Create an icon array to be given to the lbox column data.
+// This should be done every time the contents of the model are changed,
+// or icon array is retrieved with the create flag set.
+// NOTE that the indices in the array and the item strings should
+// be synchronised. The selection icon is always at index
+// 0 (selected) and 1 (not selected)
+void CMIDChoiceGroupModel::UpdateIconArrayL()
+{
+    ASSERT(iElements);
+    ASSERT(iIconArray);
+
+    // Clear array, DO NOT DELETE icons
+    iIconArray->Reset();
+
+    TInt nCount = NumberOfItems();
+
+    if (nCount <= 0)
+    {
+        return;
+    }
+
+    // First add the selection icons
+    iIconArray->AppendL(iIconSelected);
+    iIconArray->AppendL(iIconNotSelected);
+
+    // Then loop through the elements and add their icons
+    for (TInt i = 0; i < nCount; i++)
+    {
+        CMIDChoiceGroupElement *pElement = ElementAt(i);
+
+        if (pElement)
+        {
+            CGulIcon* icon = pElement->Icon();
+
+            if (icon)
+            {
+                // Add the elements icon
+                iIconArray->AppendL(icon);
+            }
+            else
+            {
+                // Add a zero-sized dummy icon
+                iIconArray->AppendL(iIconDummy);
+            }
+        }
+    }
+}
+
+TBool CMIDChoiceGroupModel::HasIcons() const
+{
+    TInt itemCount = NumberOfItems();
+    for (TInt i = 0; i < itemCount; ++i)
+    {
+        CMIDChoiceGroupElement *element = ElementAt(i);
+
+        if (element && element->Icon())
+        {
+            return ETrue;
+        }
+    }
+
+    return EFalse;
+}
+