--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swttree.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1065 @@
+/*******************************************************************************
+ * 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 <aknsinglecolumnstyletreelist.h>
+#include <AknsDrawUtils.h>
+#include <AknUtils.h>
+#include <avkon.mbg>
+#include <barsread.h>
+#include <swtlaffacade.h>
+#include "eswtmobileextensions.h"
+#include "swtfont.h"
+#include "swttree.h"
+#include "swtcontrolhelper.h"
+
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+#include <touchfeedback.h>
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+
+// ======== MEMBER FUNCTIONS ========
+
+
+CSwtTree* CSwtTree::NewL(MSwtDisplay& aDisplay, TSwtPeer aPeer,
+ MSwtComposite& aParent, TInt aStyle)
+{
+ CCoeControl& parentCtrl = aParent.Control()->CoeControl();
+ CSwtTree* self = new(ELeave) CSwtTree(aDisplay, aPeer, aParent, aStyle,
+ parentCtrl.IsVisible(), parentCtrl.IsDimmed());
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ self->InitControlBaseL();
+ CleanupStack::Pop(self);
+ return self;
+}
+
+CSwtTree::CSwtTree(MSwtDisplay& aDisplay, TSwtPeer aPeer,
+ MSwtComposite& aParent, TInt aStyle, TBool aVisibility, TBool aDimmed)
+ : CSwtComposite(aDisplay, aPeer, &aParent, aStyle, aVisibility, aDimmed)
+ , iItemHeightValid(EFalse)
+{
+}
+
+void CSwtTree::ConstructL()
+{
+ CCoeControl& coeParent = iParent->Control()->CoeControl();
+ SetContainerWindowL(coeParent);
+ SetComponentsToInheritVisibility(ETrue);
+ CCoeControl::MakeVisible(coeParent.IsVisible());
+ CCoeControl::SetDimmed(coeParent.IsDimmed());
+
+ iTree = CAknSingleColumnStyleTreeList::NewL(*this);
+ TInt flags = KAknTreeListMarqueeScrolling;
+ if (IsMarkable())
+ {
+ flags |= KAknTreeListMarkable;
+ }
+ iTree->SetFlags(flags);
+ iTree->AddObserverL(this);
+
+ // Eventhough container already given, we still need to do this for the skin background
+ iTree->SetContainerWindowL(*this);
+
+ // Give initial LAF value
+ UpdateItemHeight();
+
+ ActivateL();
+
+ TDisplayMode displayMode(ENone);
+ CEikonEnv* eikonEnv = iDisplay.CoeEnv();
+ if (eikonEnv)
+ {
+ CWsScreenDevice* screenDevice = eikonEnv->ScreenDevice();
+ if (screenDevice)
+ {
+ displayMode = screenDevice->DisplayMode();
+ }
+ }
+ iMaskHandler = new CSwtMaskHandler(displayMode);
+}
+
+CSwtTree::~CSwtTree()
+{
+ delete iTree;
+ iItems.Close();
+ delete iMaskHandler;
+ TInt count = iImages.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ TSize imageSize = iImages[i]->Bitmap().SizeInPixels();
+ if (imageSize.iHeight > iImageMaxSize.iHeight ||
+ imageSize.iWidth > iImageMaxSize.iWidth)
+ {
+ // If image size is bigger than the old maximum size, then
+ // the image has been also previously scaled.
+ imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
+ imageSize, iImageMaxSize);
+ }
+ iImages[i]->RemoveSubRef(imageSize);
+ iImages[i]->RemoveRef();
+ }
+ iImages.Close();
+ iImageIds.Close();
+ iImageRefs.Close();
+}
+
+TInt CSwtTree::CountComponentControls() const
+{
+ return 1;
+}
+
+CCoeControl* CSwtTree::ComponentControl(TInt /*aIdx*/) const
+{
+ return iTree;
+}
+
+void CSwtTree::HandleResourceChange(TInt aType)
+{
+ if (aType == KEikDynamicLayoutVariantSwitch)
+ {
+ iItemHeightValid = EFalse;
+ UpdateItemHeight();
+ }
+ CAknControl::HandleResourceChange(aType);
+ UpdateImagesSize();
+}
+
+TKeyResponse CSwtTree::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
+{
+ TBool traversalDoIt = ETrue;
+
+ if (iItems.Count() > 0)
+ {
+ switch (aKeyEvent.iCode)
+ {
+ case EKeyEnter:
+ case EKeyOK:
+ {
+ if (IsMarkable())
+ {
+ traversalDoIt = EFalse;
+ }
+ break;
+ }
+ case EKeyUpArrow:
+ {
+ traversalDoIt = EFalse;
+ if (iTree->FocusedItem() == iItems[0])
+ {
+ if (GetShell().FindTraversalTargetL(ESwtTraverseArrowPrevious, *this))
+ {
+ traversalDoIt = ETrue;
+ }
+ }
+ break;
+ }
+ case EKeyDownArrow:
+ {
+ traversalDoIt = EFalse;
+ if (iTree->FocusedItem() == LastCollapsedItem())
+ {
+ if (GetShell().FindTraversalTargetL(ESwtTraverseArrowNext, *this))
+ {
+ traversalDoIt = ETrue;
+ }
+ }
+ break;
+ }
+ case EKeyLeftArrow:
+ {
+ // Left key collapses node
+ TInt item = iTree->FocusedItem();
+ if (item != KAknTreeIIDNone)
+ {
+ traversalDoIt = EFalse;
+ if (iTree->Parent(item) == KAknTreeIIDRoot && !iTree->IsExpanded(item))
+ {
+ if (GetShell().FindTraversalTargetL(ESwtTraverseArrowPrevious, *this))
+ {
+ traversalDoIt = ETrue;
+ }
+ }
+ }
+ break;
+ }
+ case EKeyRightArrow:
+ {
+ // Right key expands node
+ TInt item = iTree->FocusedItem();
+ if (item != KAknTreeIIDNone)
+ {
+ traversalDoIt = EFalse;
+ if (iTree->ChildCount(item) == 0)
+ {
+ if (GetShell().FindTraversalTargetL(ESwtTraverseArrowNext, *this))
+ {
+ traversalDoIt = ETrue;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return HandleKeyL(aKeyEvent, aType, traversalDoIt);
+}
+
+void CSwtTree::SizeChanged()
+{
+ if (iTree)
+ {
+ iTree->SetRect(BorderInnerRect());
+ }
+ CSwtComposite::SizeChanged();
+}
+
+void CSwtTree::PositionChanged()
+{
+ if (iTree)
+ {
+ iTree->SetRect(BorderInnerRect());
+ }
+ CSwtComposite::PositionChanged();
+}
+
+void CSwtTree::FocusChanged(TDrawNow aDrawNow)
+{
+ // This gets called before contained list is created.
+ if (iTree)
+ {
+ TBool isFocused = IsFocusControl();
+ iTree->SetFocus(isFocused, aDrawNow);
+ if (isFocused)
+ {
+ UpdateItemHeight();
+ }
+ }
+ HandleFocusChanged(aDrawNow);
+}
+
+CCoeControl& CSwtTree::CoeControl()
+{
+ return *this;
+}
+
+const CCoeControl& CSwtTree::CoeControl() const
+{
+ return *this;
+}
+
+// Needed for finding the skin background
+TTypeUid::Ptr CSwtTree::MopSupplyObject(TTypeUid aId)
+{
+ TTypeUid::Ptr id = ASwtControlBase::SwtMopSupplyObject(aId);
+
+ if (id.Pointer() == NULL)
+ {
+ return CAknControl::MopSupplyObject(aId);
+ }
+ else
+ {
+ return id;
+ }
+}
+
+TBool CSwtTree::IsFocusable(TInt aReason /*=KSwtFocusByApi*/) const
+{
+ // Bypass CSwtComposite's focusability behavior.
+ return ASwtScrollableBase::IsFocusable(aReason);
+}
+
+TInt CSwtTree::FocusBackgroundPolicy() const
+{
+ // Bypass CSwtComposite's focus background.
+ return ASwtControlBase::FocusBackgroundPolicy();
+};
+
+void CSwtTree::ProcessKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
+{
+ ASSERT(iTree);
+ iTree->OfferKeyEventL(aKeyEvent, aType);
+}
+
+TBool CSwtTree::IsKeyUsed(TUint aKeyCode) const
+{
+ if (aKeyCode == EKeyBackspace)
+ {
+ return EFalse;
+ }
+ else if (aKeyCode == EKeyOK || aKeyCode == EKeyEnter)
+ {
+ if (!IsMarkable())
+ {
+ MSwtCommandArranger* commandArranger = iDisplay.CommandArranger();
+ if (commandArranger)
+ {
+ if (commandArranger->IsContextSensitiveOperationSet())
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+ else
+ {
+ return ETrue;
+ }
+}
+
+TSize CSwtTree::ComputeSizeL(TInt aWHint, TInt aHHint)
+{
+ if (!iTree)
+ {
+ return TSize(0, 0);
+ }
+
+ TSize res(aWHint, aHHint);
+
+ TInt count = iTree->ChildCount(KAknTreeIIDRoot);
+
+ if (aWHint == KSwtDefault)
+ {
+ TRect mainRect(TRect::EUninitialized);
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainRect);
+ TAknLayoutRect layoutRect = ItemLayoutRect();
+ TRect rect = layoutRect.Rect();
+ TInt vPadding = mainRect.Height() - rect.Height();
+ TInt scrollBarAndTrimWidth = Max(0, mainRect.Width() - rect.Width());
+ TAknLayoutText txtLayoutRect = CSwtLafFacade::GetLayoutText(CSwtLafFacade::EListSingle2HeadingMsgPaneT1,
+ rect, IsMarkable() ? 3 : 2);
+ TInt txtRightPadding = Max(0, rect.iBr.iX - txtLayoutRect.TextRect().iBr.iX);
+ TInt txtLeftPadding = Max(0, txtLayoutRect.TextRect().iTl.iX);
+ TInt markIconWidth(0);
+ if (IsMarkable())
+ {
+ markIconWidth = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG2,
+ txtLayoutRect.TextRect(), 1).Rect().Width();
+ }
+
+ res.iWidth = 0;
+ const CFont* font = txtLayoutRect.Font();
+ if (font)
+ {
+ for (TInt i = 0; i < count; i++)
+ {
+ res.iWidth = Max(res.iWidth, font->TextWidthInPixels(iTree->Text(iTree->Child(KAknTreeIIDRoot, i))));
+ }
+ }
+
+ res.iWidth += txtLeftPadding;
+ res.iWidth += txtRightPadding;
+ res.iWidth += scrollBarAndTrimWidth;
+ res.iWidth += markIconWidth;
+ res.iWidth += GetBorderWidth() * 2;
+ }
+
+ if (aHHint == KSwtDefault)
+ {
+ if (count == 0)
+ {
+ count = 1; // empty tree
+ }
+ res.iHeight = count * ItemHeight();
+ res.iHeight += GetBorderWidth() * 2;
+ }
+
+ return res;
+}
+
+void CSwtTree::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+{
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+ //Native control used for tree doesn't have flag for MULTI, so
+ //given feedback is normal list feedback.
+ //When tree is MULTI, we should give checkbox feedback on touch down.
+ //So first we disable feedback for native side and do our
+ //checkbox feedback. Then feedback for native side is restored.
+ MTouchFeedback* feedback = NULL;
+ if (aPointerEvent.iType == TPointerEvent::EButton1Up)
+ {
+ TUint32 flags = iTree->Flags();
+ if ((flags & KAknTreeListMarkable) &&
+ iTree->IsLeaf(iTree->FocusedItem()))
+ {
+ feedback = MTouchFeedback::Instance();
+ if (feedback)
+ {
+ feedback->EnableFeedbackForControl(iTree, EFalse);
+ feedback->InstantFeedback(ETouchFeedbackCheckbox);
+ }
+ }
+ }
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+
+ iLastFocusedItem = iTree->FocusedItem();
+ CSwtComposite::HandlePointerEventL(aPointerEvent);
+
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+ if (feedback)
+ {
+ //Restore native feedback.
+ feedback->EnableFeedbackForControl(iTree, ETrue);
+ }
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+}
+
+MSwtComposite* CSwtTree::Composite()
+{
+ return this;
+}
+
+TInt CSwtTree::AddL(TInt aItemHandle)
+{
+ ASSERT(iTree);
+ TInt flags = CAknSingleColumnStyleTreeList::EPersistent;
+ if (aItemHandle < KAknTreeIIDRoot)
+ {
+ aItemHandle = KAknTreeIIDRoot;
+ }
+
+ TInt id = iTree->AddSubtitleRowL(aItemHandle, KNullDesC, flags, ETrue);
+
+ // Ids of the children items are inserted after the id of the parent.
+ // This is to facilitate 'insert with sort' mechanism.
+ TBool parentFound = EFalse;
+ if (aItemHandle != KAknTreeIIDRoot)
+ {
+ TInt index = iItems.Find(aItemHandle);
+ if (index != KErrNotFound)
+ {
+ // Always at least +1 since item already added
+ index += iTree->ChildCount(aItemHandle);
+ User::LeaveIfError(iItems.Insert(id, index));
+ parentFound = ETrue;
+ }
+ }
+
+ if (!parentFound)
+ {
+ User::LeaveIfError(iItems.Append(id));
+ }
+
+ return id;
+}
+
+TRect CSwtTree::Bounds(TInt aItemHandle) const
+{
+ ASSERT(iTree);
+ TRect rect(0, 0, 0, 0);
+ TInt posInScreen = iTree->VisibleItemIndex(aItemHandle);
+ if (posInScreen >= 0)
+ {
+ TInt itemHeight = ItemHeight();
+ rect.iTl.iY = itemHeight * posInScreen;
+ rect.SetWidth(iTree->Rect().Width());
+ rect.SetHeight(itemHeight);
+ }
+ return rect;
+}
+
+void CSwtTree::Check(TInt aItemHandle, TBool aState)
+{
+ ASSERT(iTree);
+ iTree->SetMarked(aItemHandle, aState, ETrue);
+}
+
+void CSwtTree::Collapse(TInt aItemHandle)
+{
+ ASSERT(iTree);
+ if (iTree->ChildCount(aItemHandle) > 0)
+ {
+ iTree->CollapseNode(aItemHandle, ETrue);
+ }
+}
+
+void CSwtTree::Expand(TInt aItemHandle)
+{
+ ASSERT(iTree);
+ if (iTree->ChildCount(aItemHandle) > 0)
+ {
+ iTree->ExpandNode(aItemHandle, ETrue);
+ }
+}
+
+TInt CSwtTree::InsertL(TInt aItemHandle, TInt aIndex)
+{
+ ASSERT(iTree);
+ TInt flags = CAknSingleColumnStyleTreeList::EPersistent;
+ if (aItemHandle < KAknTreeIIDRoot)
+ {
+ aItemHandle = KAknTreeIIDRoot;
+ }
+
+ TInt id = iTree->AddSubtitleRowL(aItemHandle, KNullDesC, flags, EFalse);
+
+ // Insert id in the list ordered item id array
+ if (KAknTreeIIDRoot == aItemHandle)
+ {
+ // Root item ids are inserted before the id position of aIndex sibbling
+ TInt sibbling = iTree->Child(KAknTreeIIDRoot, aIndex);
+ TInt index = iItems.Find(sibbling);
+ if (index != KErrNotFound)
+ {
+ // Insert at sibbling's position
+ ASSERT(index <= iItems.Count());
+ User::LeaveIfError(iItems.Insert(id, index));
+ iTree->Sort(this, ETrue);
+ }
+ else
+ {
+ // Insertion failure, just append the item id and pray
+ User::LeaveIfError(iItems.Append(id));
+ }
+ }
+ else
+ {
+ // Ids of the children items are inserted after the id of the parent.
+ TInt index = iItems.Find(aItemHandle);
+ if (index != KErrNotFound)
+ {
+ index++; // first position after parent
+ index += aIndex;
+ ASSERT(index <= iItems.Count());
+ User::LeaveIfError(iItems.Insert(id, index));
+ iTree->Sort(this, ETrue);
+ }
+ else
+ {
+ // Insertion failure, just append the item id and pray
+ User::LeaveIfError(iItems.Append(id));
+ }
+ }
+
+ return id;
+}
+
+TBool CSwtTree::IsExpanded(TInt aItemHandle) const
+{
+ ASSERT(iTree);
+ if (iTree->ChildCount(aItemHandle) == 0)
+ {
+ return EFalse;
+ }
+ else
+ {
+ return iTree->IsExpanded(aItemHandle);
+ }
+}
+
+TBool CSwtTree::IsSelected(TInt aItemHandle) const
+{
+ ASSERT(iTree);
+ return iTree->IsMarked(aItemHandle); // selected or checked
+}
+
+TInt CSwtTree::ItemAt(TInt aX, TInt aY) const
+{
+ TInt res = KErrNotFound;
+ TRect rect = iTree->Rect();
+
+ TPoint point(aX, aY);
+ if (rect.Contains(point))
+ {
+ ASSERT(iTree);
+ TInt count = iItems.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ TInt id = iItems[i];
+ if (Bounds(id).Contains(point))
+ {
+ return id;
+ }
+ }
+ }
+
+ return res;
+}
+
+TInt CSwtTree::ItemHeight() const
+{
+ const_cast<CSwtTree*>(this)->UpdateItemHeight();
+ return iItemHeight;
+}
+
+void CSwtTree::Remove(TInt aItemHandle)
+{
+ ASSERT(iTree);
+
+ // Must remove the item ids before removing the actual items.
+ RemoveItemRefs(aItemHandle);
+
+ // All children will automatically be removed too.
+ iTree->RemoveItem(aItemHandle, ETrue);
+}
+
+void CSwtTree::RemoveAll()
+{
+ ASSERT(iTree);
+ iItems.Reset();
+ iTree->RemoveItem(KAknTreeIIDRoot, ETrue);
+}
+
+void CSwtTree::Select(const TInt* aItemHandles, TInt aCount, TBool aState)
+{
+ ASSERT(iTree);
+ if (iStyle & KSwtStyleMulti)
+ {
+ for (TInt i = 0; i < aCount; i++)
+ {
+ iTree->SetMarked(aItemHandles[i], aState, ETrue);
+ }
+ }
+ else
+ {
+ if (aState && aCount > 0)
+ {
+ iTree->SetFocusedItem(aItemHandles[0]);
+ }
+ }
+}
+
+void CSwtTree::SelectAll(TBool aState)
+{
+ ASSERT(iTree);
+ iTree->SetMarked(KAknTreeIIDRoot, aState, ETrue);
+}
+
+TInt CSwtTree::SelectionCount() const
+{
+ const CArrayFix<TInt>* arr = NULL;
+ TRAP_IGNORE(arr = SelectionL());
+ TInt res(0);
+ if (arr)
+ {
+ res = arr->Count();
+ }
+ delete arr;
+ return res;
+}
+
+const CArrayFix<TInt>* CSwtTree::SelectionL() const
+{
+ ASSERT(iTree);
+ CArrayFix<TInt>* res = NULL;
+ if (iStyle & KSwtStyleMulti)
+ {
+ RArray<TInt> arr;
+ CleanupClosePushL(arr);
+ iTree->GetMarkedItemsL(arr);
+ TInt count = arr.Count();
+ if (count > 0)
+ {
+ res = new(ELeave) CArrayFixFlat<TInt>(count);
+ CleanupStack::PushL(res);
+ for (TInt i = 0; i < count; i++)
+ {
+ res->AppendL(arr[i]);
+ }
+ CleanupStack::Pop(res);
+ }
+ CleanupStack::PopAndDestroy(&arr);
+ }
+ else
+ {
+ TInt item = iTree->FocusedItem();
+ if (item != KAknTreeIIDNone)
+ {
+ res = new(ELeave) CArrayFixFlat<TInt>(1);
+ CleanupStack::PushL(res);
+ res->AppendL(item);
+ CleanupStack::Pop(res);
+ }
+ }
+ return res;
+}
+
+// CSwtLafFacade::EListSingle2HeadingMsgPaneG1 could be used to implement downscaling
+void CSwtTree::SetImageL(TInt aItemHandle, const MSwtImage* aImage)
+{
+ ASSERT(iTree);
+ if (aImage)
+ {
+ TInt id = KErrNotFound;
+ TInt index = iImages.Find(aImage);
+ if (index != KErrNotFound)
+ {
+ // Image already used by other items, increase local ref count
+ id = iImageIds[index];
+ iImageRefs[index]++;
+ }
+ else
+ {
+ // best suitable size from layouts.
+ TSize layoutImgSize = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG1,
+ ItemLayoutRect().Rect(), 4).Rect().Size();
+ // best image size we can make to fit in the above layout size.
+ TSize bitmapSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
+ aImage->Bitmap().SizeInPixels(), layoutImgSize);
+
+ // Register image with CAknTree, increase MSwtImage ref count, store the new id for later use
+ const CFbsBitmap& bmp = aImage->SubBitmap(bitmapSize);
+ const CFbsBitmap* mask = aImage->SubMaskBitmap(bitmapSize, ETrue);
+ aImage->AddSubRef(bitmapSize);
+ iImageMaxSize = bitmapSize;
+ if (!mask)
+ {
+ mask = iMaskHandler->GetMask(bmp.SizeInPixels());
+ }
+ id = iTree->AddIconL(const_cast<CFbsBitmap*>(&bmp), const_cast<CFbsBitmap*>(mask),
+ EFalse, EAspectRatioPreserved);
+ aImage->AddRef();
+ User::LeaveIfError(iImages.Append(aImage));
+ User::LeaveIfError(iImageIds.Append(id));
+ User::LeaveIfError(iImageRefs.Append(1));
+ }
+
+ if (id != KErrNotFound)
+ {
+ // Set item custom image id
+ iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::ECollapsedNode, id, ETrue);
+ iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode, id, ETrue);
+ }
+ }
+ else
+ {
+ TInt id = iTree->Icon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode);
+ if (id != KErrNotFound)
+ {
+ // Set default image id to item
+ iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode,
+ AknTreeListIconID::KDefault, ETrue);
+ iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::ECollapsedNode,
+ AknTreeListIconID::KDefault, ETrue);
+ TInt index = iImageIds.Find(id);
+ if (index != KErrNotFound)
+ {
+ // Decrease local ref
+ iImageRefs[index]--;
+ if (iImageRefs[index] == 0)
+ {
+ // No items are using the image, deregister it and decrease the MSwtImage ref count
+ iTree->RemoveIconL(id);
+ const MSwtImage* image = iImages[index];
+ TSize imageSize = image->Bitmap().SizeInPixels();
+ if (imageSize.iHeight > iImageMaxSize.iHeight ||
+ imageSize.iWidth > iImageMaxSize.iWidth)
+ {
+ imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
+ imageSize, iImageMaxSize);
+ }
+ image->RemoveSubRef(imageSize);
+ image->RemoveRef();
+ iImages.Remove(index);
+ iImageIds.Remove(index);
+ iImageRefs.Remove(index);
+ iImages.Compress();
+ iImageIds.Compress();
+ iImageRefs.Compress();
+ }
+ }
+ }
+ }
+}
+
+void CSwtTree::SetTextL(TInt aItemHandle, const TDesC& aText)
+{
+ ASSERT(iTree);
+ iTree->SetTextL(aItemHandle, aText, ETrue);
+}
+
+TInt CSwtTree::TopItem() const
+{
+ ASSERT(iTree);
+ TInt count = iItems.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ TInt id = iItems[i];
+ if (iTree->VisibleItemIndex(id) == 0)
+ {
+ return id;
+ }
+ }
+ return KErrNotFound;
+}
+
+TInt CSwtTree::HandleTreeListEvent(CAknTreeList& aList, TAknTreeItemID aItem,
+ MAknTreeListObserver::TEvent aEvent)
+{
+ if (&aList != iTree)
+ {
+ return KErrNone;
+ }
+
+ // EItemSelected is never sent for nodes, hence the manual marking
+ switch (aEvent)
+ {
+ case MAknTreeListObserver::ENodeExpanded:
+ {
+ TInt count = iTree->ChildCount(aItem);
+ if (count > 0)
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventExpand, aItem));
+ }
+ if (IsMarkable())
+ {
+ if (count == 0)
+ {
+ iTree->SetMarked(aItem, ETrue, ETrue);
+ }
+ }
+ else
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventDefaultSelection, aItem));
+ }
+ break;
+ }
+ case MAknTreeListObserver::ENodeCollapsed:
+ {
+ TInt count = iTree->ChildCount(aItem);
+ if (count > 0)
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventCollapse, aItem));
+ }
+ if (IsMarkable())
+ {
+ if (count == 0)
+ {
+ iTree->SetMarked(aItem, EFalse, ETrue);
+ }
+ }
+ break;
+ }
+ case MAknTreeListObserver::EItemFocused:
+ {
+ if (iStyle & KSwtStyleSingle)
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
+ }
+ break;
+ }
+ case MAknTreeListObserver::EItemMarked:
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
+ break;
+ }
+ case MAknTreeListObserver::EItemUnmarked:
+ {
+ TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
+ break;
+ }
+#ifdef RD_JAVA_S60_RELEASE_9_2
+ case MAknTreeListObserver::EEventPanningStarted:
+ GetShell().SetUrgentPaintControl(this);
+ break;
+ case MAknTreeListObserver::EEventFlickStopped:
+ GetShell().SetUrgentPaintControl(NULL);
+ break;
+#endif // RD_JAVA_S60_RELEASE_9_2
+ default:
+ break;
+ }
+
+ return KErrNone;
+}
+
+TInt CSwtTree::Compare(TAknTreeItemID aFirst, TAknTreeItemID aSecond)
+{
+ TInt firstPos = iItems.Find(aFirst);
+ TInt secondPos = iItems.Find(aSecond);
+ if (firstPos < secondPos)
+ {
+ return -1;
+ }
+ else
+ {
+ return +1;
+ }
+}
+
+void CSwtTree::UpdateItemHeight()
+{
+ if (iItemHeightValid)
+ {
+ return;
+ }
+
+ ASSERT(iTree);
+ TRect rect = iTree->HighlightRect();
+ if (!rect.IsEmpty())
+ {
+ iItemHeightValid = ETrue;
+ iItemHeight = rect.Height();
+ return;
+ }
+
+ // LAF as last resort, might be a few pixels inaccurate.
+ iItemHeightValid = EFalse;
+ iItemHeight = ItemLayoutRect().Rect().Height();
+}
+
+TAknLayoutRect CSwtTree::ItemLayoutRect()
+{
+ TRect mainRect(TRect::EUninitialized);
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainRect);
+ TAknLayoutRect layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListScrollGenPane, mainRect, 0);
+ layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListGenPane, layoutRect.Rect(), 0);
+ layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingleGraphicH1Pane, layoutRect.Rect(), 0);
+ return layoutRect;
+}
+
+void CSwtTree::UpdateImagesSize()
+{
+ TSize imageNewSize = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG1,
+ ItemLayoutRect().Rect(), 4).Rect().Size();
+
+ if (imageNewSize != iImageMaxSize && iImages.Count() > 0)
+ {
+ TInt count = iItems.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ TInt itemHandle = iItems[i];
+ if (itemHandle)
+ {
+ // getting icon id from itemHandle.
+ TInt id = iTree->Icon(itemHandle, CAknSingleColumnStyleTreeList::EExpandedNode);
+ if (id != KErrNotFound)
+ {
+ // image index from icon id.
+ TInt index = iImageIds.Find(id);
+ const MSwtImage* image = iImages[index];
+ TSize imageSize = image->Bitmap().SizeInPixels();
+
+ TSize oldSize;
+ TBool doScaling = ETrue;
+
+ if (imageSize.iHeight > iImageMaxSize.iHeight ||
+ imageSize.iWidth > iImageMaxSize.iWidth)
+ {
+ // If image size is bigger than the old maximum size, then
+ // the image has been also previously scaled.
+ oldSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
+ imageSize, iImageMaxSize);
+ }
+ else if (imageSize.iHeight > imageNewSize.iHeight ||
+ imageSize.iWidth > imageNewSize.iWidth)
+ {
+ // Image is bigger than the new boundaries, but it did fit
+ // inside the old boundaries, so the image is default size.
+ oldSize = imageSize;
+ }
+ else
+ {
+ doScaling = EFalse;
+ }
+
+ if (doScaling)
+ {
+
+ // best image size to fit in the tree item.
+ imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
+ imageSize, imageNewSize);
+ // scaling down the bitmap and mask.
+ const CFbsBitmap& bmp = image->SubBitmap(imageSize);
+ const CFbsBitmap* mask = image->SubMaskBitmap(imageSize, ETrue);
+
+ if (!mask)
+ {
+ mask = iMaskHandler->GetMask(bmp.SizeInPixels());
+ }
+ // replacing the old icon with new icon.
+ TRAP_IGNORE(iTree->AssignIconL(id, const_cast<CFbsBitmap*>(&bmp) ,
+ const_cast<CFbsBitmap*>(mask), EFalse, EAspectRatioPreserved));
+
+ image->AddSubRef(imageSize);
+ image->RemoveSubRef(oldSize);
+
+ }
+ }
+ }
+ }
+ iImageMaxSize = imageNewSize;
+ }
+}
+
+
+TInt CSwtTree::LastCollapsedItem()
+{
+ TInt count = iItems.Count();
+ if (count == 0)
+ {
+ return KErrNotFound;
+ }
+ TInt i;
+ for (i = count - 1; i >= 0; i--)
+ {
+ TInt parentId = iTree->Parent(iItems[i]);
+ if (parentId == KAknTreeIIDRoot)
+ {
+ break;
+ }
+ if (iTree->IsExpanded(parentId))
+ {
+ break;
+ }
+ }
+ return iItems[i];
+}
+
+void CSwtTree::RemoveItemRefs(TInt aItemHandle)
+{
+ TInt index = iItems.Find(aItemHandle);
+ if (index != KErrNotFound)
+ {
+ iItems.Remove(index);
+ }
+ TInt count = iTree->ChildCount(aItemHandle);
+ for (int i = 0; i < count; i++)
+ {
+ RemoveItemRefs(iTree->Child(aItemHandle, i));
+ }
+}
+
+TBool CSwtTree::IsMarkable() const
+{
+ // Natively, multi selection covers also the check style.
+ // Java is responsible to not overselect in SINGLE & CHECK.
+ return (iStyle & KSwtStyleMulti) || (iStyle & KSwtStyleCheck);
+}
+
+#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
+void CSwtTree::DoControlSpecificFeedback(
+ const TBool& aFirstTap,
+ const TBool& aTappedToChildRect,
+ const TPointerEvent& aPointerEvent) const
+{
+ MTouchFeedback* feedback = MTouchFeedback::Instance();
+ if (feedback && !aTappedToChildRect)
+ {
+ switch (aPointerEvent.iType)
+ {
+ case TPointerEvent::EButton1Down:
+ if (aFirstTap)
+ {
+ feedback->InstantFeedback(ETouchFeedbackSensitiveList);
+ }
+ break;
+ }
+ }
+}
+#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK