|
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 |