javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swtcombo.cpp
branchRCL_3
changeset 14 04becd199f91
child 19 71c436fe3ce0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swtcombo.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1468 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia Corporation - S60 implementation
+ *******************************************************************************/
+
+
+#include <AknUtils.h>
+#include <AknsDrawUtils.h>
+#include <AknLayoutFont.h>
+#ifdef RD_TACTILE_FEEDBACK
+#include <touchfeedback.h>
+#endif // RD_TACTILE_FEEDBACK
+#include <swtlaffacade.h>
+#include <swtcomboproxy.h>
+#include "swtcombo.h"
+
+
+// NOTE: Due to several issues in operating a CAknChoiceList while open,
+// workarounds have been put in place troughout this implementation,
+// which consist of closing the combo, before operating on it.
+
+
+const TInt KMaxVisibleItemCount(6);
+_LIT(KTxtSpace, " ");
+
+#ifdef RD_TACTILE_FEEDBACK
+const TInt KTouchFeedbackRectId1(0);
+#endif // RD_TACTILE_FEEDBACK
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::NewL
+// ---------------------------------------------------------------------------
+//
+CSwtCombo* CSwtCombo::NewL(MSwtDisplay& aDisplay, TSwtPeer aPeer,
+                           MSwtComposite& aParent, TInt aStyle)
+{
+    CSwtCombo* self = new(ELeave) CSwtCombo(aDisplay, aPeer,
+                                            aParent, aStyle);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    self->InitControlBaseL();
+    CleanupStack::Pop(self);
+    return self;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CSwtCombo
+// ---------------------------------------------------------------------------
+//
+CSwtCombo::CSwtCombo(MSwtDisplay& aDisplay, TSwtPeer aPeer,
+                     MSwtComposite& aParent, TInt aStyle)
+        : ASwtScrollableBase(aDisplay, aPeer, &aParent, aStyle)
+{
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::~CSwtCombo
+// ---------------------------------------------------------------------------
+//
+CSwtCombo::~CSwtCombo()
+{
+#ifdef RD_TACTILE_FEEDBACK
+    if (iFeedback)
+    {
+        iFeedback->RemoveFeedbackForControl(this);
+    }
+#endif // RD_TACTILE_FEEDBACK
+
+    // Choice list, own.
+    delete iCombo;
+    iCombo = NULL;
+
+    // String item array, not own
+    iItems = NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::ConstructL()
+{
+    // Handle parent
+    CCoeControl& coeParent = iParent->Control()->CoeControl();
+    SetContainerWindowL(coeParent);
+    CAknControl::MakeVisible(coeParent.IsVisible());
+    CAknControl::SetDimmed(coeParent.IsDimmed());
+
+    // Create Avkon choice list and its item array.
+    iItems = new(ELeave) CDesCArrayFlat(1);
+    iCombo = CSwtComboProxy::NewL(this, iItems);
+
+    // Construct choice list.
+    iCombo->SetContainerWindowL(*this);
+    iCombo->SetObserver(this);
+    iCombo->SetFlags(iCombo->Flags() | CSwtComboProxy::EComboPositionBottom);
+    iCombo->SetSelectedIndex(-1);
+    iPrevSelIdx = -1;
+
+#ifdef RD_TACTILE_FEEDBACK
+    iFeedback = MTouchFeedback::Instance();
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+    // Disabling feedback for CSwtCombo.
+    // When enabled - first tap on combo creates extra feedback,
+    // that is not needed.
+    if (iFeedback)
+    {
+        iFeedback->EnableFeedbackForControl(this, EFalse);
+    }
+#endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+#endif // RD_TACTILE_FEEDBACK
+
+    // Ready to draw
+    SetComponentsToInheritVisibility(ETrue);
+    SetBackground(this);   // Back will be drawn by ASwtControlBase::Draw
+    ActivateL();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CountComponentControls
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::CountComponentControls() const
+{
+    return 1;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComponentControl
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+CCoeControl* CSwtCombo::ComponentControl(TInt /*aIdx*/) const
+{
+    return iCombo;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::PositionChanged
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::PositionChanged()
+{
+    CenterContainedCombo();
+    UpdateTouchFeedbackRect();
+    HandlePositionChanged();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SizeChanged
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SizeChanged()
+{
+    TRect rect(BorderInnerRect());
+    iCombo->SetSize(TSize(rect.Size().iWidth, iCombo->MinimumSize().iHeight));
+    CenterContainedCombo();
+    UpdateTouchFeedbackRect();
+    HandleSizeChanged();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::FocusChanged
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::FocusChanged(TDrawNow aDrawNow)
+{
+    // The Combo looses focus to the open popup list due to stack change.
+    if (iOpening)
+    {
+        if (!IsFocused())
+        {
+            SetFocus(ETrue);
+        }
+        return;
+    }
+    TBool isFocused = IsFocusControl();
+    iCombo->SetFocus(isFocused, aDrawNow);
+    HandleFocusChanged(aDrawNow);
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::MakeVisible
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::MakeVisible(TBool aVisible)
+{
+    DoClose();
+#ifdef RD_TACTILE_FEEDBACK
+    if (iFeedback)
+    {
+        iFeedback->EnableFeedbackForControl(this, aVisible);
+    }
+#endif // RD_TACTILE_FEEDBACK
+    CAknControl::MakeVisible(aVisible);
+    FocusabilityChanged();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetDimmed
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetDimmed(TBool aDimmed)
+{
+    DoClose();
+#ifdef RD_TACTILE_FEEDBACK
+    if (iFeedback)
+    {
+        iFeedback->EnableFeedbackForControl(this, !aDimmed);
+    }
+#endif // RD_TACTILE_FEEDBACK
+    CAknControl::SetDimmed(aDimmed);
+    iCombo->SetDimmed(aDimmed);
+    FocusabilityChanged();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::OfferKeyEventL
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+TKeyResponse CSwtCombo::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
+{
+    if (iOpen)
+    {
+        // The popup list already handled the key event at this point.
+        // Without this return, the popup list would open again.
+        // Therefore, while open, the Combo does not generate key events.
+        return EKeyWasConsumed;
+    }
+    TBool traversalDoIt = ETrue;
+    if (aKeyEvent.iCode == EKeyEnter || aKeyEvent.iCode == EKeyOK)
+    {
+        traversalDoIt = EFalse;
+    }
+    return HandleKeyL(aKeyEvent, aType, traversalDoIt);
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::HandlePointerEventL
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+#ifdef RD_SCALABLE_UI_V2
+void CSwtCombo::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+{
+    TBool pressed = iPressed;
+    if (aPointerEvent.iType == TPointerEvent::EButton1Down)
+    {
+        iPressed = ETrue;
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+        // When clicking on area outside combo (e.g. on Caption of captioned
+        // control), no native feedback (from CAknChoiceList) is generated.
+        // So eSWT has to generate the feedback.
+        if (iFeedback && !iCombo->Rect().Contains(aPointerEvent.iPosition))
+        {
+            iFeedback->InstantFeedback(ETouchFeedbackList);
+        }
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+    }
+
+    if (aPointerEvent.iType == TPointerEvent::EButton1Up)
+    {
+        if (!iDisplay.RevertPointerEvent())
+        {
+            // Opening the popup choice list must be always done manually.
+            DoOpenL();
+        }
+        else
+        {
+            iPressed = EFalse;
+        }
+    }
+    else
+    {
+        CCoeControl::HandlePointerEventL(aPointerEvent);
+    }
+
+    if (pressed != iPressed)
+        Redraw();
+}
+#endif //RD_SCALABLE_UI_V2
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::HandleResourceChange
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::HandleResourceChange(TInt aType)
+{
+    TRAP_IGNORE(SwtHandleResourceChangeL(aType));
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::Draw
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::Draw(const TRect& /*aRect*/) const
+{
+    DrawContainedComboBorder();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::MopSupplyObject
+// From CCoeControl
+// ---------------------------------------------------------------------------
+//
+TTypeUid::Ptr CSwtCombo::MopSupplyObject(TTypeUid aId)
+{
+    TTypeUid::Ptr id = ASwtControlBase::SwtMopSupplyObject(aId);
+    if (!id.Pointer())
+    {
+        return CAknControl::MopSupplyObject(aId);
+    }
+    else
+    {
+        return id;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SbFrame
+// From ASwtScrollableBase
+// ---------------------------------------------------------------------------
+//
+CEikScrollBarFrame* CSwtCombo::SbFrame() const
+{
+    return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CoeControl
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+CCoeControl& CSwtCombo::CoeControl()
+{
+    return *this;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CoeControl
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+const CCoeControl& CSwtCombo::CoeControl() const
+{
+    return *this;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeSizeL
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+TSize CSwtCombo::ComputeSizeL(TInt aWhint, TInt aHhint)
+{
+    TSize prefSize(aWhint, aHhint);
+
+    if (aWhint != KSwtDefault && aHhint != KSwtDefault)
+    {
+        return prefSize;
+    }
+
+    // WORKAROUND: The platform API does not provide functions that could
+    // return ideal dimensions based on content. Therefore, default values
+    // from CAknChoiceList layouts and text measuring give the computed size.
+    // WARNING: We asume here that CAknChoiceList will not change layouts.
+    TInt w = aWhint;
+    TInt h = aHhint;
+
+    CSwtLafFacade::TSwtLafFacadeWindowLineLayout layoutPane =
+        CSwtLafFacade::GetChoiceListPaneLayout();
+    CSwtLafFacade::TSwtLafFacadeTextLineLayout layoutLabel =
+        CSwtLafFacade::GetChoiceListPaneT1Layout();
+
+    if (aHhint == KSwtDefault)
+    {
+        // Calculate height based on choice list pane and border.
+        h = layoutPane.iH;
+
+        MSwtUiUtils& utils = iDisplay.UiUtils();
+        TMargins8 padding = iDisplay.UiUtils().InlineReferencePadding();
+        TInt height = utils.InlineReferenceFontHeight();
+        height += padding.iTop + padding.iBottom;
+        if (h < height) h = height;
+
+        h += BorderSizeDelta().iHeight;
+    }
+
+    if (aWhint == KSwtDefault)
+    {
+        // Go trough all the items and get the with of the widest one.
+        TInt txtMaxW = 0;
+        const CAknLayoutFont* font = AknLayoutUtils::LayoutFontFromId(
+                                         layoutLabel.iFont);
+        if (font)
+        {
+            TInt count = iItems->Count();
+            for (TInt i = 0; i < count; i++)
+            {
+                txtMaxW = Max(txtMaxW,
+                              font->TextWidthInPixels((*iItems)[i]));
+            }
+            // WORKAROUND: Add space for one more char to avoid clipping :)
+            txtMaxW += font->TextWidthInPixels(KTxtSpace);
+        }
+
+        // Calculate width based on widest item, label pane and border.
+        w += txtMaxW;
+        w += layoutLabel.il;
+        w += layoutLabel.ir;
+        w += BorderSizeDelta().iWidth;
+    }
+    prefSize.iHeight = h;
+    prefSize.iWidth = w;
+
+    return prefSize;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ProcessKeyEventL
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::ProcessKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
+{
+    if (aType == EEventKey)
+    {
+        if (aKeyEvent.iCode == EKeyEnter || aKeyEvent.iCode == EKeyOK)
+        {
+            if (!iOpen)
+            {
+                DoOpenL();
+                iDisplay.PostDefaultSelectionEventL(iPeer);
+            }
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::IsKeyUsed
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+TBool CSwtCombo::IsKeyUsed(TUint aKeyCode) const
+{
+    TBool used = ETrue;
+    switch (aKeyCode)
+    {
+    case EKeyBackspace:
+        used = EFalse;
+        break;
+
+    default:
+        break;
+    }
+    return used;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SwtHandleResourceChangeL
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SwtHandleResourceChangeL(TInt aType)
+{
+    if (aType == KEikDynamicLayoutVariantSwitch)
+    {
+        DoClose();
+    }
+
+    CAknControl::HandleResourceChange(aType);
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::MSKLabelL
+// From MSwtControl
+// ---------------------------------------------------------------------------
+//
+HBufC* CSwtCombo::MSKLabelL() const
+{
+    return iEikonEnv->AllocReadResourceL(R_QTN_MSK_OPEN);
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtScrollable
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::ComputeTrim(TRect& aRect) const
+{
+    aRect = BorderOuterRect(aRect);
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+MSwtScrollable* CSwtCombo::Scrollable()
+{
+    return this;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::RegisterChildL(MSwtControl& /*aChild*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::UnregisterChild(MSwtControl& /*aChild*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+CSwtPeerArray* CSwtCombo::GetChildrenPeersL()
+{
+    return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::Children
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+const RSwtControlArray* CSwtCombo::Children() const
+{
+    return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ChildFocusChanged
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::ChildFocusChanged(MSwtControl& /*aControl*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CountFocusableChildren
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::CountFocusableChildren(TInt, const MSwtControl*, TBool) const
+{
+    // DO NOTHING
+    return 0;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetTabListL(MSwtControl** /*aControls*/, TInt /*aCount*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+CSwtPeerArray* CSwtCombo::GetTabListL() const
+{
+    return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::MoveChildAbove(MSwtControl& /*aChild1*/, const MSwtControl* /*aChild2*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::MoveChildBelow(MSwtControl& /*aChild1*/, const MSwtControl* /*aChild2*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ComputeTrim
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::NotifyRadioGroup(MSwtButton* /*aSelectedButton*/)
+{
+    // DO NOTHING
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetScrolledCompositeContentL
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetScrolledCompositeContentL(MSwtControl* /*aContent*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ScrolledCompositeContent
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+MSwtControl* CSwtCombo::ScrolledCompositeContent() const
+{
+    return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ScrolledCompositePysicsAction
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::ScrolledCompositePysicsAction() const
+{
+    return 0;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DrawScrollBarBackground
+// From MSwtComposite
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DrawScrollBarBackground(const TRect& /*aRect*/) const
+{
+    // Do nothing
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::Composite
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+MSwtComposite* CSwtCombo::Composite()
+{
+    return this;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::AppendL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::AppendL(const TDesC& aTxt)
+{
+    if (iItems->Count() == 0)
+    {
+        UpdateTouchFeedbackRect();
+    }
+
+    // Get selected index
+    TInt selIdx = iCombo->SelectedIndex();
+
+    // Close if opened
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Append item.
+    iItems->AppendL(aTxt);
+
+    // Restore selected index
+    iCombo->SetSelectedIndex(selIdx);
+
+    // Reopen if previously opened
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::InsertL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::InsertL(TInt aIdx, const TDesC& aTxt)
+{
+    // Throw exception on invalid range
+    if ((aIdx < 0) || (aIdx > iItems->Count()))
+    {
+        User::Leave(ESwtErrorInvalidRange);
+    }
+
+    if (iItems->Count() == 0)
+    {
+        UpdateTouchFeedbackRect();
+    }
+
+    // Get selected index
+    TInt selIdx = iCombo->SelectedIndex();
+
+    // Close if opened
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Insert string
+    iItems->InsertL(aIdx, aTxt);
+
+    // Restore selected index
+    if (aIdx <= selIdx)
+    {
+        selIdx++;
+    }
+    iCombo->SetSelectedIndex(selIdx);
+
+    // Reopen if previously opened
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::ClearSelectionL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::ClearSelectionL()
+{
+    // NOT SUPPORTED FOR READ_ONLY
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CopyL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::CopyL()
+{
+    // NOT SUPPORTED FOR READ_ONLY
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DeselectItem
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DeselectItem(TInt aIdx)
+{
+    if ((aIdx >= 0) && (aIdx < iItems->Count()))
+    {
+        if (iCombo->SelectedIndex() == aIdx)
+        {
+            // Item exists and is selected, clear selection
+            TRAP_IGNORE(DoSelectItemL(-1));
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DeselectAll
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DeselectAll()
+{
+    TRAP_IGNORE(DoSelectItemL(-1));
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetItemL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::GetItemL(TInt aIdx, TPtrC& aTxt) const
+{
+    if ((aIdx >= 0) && (aIdx < iItems->Count()))
+    {
+        // Item exists, return its string
+        aTxt.Set((*iItems)[aIdx]);
+    }
+    else
+    {
+        // Item does not exist, leave
+        User::Leave(ESwtErrorInvalidRange);
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetItemCount
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetItemCount() const
+{
+    return iItems->Count();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetItemHeight
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetItemHeight() const
+{
+    // NOT SUPPORTED BY AVKON
+    return 0;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetItemsL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+CPtrCArray* CSwtCombo::GetItemsL() const
+{
+    TInt txtCount = iItems->Count();
+
+    // No items, return NULL
+    if (txtCount == 0)
+    {
+        return NULL;
+    }
+
+    // Return copy of the item array
+    CPtrCArray* arr = new(ELeave) CPtrCArray(txtCount);
+    CleanupStack::PushL(arr);
+    for (TInt i = 0; i < txtCount; i++)
+    {
+        arr->AppendL((*iItems)[i]);
+    }
+    CleanupStack::Pop(arr);
+
+    return arr;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetOrientation
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetOrientation() const
+{
+    if (iCombo->Flags() & CSwtComboProxy::EComboPositionLeft)
+    {
+        return KSwtStyleRightToLeft;
+    }
+    else
+    {
+        return KSwtStyleLeftToRight;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetSelection
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TPoint CSwtCombo::GetSelection() const
+{
+    // NOT SUPPORTED FOR READ_ONLY
+    return TPoint();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetSelectionIndex
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetSelectionIndex() const
+{
+    return iCombo->SelectedIndex();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetTextL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+HBufC* CSwtCombo::GetTextL() const
+{
+    TInt idx = iCombo->SelectedIndex();
+    if (idx >= 0 && idx < iItems->Count())
+    {
+        // An item is selected / shown in the label, return its string
+        HBufC* buf = NULL;
+        TPtrC txt((*iItems)[iCombo->SelectedIndex()]);
+        buf = HBufC::NewL(txt.Length());
+        *buf = txt;
+        return buf;
+    }
+    else
+    {
+        // No item selected / empty label
+        return KNullDesC().AllocL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetTextHeightL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetTextHeightL() const
+{
+    return iCombo->MinimumSize().iHeight;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetTextLimit
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetTextLimit() const
+{
+    // NOT SUPPORTED FOR READ_ONLY
+    return -1;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::GetVisibleItemCount
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::GetVisibleItemCount() const
+{
+    // WORKAROUND No API for this but we know that this number is max 6
+    if (iItems->Count() < KMaxVisibleItemCount)
+    {
+        return iItems->Count();
+    }
+    else
+    {
+        return KMaxVisibleItemCount;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::IndexOf
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TInt CSwtCombo::IndexOf(const TDesC& aTxt, TInt& aStart) const
+{
+    // Out of range check
+    if ((aStart < 0) || (aStart >= iItems->Count()))
+    {
+        return KErrNotFound;
+    }
+
+    // Search for the string, return index
+    if (aStart == 0)
+    {
+        TInt pos;
+        if (iItems->Find(aTxt, pos) == KErrNone)
+        {
+            return pos;
+        }
+    }
+    else
+    {
+        for (TInt i = aStart; i < iItems->Count(); i++)
+        {
+            if (aTxt.Compare((*iItems)[i]) == KErrNone)
+            {
+                return i;
+            }
+        }
+    }
+
+    return KErrNotFound;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::InsertInTextControlL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TBool CSwtCombo::InsertInTextControlL(const TDesC& /*aTxt*/)
+{
+    // NOT SUPPORTED FOR READ_ONLY
+    return EFalse;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::PasteL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TBool CSwtCombo::PasteL()
+{
+    // NOT SUPPORTED FOR READ_ONLY
+    return EFalse;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::RemoveItemL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::RemoveItemL(TInt aIdx)
+{
+    // Leave if out of range
+    if ((aIdx < 0) || (aIdx >= iItems->Count()))
+    {
+        User::Leave(ESwtErrorInvalidRange);
+    }
+
+    // Get selected index
+    TInt selIdx = iCombo->SelectedIndex();
+
+    // Close if open
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Remove item
+    iItems->Delete(aIdx);
+
+    // Restore selected index
+    if (aIdx <= selIdx)
+    {
+        if (aIdx == selIdx)
+        {
+            selIdx = -1;
+        }
+        else
+        {
+            selIdx--;
+        }
+    }
+    iCombo->SetSelectedIndex(selIdx);
+
+    // Clear feedback if no items left
+    if (iItems->Count() == 0)
+    {
+        UpdateTouchFeedbackRect();
+    }
+
+    // Reopen if previously open
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// --------------------------------------------------------------------------
+// CSwtCombo::RemoveRangeL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::RemoveRangeL(TInt aStart, TInt aEnd)
+{
+    ASSERT(aStart <= aEnd);
+
+    // Leave if out of range
+    if ((aStart < 0) || (aEnd >= iItems->Count()))
+    {
+        User::Leave(ESwtErrorInvalidRange);
+    }
+
+    // Get selected index
+    TInt selIdx = iCombo->SelectedIndex();
+
+    // Close if open
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Remove inclusive range of items
+    iItems->Delete(aStart, aEnd - aStart + 1);
+
+    // Restore selected index
+    if (aStart <= selIdx)
+    {
+        if (aEnd >= selIdx)
+        {
+            selIdx = -1;
+        }
+        else
+        {
+            selIdx = selIdx - (aEnd - aStart + 1);
+        }
+    }
+    iCombo->SetSelectedIndex(selIdx);
+
+    // Clear feedback if no items left
+    if (iItems->Count() == 0)
+    {
+        UpdateTouchFeedbackRect();
+    }
+
+    // Reopen if previously open
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::RemoveAllL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::RemoveAllL()
+{
+    // Close if open
+    if (iOpen)
+    {
+        DoClose();
+    }
+
+    // Remove all items
+    iItems->Reset();
+
+    // Clear selection and feedback area
+    iCombo->SetSelectedIndex(-1);
+    UpdateTouchFeedbackRect();
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SelectItemL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SelectItemL(TInt aIdx)
+{
+    if ((aIdx >= 0) && (aIdx < iItems->Count()))
+    {
+        // Item exists, select it
+        DoSelectItemL(aIdx);
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetItemsL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetItemsL(MDesCArray* aTxtArr)
+{
+    // Copy the array
+    CDesCArray* arr = new(ELeave) CDesCArrayFlat(aTxtArr->MdcaCount());
+    CleanupStack::PushL(arr);
+    for (TInt i = 0; i < aTxtArr->MdcaCount(); i++)
+    {
+        arr->AppendL(aTxtArr->MdcaPoint(i));
+    }
+    CleanupStack::Pop(arr);
+
+    // Close if open
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Set copied array. The previous item array is cleared by CAknChoiceList
+    iCombo->SetItems(arr);
+    iItems = arr;
+
+    // Clear selection
+    iCombo->SetSelectedIndex(-1);
+
+    UpdateTouchFeedbackRect();
+
+    // Reopen if previously open
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetOrientationL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetOrientationL(TInt aOrientation)
+{
+    if (!(aOrientation & KSwtStyleRightToLeft
+            || aOrientation & KSwtStyleLeftToRight))
+    {
+        return;
+    }
+
+    // Close if open
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    // Change flags
+    TInt flags = iCombo->Flags();
+    if (aOrientation & KSwtStyleRightToLeft)
+    {
+        flags &= ~CSwtComboProxy::EComboPositionRight;
+        flags |= CSwtComboProxy::EComboPositionLeft;
+    }
+    else
+    {
+        flags &= ~CSwtComboProxy::EComboPositionLeft;
+        flags |= CSwtComboProxy::EComboPositionRight;
+    }
+    iCombo->SetFlags(flags);
+
+    // Reopen if previously open
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetSelectionL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetSelectionL(TInt /*aStart*/, TInt /*aEnd*/)
+{
+    // NOT SUPPORTED FOR READ_ONLY
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetTextL
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TBool CSwtCombo::SetTextL(TDes& /*aTxt*/)
+{
+    // NOT SUPPORTED FOR READ_ONLY
+    return EFalse;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetTextLimit
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+TBool CSwtCombo::SetTextLimit(TInt /*aTxtLimit*/)
+{
+    // NOT SUPPORTED BY AVKON
+    return EFalse;
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::SetVisibleItemCount
+// From MSwtCombo
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::SetVisibleItemCount(TInt /*aCount*/)
+{
+    // NOT SUPPORTED BY AVKON
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::HandleControlEventL
+// From MCoeControlObserver
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::HandleControlEventL(
+    CCoeControl* aControl,
+    TCoeEvent aEventType)
+{
+    if ((aControl == iCombo) && (aEventType == EEventStateChanged || aEventType == EEventRequestCancel))
+    {
+        // The choice list got closed
+        iOpen = EFalse;
+        iPressed = EFalse;
+
+        // If selection changed, post selection event
+        if (iPrevSelIdx != iCombo->SelectedIndex())
+        {
+            iDisplay.PostSelectionEventL(iPeer);
+        }
+
+        // Get new selection
+        iPrevSelIdx = iCombo->SelectedIndex();
+        Redraw();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DoOpenL()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DoOpenL()
+{
+    if ((!iOpen) && (iItems->Count() > 0))
+    {
+        // Open choice list only if there are items
+        iOpening = ETrue;
+        iCombo->ShowChoiceListL();
+        iOpening = EFalse;
+        iOpen = ETrue;
+
+        // This is needed by the Composite pointer handling. Composite must
+        // receive a pointer up event to clear the pointer capturing control.
+        ClaimPointerGrab();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DoClose()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DoClose()
+{
+    if (iOpen)
+    {
+        iCombo->HideChoiceList();
+        iOpen = EFalse;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DoSelectItemL()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DoSelectItemL(TInt aIdx)
+{
+    // Close if opened
+    TBool reopen = EFalse;
+    if (iOpen)
+    {
+        DoClose();
+        reopen = ETrue;
+    }
+
+    iCombo->SetSelectedIndex(aIdx);
+
+    // Reopen if previously opened
+    if (reopen)
+    {
+        DoOpenL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::CenterContainedCombo()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::CenterContainedCombo()
+{
+    TRect rect(BorderInnerRect());
+    TInt h(iCombo->Size().iHeight);
+    if (h < rect.Height())
+    {
+        iCombo->SetPosition(TPoint(rect.iTl.iX,
+                                   rect.iTl.iY + (rect.Height() - h) / 2));
+    }
+    else
+    {
+        iCombo->SetPosition(rect.iTl);
+    }
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::UpdateTouchFeedbackRect()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::UpdateTouchFeedbackRect() const
+{
+#ifdef RD_TACTILE_FEEDBACK
+    if (iFeedback)
+    {
+        if (iItems->Count() > 0)
+        {
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+            CFeedbackSpec* spec = CFeedbackSpec::New();
+            if (spec)
+            {
+                spec->AddFeedback(ETouchEventStylusDown, ETouchFeedbackList);
+                spec->AddFeedback(ETouchEventStylusUp, ETouchFeedbackList);
+                iFeedback->SetFeedbackArea(
+                    this, KTouchFeedbackRectId1, Rect(), spec);
+                delete spec;
+            }
+#else
+            iFeedback->SetFeedbackArea(this, KTouchFeedbackRectId1, Rect(),
+                                       ETouchFeedbackBasic, ETouchEventStylusDown);
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+        }
+        else
+        {
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+            CFeedbackSpec* spec = CFeedbackSpec::New();
+            if (spec)
+            {
+                spec->AddFeedback(ETouchEventStylusDown, ETouchFeedbackNone);
+                spec->AddFeedback(ETouchEventStylusUp, ETouchFeedbackNone);
+                iFeedback->SetFeedbackArea(
+                    this, KTouchFeedbackRectId1, Rect(), spec);
+                delete spec;
+            }
+#else
+            iFeedback->ChangeFeedbackType(this, KTouchFeedbackRectId1,
+                                          ETouchFeedbackNone);
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+        }
+    }
+#endif //RD_TACTILE_FEEDBACK
+}
+
+// ---------------------------------------------------------------------------
+// CSwtCombo::DrawContainedComboBorder()
+// ---------------------------------------------------------------------------
+//
+void CSwtCombo::DrawContainedComboBorder() const
+{
+    CWindowGc& gc = SystemGc();
+    gc.SetBrushStyle(CGraphicsContext::ENullBrush);
+    gc.SetPenColor(iDisplay.UiUtils().GetSystemColor(ESwtColorWidgetBorder));
+    gc.SetPenStyle(CGraphicsContext::ESolidPen);
+    gc.SetPenSize(TSize(1, 1));
+    gc.DrawRect(iCombo->Rect());
+}
+