javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swttree.cpp
branchRCL_3
changeset 14 04becd199f91
child 19 71c436fe3ce0
equal deleted inserted replaced
13:f5050f1da672 14:04becd199f91
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2005, 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     Nokia Corporation - S60 implementation
       
    10  *******************************************************************************/
       
    11 
       
    12 
       
    13 #include <aknsinglecolumnstyletreelist.h>
       
    14 #include <AknsDrawUtils.h>
       
    15 #include <AknUtils.h>
       
    16 #include <avkon.mbg>
       
    17 #include <barsread.h>
       
    18 #include <swtlaffacade.h>
       
    19 #include "eswtmobileextensions.h"
       
    20 #include "swtfont.h"
       
    21 #include "swttree.h"
       
    22 #include "swtcontrolhelper.h"
       
    23 
       
    24 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    25 #include <touchfeedback.h>
       
    26 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    27 
       
    28 // ======== MEMBER FUNCTIONS ========
       
    29 
       
    30 
       
    31 CSwtTree* CSwtTree::NewL(MSwtDisplay& aDisplay, TSwtPeer aPeer,
       
    32                          MSwtComposite& aParent, TInt aStyle)
       
    33 {
       
    34     CCoeControl& parentCtrl = aParent.Control()->CoeControl();
       
    35     CSwtTree* self = new(ELeave) CSwtTree(aDisplay, aPeer, aParent, aStyle,
       
    36                                           parentCtrl.IsVisible(), parentCtrl.IsDimmed());
       
    37     CleanupStack::PushL(self);
       
    38     self->ConstructL();
       
    39     self->InitControlBaseL();
       
    40     CleanupStack::Pop(self);
       
    41     return self;
       
    42 }
       
    43 
       
    44 CSwtTree::CSwtTree(MSwtDisplay& aDisplay, TSwtPeer aPeer,
       
    45                    MSwtComposite& aParent, TInt aStyle, TBool aVisibility, TBool aDimmed)
       
    46         : CSwtComposite(aDisplay, aPeer, &aParent, aStyle, aVisibility, aDimmed)
       
    47         , iItemHeightValid(EFalse)
       
    48 {
       
    49 }
       
    50 
       
    51 void CSwtTree::ConstructL()
       
    52 {
       
    53     CCoeControl& coeParent = iParent->Control()->CoeControl();
       
    54     SetContainerWindowL(coeParent);
       
    55     SetComponentsToInheritVisibility(ETrue);
       
    56     CCoeControl::MakeVisible(coeParent.IsVisible());
       
    57     CCoeControl::SetDimmed(coeParent.IsDimmed());
       
    58 
       
    59     iTree = CAknSingleColumnStyleTreeList::NewL(*this);
       
    60     TInt flags = KAknTreeListMarqueeScrolling;
       
    61     if (IsMarkable())
       
    62     {
       
    63         flags |= KAknTreeListMarkable;
       
    64     }
       
    65     iTree->SetFlags(flags);
       
    66     iTree->AddObserverL(this);
       
    67 
       
    68     // Eventhough container already given, we still need to do this for the skin background
       
    69     iTree->SetContainerWindowL(*this);
       
    70 
       
    71     // Give initial LAF value
       
    72     UpdateItemHeight();
       
    73 
       
    74     ActivateL();
       
    75 
       
    76     TDisplayMode displayMode(ENone);
       
    77     CEikonEnv* eikonEnv = iDisplay.CoeEnv();
       
    78     if (eikonEnv)
       
    79     {
       
    80         CWsScreenDevice* screenDevice = eikonEnv->ScreenDevice();
       
    81         if (screenDevice)
       
    82         {
       
    83             displayMode = screenDevice->DisplayMode();
       
    84         }
       
    85     }
       
    86     iMaskHandler = new CSwtMaskHandler(displayMode);
       
    87 }
       
    88 
       
    89 CSwtTree::~CSwtTree()
       
    90 {
       
    91     delete iTree;
       
    92     iItems.Close();
       
    93     delete iMaskHandler;
       
    94     TInt count = iImages.Count();
       
    95     for (TInt i = 0; i < count; i++)
       
    96     {
       
    97         TSize imageSize = iImages[i]->Bitmap().SizeInPixels();
       
    98         if (imageSize.iHeight > iImageMaxSize.iHeight ||
       
    99                 imageSize.iWidth > iImageMaxSize.iWidth)
       
   100         {
       
   101             // If image size is bigger than the old maximum size, then
       
   102             // the image has been also previously scaled.
       
   103             imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
       
   104                             imageSize, iImageMaxSize);
       
   105         }
       
   106         iImages[i]->RemoveSubRef(imageSize);
       
   107         iImages[i]->RemoveRef();
       
   108     }
       
   109     iImages.Close();
       
   110     iImageIds.Close();
       
   111     iImageRefs.Close();
       
   112 }
       
   113 
       
   114 TInt CSwtTree::CountComponentControls() const
       
   115 {
       
   116     return 1;
       
   117 }
       
   118 
       
   119 CCoeControl* CSwtTree::ComponentControl(TInt /*aIdx*/) const
       
   120 {
       
   121     return iTree;
       
   122 }
       
   123 
       
   124 void CSwtTree::HandleResourceChange(TInt aType)
       
   125 {
       
   126     if (aType == KEikDynamicLayoutVariantSwitch)
       
   127     {
       
   128         iItemHeightValid = EFalse;
       
   129         UpdateItemHeight();
       
   130     }
       
   131     CAknControl::HandleResourceChange(aType);
       
   132     UpdateImagesSize();
       
   133 }
       
   134 
       
   135 TKeyResponse CSwtTree::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
       
   136 {
       
   137     TBool traversalDoIt = ETrue;
       
   138 
       
   139     if (iItems.Count() > 0)
       
   140     {
       
   141         switch (aKeyEvent.iCode)
       
   142         {
       
   143         case EKeyEnter:
       
   144         case EKeyOK:
       
   145         {
       
   146             if (IsMarkable())
       
   147             {
       
   148                 traversalDoIt = EFalse;
       
   149             }
       
   150             break;
       
   151         }
       
   152         case EKeyUpArrow:
       
   153         {
       
   154             traversalDoIt = EFalse;
       
   155             if (iTree->FocusedItem() == iItems[0])
       
   156             {
       
   157                 if (GetShell().FindTraversalTargetL(ESwtTraverseArrowPrevious, *this))
       
   158                 {
       
   159                     traversalDoIt = ETrue;
       
   160                 }
       
   161             }
       
   162             break;
       
   163         }
       
   164         case EKeyDownArrow:
       
   165         {
       
   166             traversalDoIt = EFalse;
       
   167             if (iTree->FocusedItem() == LastCollapsedItem())
       
   168             {
       
   169                 if (GetShell().FindTraversalTargetL(ESwtTraverseArrowNext, *this))
       
   170                 {
       
   171                     traversalDoIt = ETrue;
       
   172                 }
       
   173             }
       
   174             break;
       
   175         }
       
   176         case EKeyLeftArrow:
       
   177         {
       
   178             // Left key collapses node
       
   179             TInt item = iTree->FocusedItem();
       
   180             if (item != KAknTreeIIDNone)
       
   181             {
       
   182                 traversalDoIt = EFalse;
       
   183                 if (iTree->Parent(item) == KAknTreeIIDRoot && !iTree->IsExpanded(item))
       
   184                 {
       
   185                     if (GetShell().FindTraversalTargetL(ESwtTraverseArrowPrevious, *this))
       
   186                     {
       
   187                         traversalDoIt = ETrue;
       
   188                     }
       
   189                 }
       
   190             }
       
   191             break;
       
   192         }
       
   193         case EKeyRightArrow:
       
   194         {
       
   195             // Right key expands node
       
   196             TInt item = iTree->FocusedItem();
       
   197             if (item != KAknTreeIIDNone)
       
   198             {
       
   199                 traversalDoIt = EFalse;
       
   200                 if (iTree->ChildCount(item) == 0)
       
   201                 {
       
   202                     if (GetShell().FindTraversalTargetL(ESwtTraverseArrowNext, *this))
       
   203                     {
       
   204                         traversalDoIt = ETrue;
       
   205                     }
       
   206                 }
       
   207             }
       
   208             break;
       
   209         }
       
   210         default:
       
   211             break;
       
   212         }
       
   213     }
       
   214 
       
   215     return HandleKeyL(aKeyEvent, aType, traversalDoIt);
       
   216 }
       
   217 
       
   218 void CSwtTree::SizeChanged()
       
   219 {
       
   220     if (iTree)
       
   221     {
       
   222         iTree->SetRect(BorderInnerRect());
       
   223     }
       
   224     CSwtComposite::SizeChanged();
       
   225 }
       
   226 
       
   227 void CSwtTree::PositionChanged()
       
   228 {
       
   229     if (iTree)
       
   230     {
       
   231         iTree->SetRect(BorderInnerRect());
       
   232     }
       
   233     CSwtComposite::PositionChanged();
       
   234 }
       
   235 
       
   236 void CSwtTree::FocusChanged(TDrawNow aDrawNow)
       
   237 {
       
   238     // This gets called before contained list is created.
       
   239     if (iTree)
       
   240     {
       
   241         TBool isFocused = IsFocusControl();
       
   242         iTree->SetFocus(isFocused, aDrawNow);
       
   243         if (isFocused)
       
   244         {
       
   245             UpdateItemHeight();
       
   246         }
       
   247     }
       
   248     HandleFocusChanged(aDrawNow);
       
   249 }
       
   250 
       
   251 CCoeControl& CSwtTree::CoeControl()
       
   252 {
       
   253     return *this;
       
   254 }
       
   255 
       
   256 const CCoeControl& CSwtTree::CoeControl() const
       
   257 {
       
   258     return *this;
       
   259 }
       
   260 
       
   261 // Needed for finding the skin background
       
   262 TTypeUid::Ptr CSwtTree::MopSupplyObject(TTypeUid aId)
       
   263 {
       
   264     TTypeUid::Ptr id = ASwtControlBase::SwtMopSupplyObject(aId);
       
   265 
       
   266     if (id.Pointer() == NULL)
       
   267     {
       
   268         return CAknControl::MopSupplyObject(aId);
       
   269     }
       
   270     else
       
   271     {
       
   272         return id;
       
   273     }
       
   274 }
       
   275 
       
   276 TBool CSwtTree::IsFocusable(TInt aReason /*=KSwtFocusByApi*/) const
       
   277 {
       
   278     // Bypass CSwtComposite's focusability behavior.
       
   279     return ASwtScrollableBase::IsFocusable(aReason);
       
   280 }
       
   281 
       
   282 TInt CSwtTree::FocusBackgroundPolicy() const
       
   283 {
       
   284     // Bypass CSwtComposite's focus background.
       
   285     return ASwtControlBase::FocusBackgroundPolicy();
       
   286 };
       
   287 
       
   288 void CSwtTree::ProcessKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
       
   289 {
       
   290     ASSERT(iTree);
       
   291     iTree->OfferKeyEventL(aKeyEvent, aType);
       
   292 }
       
   293 
       
   294 TBool CSwtTree::IsKeyUsed(TUint aKeyCode) const
       
   295 {
       
   296     if (aKeyCode == EKeyBackspace)
       
   297     {
       
   298         return EFalse;
       
   299     }
       
   300     else if (aKeyCode == EKeyOK || aKeyCode == EKeyEnter)
       
   301     {
       
   302         if (!IsMarkable())
       
   303         {
       
   304             MSwtCommandArranger* commandArranger = iDisplay.CommandArranger();
       
   305             if (commandArranger)
       
   306             {
       
   307                 if (commandArranger->IsContextSensitiveOperationSet())
       
   308                 {
       
   309                     return EFalse;
       
   310                 }
       
   311             }
       
   312             return ETrue;
       
   313         }
       
   314         else
       
   315         {
       
   316             return ETrue;
       
   317         }
       
   318     }
       
   319     else
       
   320     {
       
   321         return ETrue;
       
   322     }
       
   323 }
       
   324 
       
   325 TSize CSwtTree::ComputeSizeL(TInt aWHint, TInt aHHint)
       
   326 {
       
   327     if (!iTree)
       
   328     {
       
   329         return TSize(0, 0);
       
   330     }
       
   331 
       
   332     TSize res(aWHint, aHHint);
       
   333 
       
   334     TInt count = iTree->ChildCount(KAknTreeIIDRoot);
       
   335 
       
   336     if (aWHint == KSwtDefault)
       
   337     {
       
   338         TRect mainRect(TRect::EUninitialized);
       
   339         AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainRect);
       
   340         TAknLayoutRect layoutRect = ItemLayoutRect();
       
   341         TRect rect = layoutRect.Rect();
       
   342         TInt vPadding = mainRect.Height() - rect.Height();
       
   343         TInt scrollBarAndTrimWidth = Max(0, mainRect.Width() - rect.Width());
       
   344         TAknLayoutText txtLayoutRect = CSwtLafFacade::GetLayoutText(CSwtLafFacade::EListSingle2HeadingMsgPaneT1,
       
   345                                        rect, IsMarkable() ? 3 : 2);
       
   346         TInt txtRightPadding = Max(0, rect.iBr.iX - txtLayoutRect.TextRect().iBr.iX);
       
   347         TInt txtLeftPadding = Max(0, txtLayoutRect.TextRect().iTl.iX);
       
   348         TInt markIconWidth(0);
       
   349         if (IsMarkable())
       
   350         {
       
   351             markIconWidth = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG2,
       
   352                             txtLayoutRect.TextRect(), 1).Rect().Width();
       
   353         }
       
   354 
       
   355         res.iWidth = 0;
       
   356         const CFont* font = txtLayoutRect.Font();
       
   357         if (font)
       
   358         {
       
   359             for (TInt i = 0; i < count; i++)
       
   360             {
       
   361                 res.iWidth = Max(res.iWidth, font->TextWidthInPixels(iTree->Text(iTree->Child(KAknTreeIIDRoot, i))));
       
   362             }
       
   363         }
       
   364 
       
   365         res.iWidth += txtLeftPadding;
       
   366         res.iWidth += txtRightPadding;
       
   367         res.iWidth += scrollBarAndTrimWidth;
       
   368         res.iWidth += markIconWidth;
       
   369         res.iWidth += GetBorderWidth() * 2;
       
   370     }
       
   371 
       
   372     if (aHHint == KSwtDefault)
       
   373     {
       
   374         if (count == 0)
       
   375         {
       
   376             count = 1; // empty tree
       
   377         }
       
   378         res.iHeight = count * ItemHeight();
       
   379         res.iHeight += GetBorderWidth() * 2;
       
   380     }
       
   381 
       
   382     return res;
       
   383 }
       
   384 
       
   385 void CSwtTree::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   386 {
       
   387 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   388     //Native control used for tree doesn't have flag for MULTI, so
       
   389     //given feedback is normal list feedback.
       
   390     //When tree is MULTI, we should give checkbox feedback on touch down.
       
   391     //So first we disable feedback for native side and do our
       
   392     //checkbox feedback. Then feedback for native side is restored.
       
   393     MTouchFeedback* feedback = NULL;
       
   394     if (aPointerEvent.iType == TPointerEvent::EButton1Up)
       
   395     {
       
   396         TUint32 flags = iTree->Flags();
       
   397         if ((flags & KAknTreeListMarkable) &&
       
   398                 iTree->IsLeaf(iTree->FocusedItem()))
       
   399         {
       
   400             feedback = MTouchFeedback::Instance();
       
   401             if (feedback)
       
   402             {
       
   403                 feedback->EnableFeedbackForControl(iTree, EFalse);
       
   404                 feedback->InstantFeedback(ETouchFeedbackCheckbox);
       
   405             }
       
   406         }
       
   407     }
       
   408 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   409 
       
   410     iLastFocusedItem = iTree->FocusedItem();
       
   411     CSwtComposite::HandlePointerEventL(aPointerEvent);
       
   412 
       
   413 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   414     if (feedback)
       
   415     {
       
   416         //Restore native feedback.
       
   417         feedback->EnableFeedbackForControl(iTree, ETrue);
       
   418     }
       
   419 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   420 }
       
   421 
       
   422 MSwtComposite* CSwtTree::Composite()
       
   423 {
       
   424     return this;
       
   425 }
       
   426 
       
   427 TInt CSwtTree::AddL(TInt aItemHandle)
       
   428 {
       
   429     ASSERT(iTree);
       
   430     TInt flags = CAknSingleColumnStyleTreeList::EPersistent;
       
   431     if (aItemHandle < KAknTreeIIDRoot)
       
   432     {
       
   433         aItemHandle = KAknTreeIIDRoot;
       
   434     }
       
   435 
       
   436     TInt id = iTree->AddSubtitleRowL(aItemHandle, KNullDesC, flags, ETrue);
       
   437 
       
   438     // Ids of the children items are inserted after the id of the parent.
       
   439     // This is to facilitate 'insert with sort' mechanism.
       
   440     TBool parentFound = EFalse;
       
   441     if (aItemHandle != KAknTreeIIDRoot)
       
   442     {
       
   443         TInt index = iItems.Find(aItemHandle);
       
   444         if (index != KErrNotFound)
       
   445         {
       
   446             // Always at least +1 since item already added
       
   447             index += iTree->ChildCount(aItemHandle);
       
   448             User::LeaveIfError(iItems.Insert(id, index));
       
   449             parentFound = ETrue;
       
   450         }
       
   451     }
       
   452 
       
   453     if (!parentFound)
       
   454     {
       
   455         User::LeaveIfError(iItems.Append(id));
       
   456     }
       
   457 
       
   458     return id;
       
   459 }
       
   460 
       
   461 TRect CSwtTree::Bounds(TInt aItemHandle) const
       
   462 {
       
   463     ASSERT(iTree);
       
   464     TRect rect(0, 0, 0, 0);
       
   465     TInt posInScreen = iTree->VisibleItemIndex(aItemHandle);
       
   466     if (posInScreen >= 0)
       
   467     {
       
   468         TInt itemHeight = ItemHeight();
       
   469         rect.iTl.iY = itemHeight * posInScreen;
       
   470         rect.SetWidth(iTree->Rect().Width());
       
   471         rect.SetHeight(itemHeight);
       
   472     }
       
   473     return rect;
       
   474 }
       
   475 
       
   476 void CSwtTree::Check(TInt aItemHandle, TBool aState)
       
   477 {
       
   478     ASSERT(iTree);
       
   479     iTree->SetMarked(aItemHandle, aState, ETrue);
       
   480 }
       
   481 
       
   482 void CSwtTree::Collapse(TInt aItemHandle)
       
   483 {
       
   484     ASSERT(iTree);
       
   485     if (iTree->ChildCount(aItemHandle) > 0)
       
   486     {
       
   487         iTree->CollapseNode(aItemHandle, ETrue);
       
   488     }
       
   489 }
       
   490 
       
   491 void CSwtTree::Expand(TInt aItemHandle)
       
   492 {
       
   493     ASSERT(iTree);
       
   494     if (iTree->ChildCount(aItemHandle) > 0)
       
   495     {
       
   496         iTree->ExpandNode(aItemHandle, ETrue);
       
   497     }
       
   498 }
       
   499 
       
   500 TInt CSwtTree::InsertL(TInt aItemHandle, TInt aIndex)
       
   501 {
       
   502     ASSERT(iTree);
       
   503     TInt flags = CAknSingleColumnStyleTreeList::EPersistent;
       
   504     if (aItemHandle < KAknTreeIIDRoot)
       
   505     {
       
   506         aItemHandle = KAknTreeIIDRoot;
       
   507     }
       
   508 
       
   509     TInt id = iTree->AddSubtitleRowL(aItemHandle, KNullDesC, flags, EFalse);
       
   510 
       
   511     // Insert id in the list ordered item id array
       
   512     if (KAknTreeIIDRoot == aItemHandle)
       
   513     {
       
   514         // Root item ids are inserted before the id position of aIndex sibbling
       
   515         TInt sibbling = iTree->Child(KAknTreeIIDRoot, aIndex);
       
   516         TInt index = iItems.Find(sibbling);
       
   517         if (index != KErrNotFound)
       
   518         {
       
   519             // Insert at sibbling's position
       
   520             ASSERT(index <= iItems.Count());
       
   521             User::LeaveIfError(iItems.Insert(id, index));
       
   522             iTree->Sort(this, ETrue);
       
   523         }
       
   524         else
       
   525         {
       
   526             // Insertion failure, just append the item id and pray
       
   527             User::LeaveIfError(iItems.Append(id));
       
   528         }
       
   529     }
       
   530     else
       
   531     {
       
   532         // Ids of the children items are inserted after the id of the parent.
       
   533         TInt index = iItems.Find(aItemHandle);
       
   534         if (index != KErrNotFound)
       
   535         {
       
   536             index++; // first position after parent
       
   537             index += aIndex;
       
   538             ASSERT(index <= iItems.Count());
       
   539             User::LeaveIfError(iItems.Insert(id, index));
       
   540             iTree->Sort(this, ETrue);
       
   541         }
       
   542         else
       
   543         {
       
   544             // Insertion failure, just append the item id and pray
       
   545             User::LeaveIfError(iItems.Append(id));
       
   546         }
       
   547     }
       
   548 
       
   549     return id;
       
   550 }
       
   551 
       
   552 TBool CSwtTree::IsExpanded(TInt aItemHandle) const
       
   553 {
       
   554     ASSERT(iTree);
       
   555     if (iTree->ChildCount(aItemHandle) == 0)
       
   556     {
       
   557         return EFalse;
       
   558     }
       
   559     else
       
   560     {
       
   561         return iTree->IsExpanded(aItemHandle);
       
   562     }
       
   563 }
       
   564 
       
   565 TBool CSwtTree::IsSelected(TInt aItemHandle) const
       
   566 {
       
   567     ASSERT(iTree);
       
   568     return iTree->IsMarked(aItemHandle);   // selected or checked
       
   569 }
       
   570 
       
   571 TInt CSwtTree::ItemAt(TInt aX, TInt aY) const
       
   572 {
       
   573     TInt res = KErrNotFound;
       
   574     TRect rect = iTree->Rect();
       
   575 
       
   576     TPoint point(aX, aY);
       
   577     if (rect.Contains(point))
       
   578     {
       
   579         ASSERT(iTree);
       
   580         TInt count = iItems.Count();
       
   581         for (TInt i = 0; i < count; i++)
       
   582         {
       
   583             TInt id = iItems[i];
       
   584             if (Bounds(id).Contains(point))
       
   585             {
       
   586                 return id;
       
   587             }
       
   588         }
       
   589     }
       
   590 
       
   591     return res;
       
   592 }
       
   593 
       
   594 TInt CSwtTree::ItemHeight() const
       
   595 {
       
   596     const_cast<CSwtTree*>(this)->UpdateItemHeight();
       
   597     return iItemHeight;
       
   598 }
       
   599 
       
   600 void CSwtTree::Remove(TInt aItemHandle)
       
   601 {
       
   602     ASSERT(iTree);
       
   603 
       
   604     // Must remove the item ids before removing the actual items.
       
   605     RemoveItemRefs(aItemHandle);
       
   606 
       
   607     // All children will automatically be removed too.
       
   608     iTree->RemoveItem(aItemHandle, ETrue);
       
   609 }
       
   610 
       
   611 void CSwtTree::RemoveAll()
       
   612 {
       
   613     ASSERT(iTree);
       
   614     iItems.Reset();
       
   615     iTree->RemoveItem(KAknTreeIIDRoot, ETrue);
       
   616 }
       
   617 
       
   618 void CSwtTree::Select(const TInt* aItemHandles, TInt aCount, TBool aState)
       
   619 {
       
   620     ASSERT(iTree);
       
   621     if (iStyle & KSwtStyleMulti)
       
   622     {
       
   623         for (TInt i = 0; i < aCount; i++)
       
   624         {
       
   625             iTree->SetMarked(aItemHandles[i], aState, ETrue);
       
   626         }
       
   627     }
       
   628     else
       
   629     {
       
   630         if (aState && aCount > 0)
       
   631         {
       
   632             iTree->SetFocusedItem(aItemHandles[0]);
       
   633         }
       
   634     }
       
   635 }
       
   636 
       
   637 void CSwtTree::SelectAll(TBool aState)
       
   638 {
       
   639     ASSERT(iTree);
       
   640     iTree->SetMarked(KAknTreeIIDRoot, aState, ETrue);
       
   641 }
       
   642 
       
   643 TInt CSwtTree::SelectionCount() const
       
   644 {
       
   645     const CArrayFix<TInt>* arr = NULL;
       
   646     TRAP_IGNORE(arr = SelectionL());
       
   647     TInt res(0);
       
   648     if (arr)
       
   649     {
       
   650         res = arr->Count();
       
   651     }
       
   652     delete arr;
       
   653     return res;
       
   654 }
       
   655 
       
   656 const CArrayFix<TInt>* CSwtTree::SelectionL() const
       
   657 {
       
   658     ASSERT(iTree);
       
   659     CArrayFix<TInt>* res = NULL;
       
   660     if (iStyle & KSwtStyleMulti)
       
   661     {
       
   662         RArray<TInt> arr;
       
   663         CleanupClosePushL(arr);
       
   664         iTree->GetMarkedItemsL(arr);
       
   665         TInt count = arr.Count();
       
   666         if (count > 0)
       
   667         {
       
   668             res = new(ELeave) CArrayFixFlat<TInt>(count);
       
   669             CleanupStack::PushL(res);
       
   670             for (TInt i = 0; i < count; i++)
       
   671             {
       
   672                 res->AppendL(arr[i]);
       
   673             }
       
   674             CleanupStack::Pop(res);
       
   675         }
       
   676         CleanupStack::PopAndDestroy(&arr);
       
   677     }
       
   678     else
       
   679     {
       
   680         TInt item = iTree->FocusedItem();
       
   681         if (item != KAknTreeIIDNone)
       
   682         {
       
   683             res = new(ELeave) CArrayFixFlat<TInt>(1);
       
   684             CleanupStack::PushL(res);
       
   685             res->AppendL(item);
       
   686             CleanupStack::Pop(res);
       
   687         }
       
   688     }
       
   689     return res;
       
   690 }
       
   691 
       
   692 // CSwtLafFacade::EListSingle2HeadingMsgPaneG1 could be used to implement downscaling
       
   693 void CSwtTree::SetImageL(TInt aItemHandle, const MSwtImage* aImage)
       
   694 {
       
   695     ASSERT(iTree);
       
   696     if (aImage)
       
   697     {
       
   698         TInt id = KErrNotFound;
       
   699         TInt index = iImages.Find(aImage);
       
   700         if (index != KErrNotFound)
       
   701         {
       
   702             // Image already used by other items, increase local ref count
       
   703             id = iImageIds[index];
       
   704             iImageRefs[index]++;
       
   705         }
       
   706         else
       
   707         {
       
   708             // best suitable size from layouts.
       
   709             TSize layoutImgSize = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG1,
       
   710                                   ItemLayoutRect().Rect(), 4).Rect().Size();
       
   711             // best image size we can make to fit in the above layout size.
       
   712             TSize bitmapSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
       
   713                                    aImage->Bitmap().SizeInPixels(), layoutImgSize);
       
   714 
       
   715             // Register image with CAknTree, increase MSwtImage ref count, store the new id for later use
       
   716             const CFbsBitmap& bmp = aImage->SubBitmap(bitmapSize);
       
   717             const CFbsBitmap* mask = aImage->SubMaskBitmap(bitmapSize, ETrue);
       
   718             aImage->AddSubRef(bitmapSize);
       
   719             iImageMaxSize = bitmapSize;
       
   720             if (!mask)
       
   721             {
       
   722                 mask = iMaskHandler->GetMask(bmp.SizeInPixels());
       
   723             }
       
   724             id = iTree->AddIconL(const_cast<CFbsBitmap*>(&bmp), const_cast<CFbsBitmap*>(mask),
       
   725                                  EFalse, EAspectRatioPreserved);
       
   726             aImage->AddRef();
       
   727             User::LeaveIfError(iImages.Append(aImage));
       
   728             User::LeaveIfError(iImageIds.Append(id));
       
   729             User::LeaveIfError(iImageRefs.Append(1));
       
   730         }
       
   731 
       
   732         if (id != KErrNotFound)
       
   733         {
       
   734             // Set item custom image id
       
   735             iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::ECollapsedNode, id, ETrue);
       
   736             iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode, id, ETrue);
       
   737         }
       
   738     }
       
   739     else
       
   740     {
       
   741         TInt id = iTree->Icon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode);
       
   742         if (id != KErrNotFound)
       
   743         {
       
   744             // Set default image id to item
       
   745             iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::EExpandedNode,
       
   746                            AknTreeListIconID::KDefault, ETrue);
       
   747             iTree->SetIcon(aItemHandle, CAknSingleColumnStyleTreeList::ECollapsedNode,
       
   748                            AknTreeListIconID::KDefault, ETrue);
       
   749             TInt index = iImageIds.Find(id);
       
   750             if (index != KErrNotFound)
       
   751             {
       
   752                 // Decrease local ref
       
   753                 iImageRefs[index]--;
       
   754                 if (iImageRefs[index] == 0)
       
   755                 {
       
   756                     // No items are using the image, deregister it and decrease the MSwtImage ref count
       
   757                     iTree->RemoveIconL(id);
       
   758                     const MSwtImage* image = iImages[index];
       
   759                     TSize imageSize = image->Bitmap().SizeInPixels();
       
   760                     if (imageSize.iHeight > iImageMaxSize.iHeight ||
       
   761                             imageSize.iWidth > iImageMaxSize.iWidth)
       
   762                     {
       
   763                         imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
       
   764                                         imageSize, iImageMaxSize);
       
   765                     }
       
   766                     image->RemoveSubRef(imageSize);
       
   767                     image->RemoveRef();
       
   768                     iImages.Remove(index);
       
   769                     iImageIds.Remove(index);
       
   770                     iImageRefs.Remove(index);
       
   771                     iImages.Compress();
       
   772                     iImageIds.Compress();
       
   773                     iImageRefs.Compress();
       
   774                 }
       
   775             }
       
   776         }
       
   777     }
       
   778 }
       
   779 
       
   780 void CSwtTree::SetTextL(TInt aItemHandle, const TDesC& aText)
       
   781 {
       
   782     ASSERT(iTree);
       
   783     iTree->SetTextL(aItemHandle, aText, ETrue);
       
   784 }
       
   785 
       
   786 TInt CSwtTree::TopItem() const
       
   787 {
       
   788     ASSERT(iTree);
       
   789     TInt count = iItems.Count();
       
   790     for (TInt i = 0; i < count; i++)
       
   791     {
       
   792         TInt id = iItems[i];
       
   793         if (iTree->VisibleItemIndex(id) == 0)
       
   794         {
       
   795             return id;
       
   796         }
       
   797     }
       
   798     return KErrNotFound;
       
   799 }
       
   800 
       
   801 TInt CSwtTree::HandleTreeListEvent(CAknTreeList& aList, TAknTreeItemID aItem,
       
   802                                    MAknTreeListObserver::TEvent aEvent)
       
   803 {
       
   804     if (&aList != iTree)
       
   805     {
       
   806         return KErrNone;
       
   807     }
       
   808 
       
   809     // EItemSelected is never sent for nodes, hence the manual marking
       
   810     switch (aEvent)
       
   811     {
       
   812     case MAknTreeListObserver::ENodeExpanded:
       
   813     {
       
   814         TInt count = iTree->ChildCount(aItem);
       
   815         if (count > 0)
       
   816         {
       
   817             TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventExpand, aItem));
       
   818         }
       
   819         if (IsMarkable())
       
   820         {
       
   821             if (count == 0)
       
   822             {
       
   823                 iTree->SetMarked(aItem, ETrue, ETrue);
       
   824             }
       
   825         }
       
   826         else
       
   827         {
       
   828             TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventDefaultSelection, aItem));
       
   829         }
       
   830         break;
       
   831     }
       
   832     case MAknTreeListObserver::ENodeCollapsed:
       
   833     {
       
   834         TInt count = iTree->ChildCount(aItem);
       
   835         if (count > 0)
       
   836         {
       
   837             TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventCollapse, aItem));
       
   838         }
       
   839         if (IsMarkable())
       
   840         {
       
   841             if (count == 0)
       
   842             {
       
   843                 iTree->SetMarked(aItem, EFalse, ETrue);
       
   844             }
       
   845         }
       
   846         break;
       
   847     }
       
   848     case MAknTreeListObserver::EItemFocused:
       
   849     {
       
   850         if (iStyle & KSwtStyleSingle)
       
   851         {
       
   852             TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
       
   853         }
       
   854         break;
       
   855     }
       
   856     case MAknTreeListObserver::EItemMarked:
       
   857     {
       
   858         TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
       
   859         break;
       
   860     }
       
   861     case MAknTreeListObserver::EItemUnmarked:
       
   862     {
       
   863         TRAP_IGNORE(iDisplay.PostTreeEventL(iPeer, ESwtEventSelection, aItem));
       
   864         break;
       
   865     }
       
   866 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   867     case MAknTreeListObserver::EEventPanningStarted:
       
   868         GetShell().SetUrgentPaintControl(this);
       
   869         break;
       
   870     case MAknTreeListObserver::EEventFlickStopped:
       
   871         GetShell().SetUrgentPaintControl(NULL);
       
   872         break;
       
   873 #endif // RD_JAVA_S60_RELEASE_9_2
       
   874     default:
       
   875         break;
       
   876     }
       
   877 
       
   878     return KErrNone;
       
   879 }
       
   880 
       
   881 TInt CSwtTree::Compare(TAknTreeItemID aFirst, TAknTreeItemID aSecond)
       
   882 {
       
   883     TInt firstPos = iItems.Find(aFirst);
       
   884     TInt secondPos = iItems.Find(aSecond);
       
   885     if (firstPos < secondPos)
       
   886     {
       
   887         return -1;
       
   888     }
       
   889     else
       
   890     {
       
   891         return +1;
       
   892     }
       
   893 }
       
   894 
       
   895 void CSwtTree::UpdateItemHeight()
       
   896 {
       
   897     if (iItemHeightValid)
       
   898     {
       
   899         return;
       
   900     }
       
   901 
       
   902     ASSERT(iTree);
       
   903     TRect rect = iTree->HighlightRect();
       
   904     if (!rect.IsEmpty())
       
   905     {
       
   906         iItemHeightValid = ETrue;
       
   907         iItemHeight = rect.Height();
       
   908         return;
       
   909     }
       
   910 
       
   911     // LAF as last resort, might be a few pixels inaccurate.
       
   912     iItemHeightValid = EFalse;
       
   913     iItemHeight = ItemLayoutRect().Rect().Height();
       
   914 }
       
   915 
       
   916 TAknLayoutRect CSwtTree::ItemLayoutRect()
       
   917 {
       
   918     TRect mainRect(TRect::EUninitialized);
       
   919     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainRect);
       
   920     TAknLayoutRect layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListScrollGenPane, mainRect, 0);
       
   921     layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListGenPane, layoutRect.Rect(), 0);
       
   922     layoutRect = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingleGraphicH1Pane, layoutRect.Rect(), 0);
       
   923     return layoutRect;
       
   924 }
       
   925 
       
   926 void CSwtTree::UpdateImagesSize()
       
   927 {
       
   928     TSize imageNewSize = CSwtLafFacade::GetLayoutRect(CSwtLafFacade::EListSingle2HeadingMsgPaneG1,
       
   929                          ItemLayoutRect().Rect(), 4).Rect().Size();
       
   930 
       
   931     if (imageNewSize != iImageMaxSize && iImages.Count() > 0)
       
   932     {
       
   933         TInt count = iItems.Count();
       
   934         for (TInt i = 0; i < count; i++)
       
   935         {
       
   936             TInt itemHandle = iItems[i];
       
   937             if (itemHandle)
       
   938             {
       
   939                 // getting icon id from itemHandle.
       
   940                 TInt id = iTree->Icon(itemHandle, CAknSingleColumnStyleTreeList::EExpandedNode);
       
   941                 if (id != KErrNotFound)
       
   942                 {
       
   943                     // image index from icon id.
       
   944                     TInt index = iImageIds.Find(id);
       
   945                     const MSwtImage* image = iImages[index];
       
   946                     TSize imageSize = image->Bitmap().SizeInPixels();
       
   947 
       
   948                     TSize oldSize;
       
   949                     TBool doScaling = ETrue;
       
   950 
       
   951                     if (imageSize.iHeight > iImageMaxSize.iHeight ||
       
   952                             imageSize.iWidth > iImageMaxSize.iWidth)
       
   953                     {
       
   954                         // If image size is bigger than the old maximum size, then
       
   955                         // the image has been also previously scaled.
       
   956                         oldSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
       
   957                                       imageSize, iImageMaxSize);
       
   958                     }
       
   959                     else if (imageSize.iHeight > imageNewSize.iHeight ||
       
   960                              imageSize.iWidth > imageNewSize.iWidth)
       
   961                     {
       
   962                         // Image is bigger than the new boundaries, but it did fit
       
   963                         // inside the old boundaries, so the image is default size.
       
   964                         oldSize = imageSize;
       
   965                     }
       
   966                     else
       
   967                     {
       
   968                         doScaling = EFalse;
       
   969                     }
       
   970 
       
   971                     if (doScaling)
       
   972                     {
       
   973 
       
   974                         // best image size to fit in the tree item.
       
   975                         imageSize = SwtControlHelper::GetAspectRatioScaledBitmapSize(
       
   976                                         imageSize, imageNewSize);
       
   977                         // scaling down the bitmap and mask.
       
   978                         const CFbsBitmap& bmp =  image->SubBitmap(imageSize);
       
   979                         const CFbsBitmap* mask =  image->SubMaskBitmap(imageSize, ETrue);
       
   980 
       
   981                         if (!mask)
       
   982                         {
       
   983                             mask = iMaskHandler->GetMask(bmp.SizeInPixels());
       
   984                         }
       
   985                         // replacing the old icon with new icon.
       
   986                         TRAP_IGNORE(iTree->AssignIconL(id, const_cast<CFbsBitmap*>(&bmp) ,
       
   987                                                        const_cast<CFbsBitmap*>(mask), EFalse, EAspectRatioPreserved));
       
   988 
       
   989                         image->AddSubRef(imageSize);
       
   990                         image->RemoveSubRef(oldSize);
       
   991 
       
   992                     }
       
   993                 }
       
   994             }
       
   995         }
       
   996         iImageMaxSize = imageNewSize;
       
   997     }
       
   998 }
       
   999 
       
  1000 
       
  1001 TInt CSwtTree::LastCollapsedItem()
       
  1002 {
       
  1003     TInt count = iItems.Count();
       
  1004     if (count == 0)
       
  1005     {
       
  1006         return KErrNotFound;
       
  1007     }
       
  1008     TInt i;
       
  1009     for (i = count - 1; i >= 0; i--)
       
  1010     {
       
  1011         TInt parentId = iTree->Parent(iItems[i]);
       
  1012         if (parentId == KAknTreeIIDRoot)
       
  1013         {
       
  1014             break;
       
  1015         }
       
  1016         if (iTree->IsExpanded(parentId))
       
  1017         {
       
  1018             break;
       
  1019         }
       
  1020     }
       
  1021     return iItems[i];
       
  1022 }
       
  1023 
       
  1024 void CSwtTree::RemoveItemRefs(TInt aItemHandle)
       
  1025 {
       
  1026     TInt index = iItems.Find(aItemHandle);
       
  1027     if (index != KErrNotFound)
       
  1028     {
       
  1029         iItems.Remove(index);
       
  1030     }
       
  1031     TInt count = iTree->ChildCount(aItemHandle);
       
  1032     for (int i = 0; i < count; i++)
       
  1033     {
       
  1034         RemoveItemRefs(iTree->Child(aItemHandle, i));
       
  1035     }
       
  1036 }
       
  1037 
       
  1038 TBool CSwtTree::IsMarkable() const
       
  1039 {
       
  1040     // Natively, multi selection covers also the check style.
       
  1041     // Java is responsible to not overselect in SINGLE & CHECK.
       
  1042     return (iStyle & KSwtStyleMulti) || (iStyle & KSwtStyleCheck);
       
  1043 }
       
  1044 
       
  1045 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1046 void CSwtTree::DoControlSpecificFeedback(
       
  1047     const TBool& aFirstTap,
       
  1048     const TBool& aTappedToChildRect,
       
  1049     const TPointerEvent& aPointerEvent) const
       
  1050 {
       
  1051     MTouchFeedback* feedback = MTouchFeedback::Instance();
       
  1052     if (feedback && !aTappedToChildRect)
       
  1053     {
       
  1054         switch (aPointerEvent.iType)
       
  1055         {
       
  1056         case TPointerEvent::EButton1Down:
       
  1057             if (aFirstTap)
       
  1058             {
       
  1059                 feedback->InstantFeedback(ETouchFeedbackSensitiveList);
       
  1060             }
       
  1061             break;
       
  1062         }
       
  1063     }
       
  1064 }
       
  1065 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK