diff -r f5050f1da672 -r 04becd199f91 javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swttree.cpp --- /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 +#include +#include +#include +#include +#include +#include "eswtmobileextensions.h" +#include "swtfont.h" +#include "swttree.h" +#include "swtcontrolhelper.h" + +#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK +#include +#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(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* arr = NULL; + TRAP_IGNORE(arr = SelectionL()); + TInt res(0); + if (arr) + { + res = arr->Count(); + } + delete arr; + return res; +} + +const CArrayFix* CSwtTree::SelectionL() const +{ + ASSERT(iTree); + CArrayFix* res = NULL; + if (iStyle & KSwtStyleMulti) + { + RArray arr; + CleanupClosePushL(arr); + iTree->GetMarkedItemsL(arr); + TInt count = arr.Count(); + if (count > 0) + { + res = new(ELeave) CArrayFixFlat(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(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(&bmp), const_cast(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(&bmp) , + const_cast(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