javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupModel.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:23:59 +0300
branchRCL_3
changeset 83 26b2b12093af
parent 77 7cee158cb8cd
permissions -rw-r--r--
Revision: v2.2.17 Kit: 201041

/*
* 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;
}